Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Sending QWidgets as a pyqtSignal()
Forum Updated to NodeBB v4.3 + New Features

Sending QWidgets as a pyqtSignal()

Scheduled Pinned Locked Moved Unsolved Qt for Python
qt for pythonpython
8 Posts 5 Posters 2.1k 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.
  • Q Offline
    Q Offline
    Qt-Bot05
    wrote on last edited by
    #1

    I'm trying to load multiple images into labels, then put them inside a table. The screen keeps freezing so
    I decided to load these images from a different thread but I run into a problem.

    When I try to set the immitted label as the table's cell widget it open's another window.
    Here's an example of what my current code looks like

    class Thread(QThread):
        item_signal = pyqtSignal(int, object)
        row_signal = pyqtSignal(int)
    
        def __init__(self, image_links):
            super(Thread, self).__init__()
            self.image_links = image_links
        
        def run(self):
            self.row_signal.emit(len(self.image_links))
            for row, i in enumerate(self.image_links):
                image_holder = QLabel()
                image = QImage()
                image.loadFromData(requests.get(i).content)
                image_holder.setPixmap(QPixmap(image))
                self.item_signal.emit(row, image_holder)
    
    
    class Window(QWidget):
        def __init__(self):
            super(Window, self).__init__()
    
            self.table = QTableWidget()
            self.worker = Thread([link1, link2..])
            self.worker.row_signal.connect(self.table.setRowCount)
            self.worker.item_signal.connect(self.func)
            self.worker.start()
       
        def func(self, row, widget):
             self.table.setCellWidget(row, 0, widget)
    

    This opens another window with the widget.
    I know I can just set the cellwidget inside the thread but I was thinking of making the thread reusable.

    JonBJ 2 Replies Last reply
    0
    • Q Qt-Bot05

      I'm trying to load multiple images into labels, then put them inside a table. The screen keeps freezing so
      I decided to load these images from a different thread but I run into a problem.

      When I try to set the immitted label as the table's cell widget it open's another window.
      Here's an example of what my current code looks like

      class Thread(QThread):
          item_signal = pyqtSignal(int, object)
          row_signal = pyqtSignal(int)
      
          def __init__(self, image_links):
              super(Thread, self).__init__()
              self.image_links = image_links
          
          def run(self):
              self.row_signal.emit(len(self.image_links))
              for row, i in enumerate(self.image_links):
                  image_holder = QLabel()
                  image = QImage()
                  image.loadFromData(requests.get(i).content)
                  image_holder.setPixmap(QPixmap(image))
                  self.item_signal.emit(row, image_holder)
      
      
      class Window(QWidget):
          def __init__(self):
              super(Window, self).__init__()
      
              self.table = QTableWidget()
              self.worker = Thread([link1, link2..])
              self.worker.row_signal.connect(self.table.setRowCount)
              self.worker.item_signal.connect(self.func)
              self.worker.start()
         
          def func(self, row, widget):
               self.table.setCellWidget(row, 0, widget)
      

      This opens another window with the widget.
      I know I can just set the cellwidget inside the thread but I was thinking of making the thread reusable.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @Qt-Bot05
      I don't know about whatever windows. But you must not do any UI stuff in a thread. I'm not sure you can use all of QLabel/QImage/QPixmap there like you do?

      1 Reply Last reply
      1
      • G Offline
        G Offline
        GuyInABlueShirt
        wrote on last edited by
        #3

        I agree with @JonB. It's definitely not a good idea to use QLabel, QImage, and QPixmap in a QThread. Your best bet is to create a worker class that does all the work you need, and have that emit some signal and method (It's using PySide6 though, I'm sure it won't be too hard to covert it to pyqt5).

        from PySide6.QtCore import QObject, QThread, Signal
        from PySide6.QtWidgets import QLabel, QWidget
        
        
        class Worker(QObject):
            finished = Signal()
        
            def __init__(self, image_links, parent=None):
                super(Worker, self).__init__(parent)
                self.image_links = image_links
                self.widgets = []
        
            def run(self):
                for i in self.image_links:
                    # Do work here..
                    holder = QLabel()
                    self.widgets.append(holder)
                self.finished.emit()
        
            def get_widgets(self):
                return self.widgets
        
        
        class Window(QWidget):
            def __init__(self, parent=None):
                super(Window, self).__init__(parent)
                self.thread = QThread()
                self.worker = Worker(['link1', 'link2', 'etc'])
                self.worker.moveToThread(self.thread)
        
                self._connect_signals()
        
                self.thread.start()
        
            def _connect_signals(self):
                self.thread.started.connect(self.worker.run)
                self.worker.finished.connect(self.thread.quit)
                self.worker.finished.connect(self.do_stuff_with_widgets)
        
            def do_stuff_with_widgets(self):
                for widget in self.worker.get_widgets():
                    # Do stuff with widgets
                    pass
        
        

        I used this for help: https://realpython.com/python-pyqt-qthread/

        This should let you do what you want to do.

        jeremy_kJ Q 2 Replies Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Hi,

          QImage is allowed as it is independent of graphics system unlike QPixmap. See the Mandelbrot example.

          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
          1
          • G GuyInABlueShirt

            I agree with @JonB. It's definitely not a good idea to use QLabel, QImage, and QPixmap in a QThread. Your best bet is to create a worker class that does all the work you need, and have that emit some signal and method (It's using PySide6 though, I'm sure it won't be too hard to covert it to pyqt5).

            from PySide6.QtCore import QObject, QThread, Signal
            from PySide6.QtWidgets import QLabel, QWidget
            
            
            class Worker(QObject):
                finished = Signal()
            
                def __init__(self, image_links, parent=None):
                    super(Worker, self).__init__(parent)
                    self.image_links = image_links
                    self.widgets = []
            
                def run(self):
                    for i in self.image_links:
                        # Do work here..
                        holder = QLabel()
                        self.widgets.append(holder)
                    self.finished.emit()
            
                def get_widgets(self):
                    return self.widgets
            
            
            class Window(QWidget):
                def __init__(self, parent=None):
                    super(Window, self).__init__(parent)
                    self.thread = QThread()
                    self.worker = Worker(['link1', 'link2', 'etc'])
                    self.worker.moveToThread(self.thread)
            
                    self._connect_signals()
            
                    self.thread.start()
            
                def _connect_signals(self):
                    self.thread.started.connect(self.worker.run)
                    self.worker.finished.connect(self.thread.quit)
                    self.worker.finished.connect(self.do_stuff_with_widgets)
            
                def do_stuff_with_widgets(self):
                    for widget in self.worker.get_widgets():
                        # Do stuff with widgets
                        pass
            
            

            I used this for help: https://realpython.com/python-pyqt-qthread/

            This should let you do what you want to do.

            jeremy_kJ Offline
            jeremy_kJ Offline
            jeremy_k
            wrote on last edited by
            #5

            @GuyInABlueShirt said in Sending QWidgets as a pyqtSignal():

            I agree with @JonB. It's definitely not a good idea to use QLabel, QImage, and QPixmap in a QThread. Your best bet is to create a worker class that does all the work you need, and have that emit some signal and method (It's using PySide6 though, I'm sure it won't be too hard to covert it to pyqt5).

            This technique doesn't resolve the QWidget access from a non-gui thread.

            Asking a question about code? http://eel.is/iso-c++/testcase/

            1 Reply Last reply
            0
            • Q Qt-Bot05

              I'm trying to load multiple images into labels, then put them inside a table. The screen keeps freezing so
              I decided to load these images from a different thread but I run into a problem.

              When I try to set the immitted label as the table's cell widget it open's another window.
              Here's an example of what my current code looks like

              class Thread(QThread):
                  item_signal = pyqtSignal(int, object)
                  row_signal = pyqtSignal(int)
              
                  def __init__(self, image_links):
                      super(Thread, self).__init__()
                      self.image_links = image_links
                  
                  def run(self):
                      self.row_signal.emit(len(self.image_links))
                      for row, i in enumerate(self.image_links):
                          image_holder = QLabel()
                          image = QImage()
                          image.loadFromData(requests.get(i).content)
                          image_holder.setPixmap(QPixmap(image))
                          self.item_signal.emit(row, image_holder)
              
              
              class Window(QWidget):
                  def __init__(self):
                      super(Window, self).__init__()
              
                      self.table = QTableWidget()
                      self.worker = Thread([link1, link2..])
                      self.worker.row_signal.connect(self.table.setRowCount)
                      self.worker.item_signal.connect(self.func)
                      self.worker.start()
                 
                  def func(self, row, widget):
                       self.table.setCellWidget(row, 0, widget)
              

              This opens another window with the widget.
              I know I can just set the cellwidget inside the thread but I was thinking of making the thread reusable.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #6

              @Qt-Bot05
              To be clear: further to comments from others above.

              I believe you can use QImage from a non-UI thread. But I believe you must not use either a QPixmap or a QLabel. That's what I mean by

              I'm not sure you can use all of [...]

              1 Reply Last reply
              1
              • G GuyInABlueShirt

                I agree with @JonB. It's definitely not a good idea to use QLabel, QImage, and QPixmap in a QThread. Your best bet is to create a worker class that does all the work you need, and have that emit some signal and method (It's using PySide6 though, I'm sure it won't be too hard to covert it to pyqt5).

                from PySide6.QtCore import QObject, QThread, Signal
                from PySide6.QtWidgets import QLabel, QWidget
                
                
                class Worker(QObject):
                    finished = Signal()
                
                    def __init__(self, image_links, parent=None):
                        super(Worker, self).__init__(parent)
                        self.image_links = image_links
                        self.widgets = []
                
                    def run(self):
                        for i in self.image_links:
                            # Do work here..
                            holder = QLabel()
                            self.widgets.append(holder)
                        self.finished.emit()
                
                    def get_widgets(self):
                        return self.widgets
                
                
                class Window(QWidget):
                    def __init__(self, parent=None):
                        super(Window, self).__init__(parent)
                        self.thread = QThread()
                        self.worker = Worker(['link1', 'link2', 'etc'])
                        self.worker.moveToThread(self.thread)
                
                        self._connect_signals()
                
                        self.thread.start()
                
                    def _connect_signals(self):
                        self.thread.started.connect(self.worker.run)
                        self.worker.finished.connect(self.thread.quit)
                        self.worker.finished.connect(self.do_stuff_with_widgets)
                
                    def do_stuff_with_widgets(self):
                        for widget in self.worker.get_widgets():
                            # Do stuff with widgets
                            pass
                
                

                I used this for help: https://realpython.com/python-pyqt-qthread/

                This should let you do what you want to do.

                Q Offline
                Q Offline
                Qt-Bot05
                wrote on last edited by Qt-Bot05
                #7

                @GuyInABlueShirt When I use the setCellWidget it still opens another window with the QLabel in it. Is what I'm trying to do impossible? Or maybe I should use a python threading library?

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

                  Do not use setCellWidget.

                  Generate your images and store them in your model. Either use the decoration role to show them or a dedicated item delegate.

                  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

                  • Login

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