Mr Choco
Mr Choco

Reputation: 25

Scrollarea can't expand (scroll) when new widget added

I tried to make some simple local chatting app for practice. I make a button to send a message every time i push the button the message displayed but the scrollarea become more narrow and not expanded the scrollarea. Am I missing something or added something i shouldn't in my code? how can i fix this?

Here is my code:

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'))

Upvotes: 1

Views: 712

Answers (1)

eyllanesc
eyllanesc

Reputation: 243907

The problem is simple you have to enable the widgetResizable property to True since that property allows the QScrollArea to calculate the size of the content.

scroll.setWidgetResizable(True)

On the other hand I have taken the time to improve your code and I show it below:

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_())

Upvotes: 2

Related Questions