RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1042332
Accepted
SIA
SIA
Asked:2020-11-05 02:56:07 +0000 UTC2020-11-05 02:56:07 +0000 UTC 2020-11-05 02:56:07 +0000 UTC

PyQt5 中的子进程执行

  • 772

我可以使用PyQt5上的一个小界面,以及加载和处理图像的功能。该函数结合 PyQt 的工作执行大约 3-4 秒。

在处理图像时,整个界面被“冻结”。
在这种情况下如何实现多线程,并行化进程而不停止PyQt?

我没有使用多线程,我听说过 asyncio,但我不知道在这种情况下到底该使用什么。

UPD:演示问题的最小示例

import sys
from PyQt5.QtWidgets import *
from time import sleep


class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 200, 200)
        self.setWindowTitle('Name')
        self.lay = QVBoxLayout(self)
        self.inp = QLineEdit()
        self.lay.addWidget(self.inp)
        self.btn = QPushButton('Действие')
        self.lay.addWidget(self.btn)
        self.btn.clicked.connect(lambda x: self.some_func(self.inp.text()))

    def some_func(self, n):
        sleep(int(n))  # Любое действие, требующее существенного времени на выполнение


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Window()
    ex.show()
    sys.exit(app.exec())
python
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    S. Nick
    2020-11-05T04:20:06Z2020-11-05T04:20:06Z

    QRunnable类是一个接口,用于表示要执行的任务或一段代码,由run()函数的重新实现来表示。

    您可以使用QThreadPool在单独的线程中执行您的代码...

    import sys
    import traceback
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5 import  *
    from time import sleep
    
    
    # Если при ошибке в слотах приложение просто падает без стека, 
    # есть хороший способ ловить такие ошибки:
    def log_uncaught_exceptions(ex_cls, ex, tb):
        text = '{}: {}:\n'.format(ex_cls.__name__, ex)
        #import traceback
        text += ''.join(traceback.format_tb(tb))
        QMessageBox.critical(None, 'Error', text)
        quit()
    sys.excepthook = log_uncaught_exceptions
    
    
    class MsgBoxWorker(QDialog):
        def __init__(self):
            super().__init__()
            self.setGeometry(900, 300, 400, 80)
            self.setWindowTitle('MsgBox Worker(QRunnable)') 
            layout     = QVBoxLayout(self)
            self.label = QLabel("")
            layout.addWidget(self.label)
            close_btn  = QPushButton("Close Окно")
            layout.addWidget(close_btn)
            # ------- Сигнал   это только закроет окно, поток как работал, так и работает
            close_btn.clicked.connect(self.close) 
    
    
    class WorkerSignals(QObject):
        ''' Определяет сигналы, доступные из рабочего рабочего потока Worker(QRunnable).'''
    
        finish   = pyqtSignal()
        error    = pyqtSignal(tuple)
        result   = pyqtSignal(object)
        progress = pyqtSignal(int)
    
    
    class Worker(QRunnable):
        ''' Наследует от QRunnable, настройки рабочего потока обработчика, сигналов и wrap-up. '''
    
        def __init__(self, fn, *args, **kwargs):
            super(Worker, self).__init__()
    
            # Хранить аргументы конструктора (повторно используемые для обработки)
            self.fn      = fn
            self.args    = args
            self.kwargs  = kwargs
            self.signals = WorkerSignals()
    
            #== Добавьте обратный вызов в наши kwargs ====================================###
            kwargs['progress_callback'] = self.signals.progress
    
        @pyqtSlot()
        def run(self):
            # Получите args/kwargs здесь; и обработка с их использованием
            try:                       # выполняем метод `some_func` переданный из Main
                result = self.fn(*self.args, **self.kwargs) 
            except:
                traceback.print_exc()
                exctype, value = sys.exc_info()[:2]
                self.signals.error.emit((exctype, value, traceback.format_exc()))
            else:  # если ошибок не была, испускаем сигнал .result и передаем результат `result`
                self.signals.result.emit(result)      # Вернуть результат обработки
            finally:
                self.signals.finish.emit()            # Done / Готово
    
    
    
    class Window(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setGeometry(300, 300, 200, 200)
            self.setWindowTitle('Name')
    
            self.inp = QLineEdit()
            self.btn = QPushButton('Действие')
            self.btn.clicked.connect(lambda x: self.some_func(self.inp.text()))
    
            self.progressBar = QProgressBar()
            self.progressBar.setProperty("value", 0)
    
            self.lay = QVBoxLayout(self)
            self.lay.addWidget(self.btn)
            self.lay.addWidget(self.inp)
            self.lay.addWidget(self.progressBar)
    
            self.threadpool = QThreadPool()
            print("Max потоков, кот. будут использоваться=`%d`" % self.threadpool.maxThreadCount())
            self.msgWorker = MsgBoxWorker()
    
    # ---- Worker(QRunnable) ------------------------# 
        def some_func(self, n):
    #        sleep(int(n))  # Любое действие, требующее существенного времени на выполнение
            # Передайте функцию для выполнения
            # Любые другие аргументы, kwargs передаются функции run
            worker = Worker(self.execute_this_fn) 
            worker.signals.result.connect(self.print_output)
            worker.signals.finish.connect(self.thread_complete)
            worker.signals.progress.connect(self.progress_fn)
            self.threadpool.start(worker)
    
        def progress_fn(self, n):
            self.progressBar.setValue(n)
            self.msgWorker.label.setText(str(n))
            # Восстанавливаем визуализацию потокового окна, если его закрыли. Поток работает.
            if not self.msgWorker.isVisible():        
                self.msgWorker.show()   
    
        def execute_this_fn(self, progress_callback):
            for n in range(0, 11):
                QThread.msleep(600)
                progress_callback.emit(n*100/10)
            return "Готово."
    
        def print_output(self, s):
            print("\ndef print_output(self, s):", s)
    
        def thread_complete(self):
            print("\nTHREAD ЗАВЕРШЕН!, self->", self)
    
    # --END-- Worker QRunnable) -------------------#         
    
        #==============================================###
        # потоки или процессы должны быть завершены    ###
        def closeEvent(self, event):
            reply = QMessageBox.question\
            (self, 'Информация',
                "Вы уверены, что хотите закрыть приложение?",
                 QMessageBox.Yes,
                 QMessageBox.No)
            if reply == QMessageBox.Yes:
                # закрыть поток Worker(QRunnable)
                self.msgWorker.close()
                super(Window, self).closeEvent(event)
            else:
                event.ignore()        
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        ex = Window()
        ex.show()
        sys.exit(app.exec())
    

    在此处输入图像描述

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5