Область прокрутки не может расширяться (прокручиваться) при добавлении нового виджета

Я попытался сделать какое-нибудь простое приложение для локального чата для практики. Я делаю кнопку для отправки сообщения каждый раз, когда я нажимаю кнопку, отображаемое сообщение, но область прокрутки становится более узкой и не расширяет область прокрутки. Я что-то упустил или добавил что-то, чего не должен в своем коде? Как я могу это исправить?

Вот мой код:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class Bubble(QLabel):
    def __init__(self,text):
        super(Bubble,self).__init__(text)
        self.setContentsMargins(5,5,5,5)

    def paintEvent(self, e):

        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing,True)
        p.drawRoundedRect(0,0,self.width()-1,self.height()-1,5,5)

        super(Bubble,self).paintEvent(e)        

class MyWidget(QWidget):

    def __init__(self,text,left=True):
        super(MyWidget,self).__init__()

        hbox = QHBoxLayout()

        label = Bubble(text)

        if not left:
            hbox.addSpacerItem(QSpacerItem(1,1,QSizePolicy.Expanding,QSizePolicy.Preferred))

        hbox.addWidget(label)

        if left:
            hbox.addSpacerItem(QSpacerItem(1,1,QSizePolicy.Expanding,QSizePolicy.Preferred))            

        hbox.setContentsMargins(0,0,0,0)

        self.setLayout(hbox)
        self.setContentsMargins(0,0,0,0)

class Chatting(QWidget):
    def __init__(self, parent=None):
        super(Chatting, self).__init__(parent)
        self.vbox = QVBoxLayout()
        for _ in range(20):
            self.vbox.addWidget(MyWidget("Left side"))

        widget = QWidget()
        widget.setLayout(self.vbox)

        scroll = QScrollArea()
        scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scroll.setWidgetResizable(False)
        scroll.setWidget(widget)     

        #Scroll Area Layer add 
        vLayout = QVBoxLayout(self)
        vLayout.addWidget(scroll)

        send = QPushButton('')
        send.setIcon(QIcon('images/send.png'))
        send.setStyleSheet("background-color:#d00001; width: 44px")
        send.setIconSize(QSize(84,20))
        send.clicked.connect(self.send_messages)
        vLayout.addWidget(send)
        self.setLayout(vLayout)

    def send_messages(self):
        self.vbox.addWidget(MyWidget('testing'))

person Mr Choco    schedule 03.10.2018    source источник


Ответы (1)


Проблема проста: вы должны включить свойство widgetResizable в значение True, поскольку это свойство позволяет QScrollArea вычислять размер содержимого.

scroll.setWidgetResizable(True)

С другой стороны, я потратил время, чтобы улучшить ваш код, и я покажу его ниже:

from PyQt4 import QtGui, QtCore


class Bubble(QtGui.QLabel):
    def __init__(self, text):
        super(Bubble,self).__init__(text)
        self.setContentsMargins(5, 5, 5, 5)

    def paintEvent(self, e):
        p = QtGui.QPainter(self)
        p.setRenderHint(QtGui.QPainter.Antialiasing, True)
        p.drawRoundedRect(self.rect().adjusted(0, 0, -1, -1), 5, 5)
        super(Bubble, self).paintEvent(e)        

class MyWidget(QtGui.QWidget):
    def __init__(self, text, left=True):
        super(MyWidget,self).__init__()
        lay = QtGui.QVBoxLayout(self)
        lay.setContentsMargins(0, 0, 0, 0)
        self.setContentsMargins(0, 0, 0, 0)
        label = Bubble(text)
        lay.addWidget(label, alignment= QtCore.Qt.AlignLeft if left else QtCore.Qt.AlignRight)


class Chatting(QtGui.QWidget):
    def __init__(self, parent=None):
        super(Chatting, self).__init__(parent)

        widget = QtGui.QWidget()
        self.vbox = QtGui.QVBoxLayout(widget)
        self.vbox.addStretch()
        self.scroll = QtGui.QScrollArea(widgetResizable=True)
        self.scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.scroll.setWidget(widget)     

        #Scroll Area Layer add 
        send = QtGui.QPushButton(icon= QtGui.QIcon('images/send.png'))
        send.setStyleSheet("background-color:#d00001; width: 44px")
        send.setIconSize(QtCore.QSize(84,20))
        send.clicked.connect(self.on_clicked)

        vLayout = QtGui.QVBoxLayout(self)
        vLayout.addWidget(self.scroll)
        vLayout.addWidget(send)

    def send_message(self, text, direction=True):
        widget = MyWidget(text, direction)
        self.vbox.insertWidget(self.vbox.count()-1, widget)
        scroll_bar = self.scroll.verticalScrollBar()
        # move to end
        QtCore.QTimer.singleShot(10, lambda: scroll_bar.setValue(scroll_bar.maximum()))

    @QtCore.pyqtSlot()
    def on_clicked(self):
        self.send_message("testing") 


if __name__ == '__main__':
    import sys
    import random

    app = QtGui.QApplication(sys.argv)
    w = Chatting()

    def test():
        for _ in range(8):
            w.send_message("testing", random.choice((True, False)))
    QtCore.QTimer.singleShot(1000, test)

    w.resize(240, 480)
    w.show()
    sys.exit(app.exec_())
person eyllanesc    schedule 03.10.2018
comment
Еще раз спасибо! Очень ценю улучшение моего кода. - person Mr Choco; 03.10.2018