PyQt QScrollArea垂直滚动条自动滚到底端

  • Post author:
  • Post category:其他


最近在做一个类似QQ的局域网消息传输软件,当发送消息或者接收到消息时,滚动条应该自动滚动到最下方。

刚开始想的是在发送或接收消息并创建提示信息后,执行如下代码

self.scrollBar.setValue(self.scrollBar.maximum())

这样做发现滚动条是可以向下动,但是不会到最下方,也就是说会有一点点空隙。

bebug发现原因是增加滚动区域高度后,maximum方法获取的值还是原本的值,也就是还没有来得及更新。

解决方案:

设置一个标志位

self.scrollButtonFlag = False

连接rangeChanged信号

self.scrollBar.rangeChanged.connect(self.handleScrollBarRangeChanged)

在需要移动滚动条的时候,将标志位置为True

    def handleSendBtnClicked(self):
        self.createItem()
        self.scrollButtonFlag = True

对应的槽函数

    def handleScrollBarRangeChanged(self, minValue, maxValue):
        if self.scrollButtonFlag:
            self.scrollBar.setValue(maxValue)
            self.scrollButtonFlag = False

设置这个标志位是为了防止手动改变滚动区域范围(比如说resize)的时候,滚动条的位置错误移动。

运行效果

启动的时候

请添加图片描述

点击发送按钮后

滚动条正常移动到最下方

请添加图片描述

将滚动条移动到某个位置,然后进行resize

resize前后滚动条的位置不发生改变

请添加图片描述

完整代码

runner.py

import sys
import source_rc
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *

from shyQUI.shyQUI import Ui_MainWindow


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)
        for i in range(5):
            self.createItem()
        self.sendBtn.clicked.connect(self.handleSendBtnClicked)
        self.scrollBar = self.displayScrollArea.verticalScrollBar()
        self.scrollBar.rangeChanged.connect(self.handleScrollBarRangeChanged)
        self.scrollButtonFlag = False

    def createItem(self):
        headLabel = QLabel(self.displayFrame)
        headLabel.setPixmap(QPixmap(r':/head/icons/computer.png'))
        headLabel.setFixedSize(30, 30)
        hbox = QHBoxLayout(self.displayFrame)
        hbox.addWidget(headLabel)
        self.verticalLayout_2.addLayout(hbox)
        headLabel.show()

    def handleScrollBarRangeChanged(self, minValue, maxValue):
        if self.scrollButtonFlag:
            self.scrollBar.setValue(maxValue)
            self.scrollButtonFlag = False

    def handleSendBtnClicked(self):
        self.createItem()
        self.scrollButtonFlag = True


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = MainWindow()
    main.setGeometry(200, 100, 800, 200)
    main.show()
    sys.exit(app.exec_())

shyQUI.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'shyQUI.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        MainWindow.setStyleSheet("#MainWindow {\n"
"background-color: #ffffff;\n"
"}\n"
"#displayFrame {\n"
"    padding: 3px 10px;\n"
"}\n"
"#sendBtn {\n"
"    color: #ffffff;\n"
"    background-color: rgb(58,146,217);\n"
"    border-radius: 5px;\n"
"    padding: 3px 10px;\n"
"    text-align: center;\n"
"    font-family: \'微软雅黑\';\n"
"    margin-right: 10px;\n"
"    font-size:14px;\n"
"}\n"
"\n"
"#line {\n"
"color:  rgb(234,234,234);;\n"
"    background-color:rgb(234,234,234);\n"
"border: none;\n"
"}\n"
"#sendTextEdit {\n"
"    border: none;\n"
"font-family: \'微软雅黑\';\n"
"font-size: 14px;\n"
"}")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setStyleSheet("/*设置整个滚动条*/\n"
"QScrollBar:vertical {\n"
"    background-clip:margin;\n"
"    background:transparent;\n"
"    width: 8px;\n"
"}\n"
"\n"
"/*设置滚动条的滑块*/\n"
"QScrollBar::handle:vertical {\n"
"    width:8px;\n"
"    background:rgb(205,205,205);\n"
"    border-radius:4px;\n"
"    min-height:20;\n"
"}\n"
"\n"
"/*鼠标放在滑块上*/\n"
"QScrollBar::handle:vertical:hover {\n"
"    background: rgb(153,153,153);\n"
"}\n"
"\n"
"/*设置滚动条的增加页和减少页区域*/\n"
"QScrollBar::add-page:vertical,\n"
"QScrollBar::sub-page:vertical{\n"
"    background:transparent;\n"
"}\n"
"\n"
"/*隐藏上下箭头和按钮*/\n"
"QScrollBar::add-line:vertical,\n"
" QScrollBar::sub-line:vertical{\n"
"           border: none;\n"
"}")
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.displayScrollArea = QtWidgets.QScrollArea(self.centralwidget)
        self.displayScrollArea.setStyleSheet("* {\n"
"border:none;\n"
"background-color: #fff;\n"
"}\n"
"\n"
"\n"
"")
        self.displayScrollArea.setWidgetResizable(True)
        self.displayScrollArea.setObjectName("displayScrollArea")
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 800, 158))
        self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
        self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.displayFrame = QtWidgets.QFrame(self.scrollAreaWidgetContents)
        self.displayFrame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.displayFrame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.displayFrame.setObjectName("displayFrame")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.displayFrame)
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.verticalLayout_3.addWidget(self.displayFrame)
        spacerItem = QtWidgets.QSpacerItem(20, 435, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout_3.addItem(spacerItem)
        self.displayScrollArea.setWidget(self.scrollAreaWidgetContents)
        self.verticalLayout.addWidget(self.displayScrollArea)
        self.line = QtWidgets.QFrame(self.centralwidget)
        self.line.setMaximumSize(QtCore.QSize(16777215, 1))
        self.line.setCursor(QtGui.QCursor(QtCore.Qt.SizeVerCursor))
        self.line.setFrameShape(QtWidgets.QFrame.HLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.verticalLayout.addWidget(self.line)
        self.sendFrame = QtWidgets.QFrame(self.centralwidget)
        self.sendFrame.setMaximumSize(QtCore.QSize(16777204, 150))
        self.sendFrame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.sendFrame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.sendFrame.setObjectName("sendFrame")
        self.gridLayout = QtWidgets.QGridLayout(self.sendFrame)
        self.gridLayout.setContentsMargins(0, 0, 0, 10)
        self.gridLayout.setSpacing(0)
        self.gridLayout.setObjectName("gridLayout")
        self.sendBtn = QtWidgets.QPushButton(self.sendFrame)
        self.sendBtn.setObjectName("sendBtn")
        self.gridLayout.addWidget(self.sendBtn, 1, 2, 1, 1)
        self.sendTextEdit = QtWidgets.QTextEdit(self.sendFrame)
        self.sendTextEdit.setObjectName("sendTextEdit")
        self.gridLayout.addWidget(self.sendTextEdit, 0, 0, 1, 3)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem1, 1, 0, 1, 1)
        self.verticalLayout.addWidget(self.sendFrame)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.sendBtn.setText(_translate("MainWindow", "发送(S)"))

source_rc.py太大就不贴了,这是对应的source.qrc文件

<RCC>
  <qresource prefix="/"/>
  <qresource prefix="head">
    <file>icons/computer.png</file>
    <file>icons/phone.png</file>
  </qresource>
  <qresource prefix="file">
    <file>icons/file.png</file>
    <file>icons/more.png</file>
    <file>icons/success.png</file>
    <file>icons/fail.png</file>
  </qresource>
  <qresource prefix="demo">
    <file>icons/picture.jpg</file>
  </qresource>
</RCC>



版权声明:本文为weixin_43069875原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。