Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

[QScrollArea] Scroll problem when adding widgets dynamically



  • Hi,

    I'm making a small network scanner. I have a QScrollArea and I add dynamically some widgets when new devices are found.

    You can see the problem at https://youtu.be/1rm9ceZkIwY ( "mini jump" when a new widget is added inside the QScrollArea, so the adding is not smooth )

    I'm using PySide 2 ( Python version of Qt ) but I don't think it comes from Python.

            self.scroll_area = QtWidgets.QScrollArea(self)
            self.scroll_area.setWidgetResizable(True)
    
            self.device_list_widget = DeviceListWidget() # Based on an QFrame, just contains QVBoxLayout ( layout contains widgets of course )
            self.scroll_area.setWidget(self.device_list_widget)
    

    Is there any solution for me ?

    If my English is not good, sorry I was born in France ... 😂
    Thank's



  • @Naufrage7 Hello my French friend, and oh god, I realized the "mini jump" so long after :D
    If you wanna hear what I am thinking, it looks like a qt-based bug. Or you can try to fix the components better :P



  • I think also. I have the impression that scroll area follow these steps :

    • the widget is inserted without margin
    • view is updated
    • margin is calculated
    • view updated

    0_1562246453464_giphy.gif

    I will set all margins to 0 and check but I will have need these margin in production ...



  • @Naufrage7 If you set the sizes of every component manually, and fix them, the problem will probably gone. But the application window (main window) should be fixed too. Otherwise, a change in main window size would screw the whole order tho :D Try and let us know!
    Good work!


  • Lifetime Qt Champion

    Hi,

    What version of PySide2 are you using ?
    Can you provide a minimal complete example that shows that behavior ?



  • Hi,

    I'm using the version 5.12.4 of Pyside 2 version ( installed from pip ).

    from PySide2 import QtCore, QtWidgets
    from ARPRequestEmitter import ARPRequestEmitter
    from ARPResponseReceiver import ARPResponseReceiver
    from threading import Thread
    from random import randint
    import sys
    
    
    class DeviceListWidget(QtWidgets.QFrame):
    
        def __init__(self, parent=None):
            super(DeviceListWidget, self).__init__(parent)
    
            self.vertical_layout = QtWidgets.QVBoxLayout()
            self.setLayout(self.vertical_layout)
    
            item_spacer = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
            self.vertical_layout.addItem(item_spacer)
    
        def add_device(self, ip, mac):
            widget = QtWidgets.QWidget()
            layout = QtWidgets.QVBoxLayout()
            label = QtWidgets.QLabel(ip)
            layout.addWidget(label)
            label = QtWidgets.QLabel(mac)
            layout.addWidget(label)
            widget.setLayout(layout)
            self.vertical_layout.insertWidget(0, widget)
    
    
    class Dialog(QtWidgets.QDialog):
    
        def __init__(self):
            super(Dialog, self).__init__()
    
            self.resize(640, 480)
    
            self.horizontal_layout = QtWidgets.QHBoxLayout()
            self.setLayout(self.horizontal_layout)
    
            self.vertical_layout_left = QtWidgets.QVBoxLayout()
            self.horizontal_layout.addLayout(self.vertical_layout_left)
    
            self.vertical_layout_right = QtWidgets.QVBoxLayout()
            self.horizontal_layout.addLayout(self.vertical_layout_right)
    
            self.label_decoration_network = QtWidgets.QLabel("Réseau")
            self.vertical_layout_left.addWidget(self.label_decoration_network)
    
            self.form_network = QtWidgets.QFormLayout()
            self.vertical_layout_left.addLayout(self.form_network)
    
            self.label_network = QtWidgets.QLabel("192.168.178.0/24")
            self.form_network.addRow(QtWidgets.QLabel("Adresse"), self.label_network)
    
            self.label_gateway = QtWidgets.QLabel("192.168.178.1")
            self.form_network.addRow(QtWidgets.QLabel("Passerelle"), self.label_gateway)
    
            self.label_capacity = QtWidgets.QLabel("0 / 254")
            self.form_network.addRow(QtWidgets.QLabel("Capacité"), self.label_capacity)
    
            item_spacer = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
            self.vertical_layout_left.addItem(item_spacer)
    
            self.line_filter = QtWidgets.QLineEdit(self)
            self.line_filter.setPlaceholderText("Tapez ici pour filter les périphériques affichés")
            self.vertical_layout_right.addWidget(self.line_filter)
    
            self.scroll_area = QtWidgets.QScrollArea(self)
            self.scroll_area.setWidgetResizable(True)
            self.vertical_layout_right.addWidget(self.scroll_area)
    
            self.device_list_widget = DeviceListWidget()
            self.scroll_area.setWidget(self.device_list_widget)
    
            self.hosts = []
    
            # self.arp_receiver = ARPResponseReceiver('en0')
            # self.arp_receiver.response_received.connect(self.__arp_received__)
            # self.arp_receiver.start()
    
            # self.arp_emitter = ARPRequestEmitter('en0', '192.168.178.0/24')
            # self.arp_emitter.start()
    
            self.timer = QtCore.QTimer()
            self.timer.timeout.connect(self.__timeout__)
            self.timer.start(500)
    
        def __timeout__(self):
            self.__arp_received__(['192.168.178.' + str(randint(0, 256)), '@MAC'])
    
        def __arp_received__(self, host):
            if host not in self.hosts:
                self.hosts.append(host)
                self.label_capacity.setText(str(len(self.hosts)) + " / 254")
                self.device_list_widget.add_device(host[0], host[1])
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        dialog = Dialog()
        dialog.show()
        sys.exit(app.exec_())
    
    

    I tested some combinations adding or removing margins and changing the size policy but I could not find solution.


Log in to reply