python pyqt5 QThread

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python pyqt5 QThread相关的知识,希望对你有一定的参考价值。

参考技术A

\'\'\'
【简介】
PyQT5中 QTimer例子

\'\'\'

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

global sec
sec = 0

class WorkThread(QThread):
trigger = pyqtSignal()

def countTime():
global sec
sec += 1
# LED显示数字+1
lcdNumber.display(sec)

def work():
# 计时器每秒计数
timer.start(1000)
# 计时开始
workThread.start()
# 当获得循环完毕的信号时,停止计数
workThread.trigger.connect(timeStop)

def timeStop():
timer.stop()
print("运行结束用时", lcdNumber.value())
global sec
sec = 0

if name == " main ":
app = QApplication(sys.argv)
top = QWidget()
top.resize(300, 120)

\'\'\'
【简介】
PyQT5中 QThread 例子

\'\'\'

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class MainWidget(QWidget):
def init (self, parent=None):
super(MainWidget, self). init (parent)
self.setWindowTitle("QThread 例子")
self.thread = Worker()
self.listFile = QListWidget()
self.btnStart = QPushButton(\'开始\')
layout = QGridLayout(self)
layout.addWidget(self.listFile, 0, 0, 1, 2)
layout.addWidget(self.btnStart, 1, 1)
self.btnStart.clicked.connect(self.slotStart)
self.thread.sinOut.connect(self.slotAdd)

class Worker(QThread):
sinOut = pyqtSignal(str)

if name == " main ":
app = QApplication(sys.argv)
demo = MainWidget()
demo.show()
sys.exit(app.exec_())

Python PyQt5 在 QThread 上为 QPushButton 加载图像

【中文标题】Python PyQt5 在 QThread 上为 QPushButton 加载图像【英文标题】:Python PyQt5 load Image for QPushButton on QThread 【发布时间】:2020-11-10 03:31:52 【问题描述】:

所以我有这个 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 加载后启动 QThreadQThread 会将所有图像加载到每个按钮上。问题是:它现在不起作用。

我遇到的另一个问题是,当我收到QThread 时,UI 等待它完成,然后突然间弹出所有内容。我希望QThread 完全独立且漂亮,如果您愿意的话,可以查看所有加载的图片。

【问题讨论】:

【参考方案1】:

线程不用于加速任何任务!!!,而是执行不阻塞任何线程的任务。鉴于上述情况,如果我有 n 个“任务”并且每个任务在“n”个线程中执行,那么总执行时间将是 1 个任务,也就是说,没有任务被加速但任务被重新分配。总结:如果你想加速一个任务,那么线程不是默认选项,因为它取决于应用程序。

另一方面,图像的加载不消耗时间,但是有很多任务消耗的时间很少,总共相当于一个消耗大量时间的任务,不幸的是该任务无法在另一个线程中执行或进程,因为 GUI 的元素不是线程安全的。

一种解决方法是每 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_())

【讨论】:

这很好用,并阻止我的程序“挂起”。但我只是想借此机会问问。虽然这种方法有效,但我不能使用标准的QThread 并在加载所有 UI 之后执行此任务吗? @JareBear 我的答案很明确:GUI 不是线程安全的 好的,非常感谢!有时它只是让我感到沮丧,我想使用带有 GUI 的 QThread 但它永远不会成功:'D

以上是关于python pyqt5 QThread的主要内容,如果未能解决你的问题,请参考以下文章

python pyqt5 QThread

python pyqt5 QTableWidget 设置表头

搭建pyqt5开发环境(python3+pycharm2019+pyqt5)

Python 3.x 安装PyQt5

python pyqt5 载入gif

如何安装python3-pyqt5