Python PyQt5 在 QThread 上为 QPushButton 加载图像
Python PyQt5 load Image for QPushButton on QThread
所以我有这个 UI 可以加载很多按钮,所有按钮都有图像,问题是,它需要很长时间,所以我试着把它放到 QThread
中,我让它工作了, 但没有速度差异,所以我尝试了不同的解决方案,但现在线程无法启动。
代码:
import sys
import os
from PyQt5 import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui, QtPrintSupport, QtWidgets, uic
# I've tried using a QThread for this, but it still took the same amount of time.
class LoadImageThumbnailshread(QThread):
def __init__(self, listButtons, listPaths):
QThread.__init__(self)
self.listButtons = listButtons
self.listPaths = listPaths
def run(self):
self.process_images_Thread()
def process_images_Thread(self):
for i, j in enumerate(self.listButtons):
j.setIcon(QIcon(self.listPaths[i]))
j.setIconSize(QSize(150-6, 60-6))
class App(QDialog):
def __init__(self):
super().__init__()
self.title = 'PyQt5 layout - pythonspot.com'
self.left = 10
self.top = 10
self.width = 320
self.height = 100
self.images_path = []
self.button_images = []
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.createGridLayout()
windowLayout = QVBoxLayout()
windowLayout.addWidget(self.horizontalGroupBox)
self.setLayout(windowLayout)
self.show()
def createGridLayout(self):
self.horizontalGroupBox = QGroupBox("Grid")
layout = QGridLayout()
layout.setColumnStretch(1, 4)
layout.setColumnStretch(2, 4)
for i in range(100):
self.btnImage = QPushButton()
self.btnImage.setObjectName('btnImage')
self.images_path.append(os.path.dirname(
os.path.abspath(__file__)) + 'view.png')
# ! I have also tried using Pixmaps with Clickable labels, but it made no diffrence.
# pixmap = QPixmap(os.path.dirname(os.path.abspath(__file__)) + image_locations[i])
# pixmap = pixmap.scaled(60, 300, Qt.KeepAspectRatio, Qt.FastTransformation)
# self.btnImage.setPixmap(pixmap)
# ! Enableing this loads the images, but very slowly
# self.btnImage.setIcon(QIcon(os.path.dirname(os.path.abspath(__file__)) + '/view.png'))
# self.btnImage.setIconSize(QSize(150-6, 60-6))
self.button_images.append(self.btnImage)
layout.addWidget(self.btnImage, i, 0)
# ! This starts the QThread
converter = LoadImageThumbnailshread(
self.button_images, self.images_path)
converter.start()
self.horizontalGroupBox.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
因此,为了解释更多我想要的内容,我想在 UI 加载后启动 QThread
,QThread
会将所有图像加载到每个纽扣。问题是:它现在不工作。
我遇到的另一个问题是,当我收到 QThread
时,UI 等待它完成,然后所有内容突然弹出。我希望 QThread
完全独立且漂亮,如果您愿意,请看所有图片一张一张地加载。
线程不用于加速任何任务!!!而是执行不阻塞任何线程的任务。鉴于上述情况,如果我有 n 个“任务”并且每个任务都在“n”个线程中执行,那么总执行时间将为 1 个任务,也就是说,没有任务被加速但任务被重新分配。结论:如果你想加速任务,那么线程不是默认选项,因为它取决于应用程序。
另一方面,加载图片并不耗时,但是有很多耗时少的任务加起来相当于一个耗时多的任务,不幸的是那个任务无法执行另一个线程或进程,因为 GUI 的元素不是 thread-safe.
一个解决方法是每 T 秒加载一小组 n 个元素,这样整个任务将被分配并且用户不会观察到任何滞后影响。
import os
import sys
from PyQt5.QtCore import QSize, QTimer
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (
QApplication,
QDialog,
QGridLayout,
QGroupBox,
QPushButton,
QVBoxLayout,
)
class App(QDialog):
def __init__(self):
super().__init__()
self.title = "PyQt5 layout - pythonspot.com"
self.left = 10
self.top = 10
self.width = 320
self.height = 100
self.images_path = []
self.button_images = []
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.createGridLayout()
windowLayout = QVBoxLayout(self)
windowLayout.addWidget(self.horizontalGroupBox)
self._iter = iter(range(100))
self._timer = QTimer(interval=10, timeout=self.lazy_loading)
self._timer.start()
def createGridLayout(self):
self.horizontalGroupBox = QGroupBox("Grid")
self.grid_layout = QGridLayout()
self.grid_layout.setColumnStretch(1, 4)
self.grid_layout.setColumnStretch(2, 4)
self.horizontalGroupBox.setLayout(self.grid_layout)
def lazy_loading(self):
try:
i = next(self._iter)
except StopIteration:
self._timer.stop()
else:
btn = QPushButton()
image_path = os.path.join(os.path.abspath(__file__), "view.png")
btn.setIcon(QIcon(image_path))
btn.setIconSize(QSize(150 - 6, 60 - 6))
self.grid_layout.addWidget(btn, i, 0)
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())
所以我有这个 UI 可以加载很多按钮,所有按钮都有图像,问题是,它需要很长时间,所以我试着把它放到 QThread
中,我让它工作了, 但没有速度差异,所以我尝试了不同的解决方案,但现在线程无法启动。
代码:
import sys
import os
from PyQt5 import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui, QtPrintSupport, QtWidgets, uic
# I've tried using a QThread for this, but it still took the same amount of time.
class LoadImageThumbnailshread(QThread):
def __init__(self, listButtons, listPaths):
QThread.__init__(self)
self.listButtons = listButtons
self.listPaths = listPaths
def run(self):
self.process_images_Thread()
def process_images_Thread(self):
for i, j in enumerate(self.listButtons):
j.setIcon(QIcon(self.listPaths[i]))
j.setIconSize(QSize(150-6, 60-6))
class App(QDialog):
def __init__(self):
super().__init__()
self.title = 'PyQt5 layout - pythonspot.com'
self.left = 10
self.top = 10
self.width = 320
self.height = 100
self.images_path = []
self.button_images = []
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.createGridLayout()
windowLayout = QVBoxLayout()
windowLayout.addWidget(self.horizontalGroupBox)
self.setLayout(windowLayout)
self.show()
def createGridLayout(self):
self.horizontalGroupBox = QGroupBox("Grid")
layout = QGridLayout()
layout.setColumnStretch(1, 4)
layout.setColumnStretch(2, 4)
for i in range(100):
self.btnImage = QPushButton()
self.btnImage.setObjectName('btnImage')
self.images_path.append(os.path.dirname(
os.path.abspath(__file__)) + 'view.png')
# ! I have also tried using Pixmaps with Clickable labels, but it made no diffrence.
# pixmap = QPixmap(os.path.dirname(os.path.abspath(__file__)) + image_locations[i])
# pixmap = pixmap.scaled(60, 300, Qt.KeepAspectRatio, Qt.FastTransformation)
# self.btnImage.setPixmap(pixmap)
# ! Enableing this loads the images, but very slowly
# self.btnImage.setIcon(QIcon(os.path.dirname(os.path.abspath(__file__)) + '/view.png'))
# self.btnImage.setIconSize(QSize(150-6, 60-6))
self.button_images.append(self.btnImage)
layout.addWidget(self.btnImage, i, 0)
# ! This starts the QThread
converter = LoadImageThumbnailshread(
self.button_images, self.images_path)
converter.start()
self.horizontalGroupBox.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
因此,为了解释更多我想要的内容,我想在 UI 加载后启动 QThread
,QThread
会将所有图像加载到每个纽扣。问题是:它现在不工作。
我遇到的另一个问题是,当我收到 QThread
时,UI 等待它完成,然后所有内容突然弹出。我希望 QThread
完全独立且漂亮,如果您愿意,请看所有图片一张一张地加载。
线程不用于加速任何任务!!!而是执行不阻塞任何线程的任务。鉴于上述情况,如果我有 n 个“任务”并且每个任务都在“n”个线程中执行,那么总执行时间将为 1 个任务,也就是说,没有任务被加速但任务被重新分配。结论:如果你想加速任务,那么线程不是默认选项,因为它取决于应用程序。
另一方面,加载图片并不耗时,但是有很多耗时少的任务加起来相当于一个耗时多的任务,不幸的是那个任务无法执行另一个线程或进程,因为 GUI 的元素不是 thread-safe.
一个解决方法是每 T 秒加载一小组 n 个元素,这样整个任务将被分配并且用户不会观察到任何滞后影响。
import os
import sys
from PyQt5.QtCore import QSize, QTimer
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (
QApplication,
QDialog,
QGridLayout,
QGroupBox,
QPushButton,
QVBoxLayout,
)
class App(QDialog):
def __init__(self):
super().__init__()
self.title = "PyQt5 layout - pythonspot.com"
self.left = 10
self.top = 10
self.width = 320
self.height = 100
self.images_path = []
self.button_images = []
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.createGridLayout()
windowLayout = QVBoxLayout(self)
windowLayout.addWidget(self.horizontalGroupBox)
self._iter = iter(range(100))
self._timer = QTimer(interval=10, timeout=self.lazy_loading)
self._timer.start()
def createGridLayout(self):
self.horizontalGroupBox = QGroupBox("Grid")
self.grid_layout = QGridLayout()
self.grid_layout.setColumnStretch(1, 4)
self.grid_layout.setColumnStretch(2, 4)
self.horizontalGroupBox.setLayout(self.grid_layout)
def lazy_loading(self):
try:
i = next(self._iter)
except StopIteration:
self._timer.stop()
else:
btn = QPushButton()
image_path = os.path.join(os.path.abspath(__file__), "view.png")
btn.setIcon(QIcon(image_path))
btn.setIconSize(QSize(150 - 6, 60 - 6))
self.grid_layout.addWidget(btn, i, 0)
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())