Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Widgets are shrinked when added to scroll area
Qt 6.11 is out! See what's new in the release blog

Widgets are shrinked when added to scroll area

Scheduled Pinned Locked Moved Unsolved General and Desktop
16 Posts 3 Posters 3.3k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    kraken1564
    wrote on last edited by kraken1564
    #1

    I have a QScrollArea and QWidget assigned to it:

    scrollArea = QScrollArea()
    widget = QWidget()
    scrollArea.setWidget(widget)
    
    layout = QVBoxLayout()
    widget.setLayout(layout)
    

    And then I create labels dynamically at run time, assign to them QPixmap with images and add these labels to the layout:

    for img in images:
        pixmap = QPixmap(img).scaled(200, 200, 1)
        label = QLabel()
        label.setPixmap(pixmap)
    
        layout.addWidget(label)
    

    And what I get is when a new label is added to the layout all the labels begin to shrink and then get the proper size. Then again shrink and so on... You can see this behaviour here (https://gfycat.com/windingwhisperedgrison).
    I tried changing 'sizePolicy' to 'Minimum', setting 'minimumHeight', calling 'updateGeometry()' - nothing. What can the problem be?

    P.S. I noticed that the labels get proper sizes again when the scroll bar (on the right) gets smaller (widget change its size and gets bigger?). Maybe the problem is that, for some reason, widget doesn't change its size fast enough but new labels are added so they shrink to fit? If it's the case how can we resize widget faster (before a new label is added)?

    1 Reply Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi
      Since you scale the pixmap to 200x200 then the easy fix is simply to set minimum size on the labels to that.
      label = QLabel()
      label.setMinimumSize(QSize(200,200));

      1 Reply Last reply
      1
      • K Offline
        K Offline
        kraken1564
        wrote on last edited by
        #3

        It doesn't work. I tried it already. The labels shrink anyway.

        mrjjM 1 Reply Last reply
        0
        • K kraken1564

          It doesn't work. I tried it already. The labels shrink anyway.

          mrjjM Offline
          mrjjM Offline
          mrjj
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @kraken1564

          Hi
          thats odd. works fine here in c++
          It wont make them less than min size.
          alt text

          can you show your exact code ? Maybe we can spot something.

          1 Reply Last reply
          0
          • K Offline
            K Offline
            kraken1564
            wrote on last edited by
            #5

            The code above is basically my code. One thing I forgot to say that I do some "computations" in a working thread and then use signals/slots to emit intermediate results. So the code where I create labels with images is my slot updating the GUI.

            I recorded the screen one more time. This what I see with the code above: https://gfycat.com/lighthearteddentalcrustacean . If I add

            widget.updateGeometry()
            

            after adding a new label, these jumps/flickers almost disappear but sometimes happen (way less frequently).

            If I add

            time.sleep(1)
            

            after emitting a new signal (so slot creating my labels is called less often), these jumps/flickers don't happen at all: https://gfycat.com/calculatinggenuinekoodoo .

            Can it be some problem with processing too many signals in a short period of time so the widgets cannot be repainted/updated fast enough to avoid these jumps/flickers?

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              Hi,

              How many signals are you sending per seconds for your image updates ?

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              0
              • K Offline
                K Offline
                kraken1564
                wrote on last edited by
                #7

                About 5-10. It's not too many I think. But I have quite old CPU - Athlon 64 x2 3800+. I do not have any fancy hardware with me right now to test it.

                But, indeed, the rarer the GUI needs to be updated, the less frequent these glitch are.

                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  The number seems fine but is it per image ?
                  It could also come from your graphics stack.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  1 Reply Last reply
                  0
                  • K Offline
                    K Offline
                    kraken1564
                    wrote on last edited by
                    #9

                    No, It's one signal per image.

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      Can you provide a minimal buildable example that shows that behaviour ?

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply
                      0
                      • K Offline
                        K Offline
                        kraken1564
                        wrote on last edited by
                        #11

                        I think the "too many signals" hypothesis is right. I added a label and update it hundreds times per second. The glitches gets way worse. If I do not do it, they almost disappear. Also I tested it on another hardware and got the same behaviour ( less signals - no glitches, more signals - glitches).

                        Here is the code (but it is use PyQt, is it ok?):

                        import sys
                        from multiprocessing import Pool
                        from pathlib import Path
                        
                        from PyQt5 import QtCore, QtGui, QtWidgets
                        
                        # !!! Change to your folder with images
                        FOLDER = '/home/user/images'
                        
                        def find_images(folder):
                            '''Return paths of the images in the folder'''
                        
                            images = []
                            for filename in Path(folder).rglob('*.jpg'):
                                if filename.is_file():
                                    images.append(str(filename))
                            return images
                        
                        def scale_image_BA(image_path):
                            '''To generate more signals, concurrent processing is
                            used (via lib "multiprocessing"). QPixmap or QImage cannot
                            be serialized so converting to QByteArray is used'''
                        
                            reader = QtGui.QImageReader(image_path)
                            reader.setScaledSize(QtCore.QSize(200, 200))
                            image = reader.read()
                        
                            ba = QtCore.QByteArray()
                            buf = QtCore.QBuffer(ba)
                            buf.open(QtCore.QIODevice.WriteOnly)
                            image.save(buf, 'JPG', 100)
                            buf.close()
                            return ba
                        
                        def QByteArray_to_QPixmap(ba_image):
                            '''Convert from QByteArray back to QPixmap'''
                        
                            pixmap = QtGui.QPixmap()
                            pixmap.loadFromData(ba_image)
                            return pixmap
                        
                        
                        class Signals(QtCore.QObject):
                            image = QtCore.pyqtSignal(QtCore.QByteArray)
                            label = QtCore.pyqtSignal(str)
                        
                        
                        class Worker(QtCore.QRunnable):
                            def __init__(self, image_paths):
                                super().__init__()
                                self.image_paths = image_paths
                                self.signals = Signals()
                        
                            @QtCore.pyqtSlot()
                            def run(self):
                                '''Run image scaling on all available cores to emit more signals'''
                        
                                with Pool() as p:
                                    for baimg in p.imap_unordered(scale_image_BA, self.image_paths):
                                        # Glitches happen if emit many signals per second???
                                        # Without updating 'label' many times, everything's fine
                                        for i in range(1000):
                                            self.signals.label.emit(str(i))
                                        self.signals.image.emit(baimg)
                        
                        
                        class MyMainWindow(QtWidgets.QMainWindow):
                        
                            def __init__(self):
                                super().__init__()
                        
                                self.setMinimumSize(QtCore.QSize(800, 600))
                        
                                centralWidget = QtWidgets.QWidget()
                                self.setCentralWidget(centralWidget)
                        
                                scrollArea = QtWidgets.QScrollArea()
                                scrollArea.setWidgetResizable(True)
                        
                                imagesWidget = QtWidgets.QWidget()
                                scrollArea.setWidget(imagesWidget)
                        
                                self.label = QtWidgets.QLabel('Counter')
                        
                                startButton = QtWidgets.QPushButton('Start')
                                startButton.clicked.connect(self.run_worker)
                        
                                verticalLayout = QtWidgets.QVBoxLayout()
                                verticalLayout.addWidget(scrollArea)
                                verticalLayout.addWidget(self.label)
                                verticalLayout.addWidget(startButton)
                                centralWidget.setLayout(verticalLayout)
                        
                                self.imagesLayout = QtWidgets.QVBoxLayout()
                                imagesWidget.setLayout(self.imagesLayout)
                        
                            def run_worker(self):
                                images = find_images(FOLDER)
                                threadpool = QtCore.QThreadPool.globalInstance()
                                w = Worker(images)
                                w.signals.image.connect(self.update_gui)
                                w.signals.label.connect(self.label.setText)
                                threadpool.start(w)
                        
                            def update_gui(self, image):
                                label = QtWidgets.QLabel()
                                pixmap = QByteArray_to_QPixmap(image)
                                label.setPixmap(pixmap)
                                self.imagesLayout.addWidget(label)
                        
                        
                        if __name__ == '__main__':
                        
                            app = QtWidgets.QApplication(sys.argv)
                            mw = MyMainWindow()
                            mw.show()
                            app.exec()
                        
                        1 Reply Last reply
                        0
                        • SGaistS Offline
                          SGaistS Offline
                          SGaist
                          Lifetime Qt Champion
                          wrote on last edited by
                          #12

                          What version of PyQt5 are you using ?

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          1 Reply Last reply
                          0
                          • K Offline
                            K Offline
                            kraken1564
                            wrote on last edited by
                            #13

                            5.12.2, but tested also on 5.14.2 and 5.9 - got the same behaviour.

                            1 Reply Last reply
                            0
                            • SGaistS Offline
                              SGaistS Offline
                              SGaist
                              Lifetime Qt Champion
                              wrote on last edited by
                              #14

                              What graphics stack do you have on your machine ?

                              Interested in AI ? www.idiap.ch
                              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                              1 Reply Last reply
                              0
                              • K Offline
                                K Offline
                                kraken1564
                                wrote on last edited by kraken1564
                                #15

                                One PC has Geforce GT 730, driver v. 435.21, Linux Mint with Cinnamon DE (last one);
                                the other one has Intel UHD 630, Manjaro with KDE (use Qt, right?) - again get the same thing,

                                1 Reply Last reply
                                0
                                • K Offline
                                  K Offline
                                  kraken1564
                                  wrote on last edited by kraken1564
                                  #16

                                  I've made the peace of code showing this behaviour a little simpler:

                                  import sys
                                  from PyQt5 import QtCore, QtGui, QtWidgets
                                  
                                  # Maybe you need to play with these constants
                                  PIXMAP_NUM = 1000
                                  EVENTLOOP_RUN_NUM = 100
                                  
                                  
                                  class Signals(QtCore.QObject):
                                      pixmaps = QtCore.pyqtSignal(list)
                                  
                                  
                                  class Worker(QtCore.QRunnable):
                                      def __init__(self):
                                          super().__init__()
                                          self.signals = Signals()
                                  
                                      @QtCore.pyqtSlot()
                                      def run(self):
                                          '''Make QPixmap object with different colours, add them to a list
                                          and emit the list'''
                                  
                                          c = QtGui.QColor
                                          colors = [c('red'), c('green'), c('blue'), c('cyan'),
                                                    c('magenta'), c('yellow')]
                                          i = 0
                                  
                                          pms = []
                                          for _ in range(PIXMAP_NUM):
                                              pixmap = QtGui.QPixmap(200, 200)
                                              pixmap.fill(colors[i])
                                              i += 1
                                              if i == len(colors):
                                                  i = 0
                                              pms.append(pixmap)
                                  
                                          self.signals.pixmaps.emit(pms)
                                  
                                  
                                  class MyMainWindow(QtWidgets.QMainWindow):
                                  
                                      def __init__(self):
                                          super().__init__()
                                  
                                          self.setMinimumSize(QtCore.QSize(800, 600))
                                  
                                          centralWidget = QtWidgets.QWidget()
                                          self.setCentralWidget(centralWidget)
                                  
                                          scrollArea = QtWidgets.QScrollArea()
                                          scrollArea.setWidgetResizable(True)
                                  
                                          imagesWidget = QtWidgets.QWidget()
                                          scrollArea.setWidget(imagesWidget)
                                  
                                          startButton = QtWidgets.QPushButton('Start')
                                          startButton.clicked.connect(self.run_worker)
                                  
                                          verticalLayout = QtWidgets.QVBoxLayout()
                                          verticalLayout.addWidget(scrollArea)
                                          verticalLayout.addWidget(startButton)
                                          centralWidget.setLayout(verticalLayout)
                                  
                                          self.imagesLayout = QtWidgets.QVBoxLayout()
                                          imagesWidget.setLayout(self.imagesLayout)
                                  
                                      def run_worker(self):
                                          threadpool = QtCore.QThreadPool.globalInstance()
                                          w = Worker()
                                          w.signals.pixmaps.connect(self.update_gui)
                                          threadpool.start(w)
                                  
                                      def update_gui(self, pixmaps):
                                          for i, img in enumerate(pixmaps):
                                              label = QtWidgets.QLabel()
                                              # The next line doesn't change the behaviour
                                              label.setMinimumSize(QtCore.QSize(200, 200))
                                              label.setPixmap(img)
                                              self.imagesLayout.addWidget(label)
                                              # The next line doesn't change the behaviour
                                              self.updateGeometry()
                                  
                                              if i % EVENTLOOP_RUN_NUM == 0:
                                                  QtCore.QCoreApplication.processEvents()
                                  
                                  
                                  if __name__ == '__main__':
                                  
                                      app = QtWidgets.QApplication(sys.argv)
                                      mw = MyMainWindow()
                                      mw.show()
                                      app.exec()
                                  

                                  This code reproduce the glitches on both the machines.

                                  I've noticed one thing. If we do not set the minimum size,

                                  label.setMinimumSize(QtCore.QSize(200, 200))
                                  

                                  labels shrink. But if we do, they overlap (so, indeed, the minimum size is respected but imagesWidget is not big enough - cannot change its own size fast enough??? - to set the labels without overlapping???)

                                  1 Reply Last reply
                                  0

                                  • Login

                                  • Login or register to search.
                                  • First post
                                    Last post
                                  0
                                  • Categories
                                  • Recent
                                  • Tags
                                  • Popular
                                  • Users
                                  • Groups
                                  • Search
                                  • Get Qt Extensions
                                  • Unsolved