Unsolved Sending QWidgets as a pyqtSignal()
-
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 likeclass 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. -
@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 ofQLabel
/QImage
/QPixmap
there like you do? -
I agree with @JonB. It's definitely not a good idea to use
QLabel
,QImage
, andQPixmap
in aQThread
. 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.
-
Hi,
QImage is allowed as it is independent of graphics system unlike QPixmap. See the Mandelbrot example.
-
@GuyInABlueShirt said in Sending QWidgets as a pyqtSignal():
I agree with @JonB. It's definitely not a good idea to use
QLabel
,QImage
, andQPixmap
in aQThread
. 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.
-
@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 aQPixmap
or aQLabel
. That's what I mean byI'm not sure you can use all of [...]
-
@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?
-
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.