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

最近在做一个类似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>
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以使用 `QScrollArea` 的 `verticalScrollBar()` 获取垂直滚动条,然后使用 `setValue()` 方法设置位置。下面是一个示例代码: ```python from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QTextEdit, QPushButton, QScrollArea from PyQt5.QtCore import Qt class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): # 创建动区域和垂直布局 scroll = QScrollArea() vbox = QVBoxLayout() # 创建一些文本框作为示例 for i in range(20): textbox = QTextEdit(f'Text {i+1}') vbox.addWidget(textbox) # 将布局设置为动区域的子控件 widget = QWidget() widget.setLayout(vbox) scroll.setWidget(widget) # 创建一个按钮,点击后动到第10个文本框 btn = QPushButton('Scroll to Text 10', self) btn.clicked.connect(lambda: scroll.verticalScrollBar().setValue(9*textbox.height())) # 将动区域和按钮添加到窗口中 vbox = QVBoxLayout(self) vbox.addWidget(scroll) vbox.addWidget(btn) self.setGeometry(300, 300, 350, 300) self.setWindowTitle('QScrollArea Example') self.show() if __name__ == '__main__': app = QApplication([]) ex = Example() app.exec_() ``` 在这个示例中,我们创建了一个 `QScrollArea` 和一个垂直布局。我们创建了 20 个 `QTextEdit` 控件,并将它们添加到布局中。然后,我们将布局设置为动区域的子控件,并将动区域添加到窗口中。 我们还创建了一个按钮,当点击它时,它会将滚动条设置为第 10 个文本框的位置。在这里,我们使用了 `setValue()` 方法,并将其设置为第 10 个文本框的高度乘以 9,因为滚动条位置是从 0 开始计数的。 你可以根据实际情况进行修改,例如将滚动条设置为其他位置,或者使用水平滚动条等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值