为了账号安全,请及时绑定邮箱和手机立即绑定

PyQT线程化的最简单方法

PyQT线程化的最简单方法

慕姐4208626 2019-11-20 10:39:45
我在PyQt中有一个带有功能的GUI addImage(image_path)。容易想象,当新图像应添加到QListWidget中时被调用。为了检测文件夹中的新图像,我使用了threading.Threadwith watchdog来检测文件夹中的文件更改,然后该线程addImage直接调用。QPixmap出于线程安全的原因,这会产生不应在gui线程之外调用的警告。使该线程安全的最佳和最简单的方法是什么?QThread?信号/插槽?QMetaObject.invokeMethod?我只需要从线程传递一个字符串到addImage。
查看完整描述

3 回答

?
largeQ

TA贡献2039条经验 获得超7个赞

我相信最好的方法是使用信号/插槽机制。这是一个例子。(注意:请参见下面的EDIT,指出我的方法可能存在的缺陷)。


from PyQt4 import QtGui

from PyQt4 import QtCore


# Create the class 'Communicate'. The instance

# from this class shall be used later on for the

# signal/slot mechanism.


class Communicate(QtCore.QObject):

    myGUI_signal = QtCore.pyqtSignal(str)


''' End class '''



# Define the function 'myThread'. This function is the so-called

# 'target function' when you create and start your new Thread.

# In other words, this is the function that will run in your new thread.

# 'myThread' expects one argument: the callback function name. That should

# be a function inside your GUI.


def myThread(callbackFunc):

    # Setup the signal-slot mechanism.

    mySrc = Communicate()

    mySrc.myGUI_signal.connect(callbackFunc) 


    # Endless loop. You typically want the thread

    # to run forever.

    while(True):

        # Do something useful here.

        msgForGui = 'This is a message to send to the GUI'

        mySrc.myGUI_signal.emit(msgForGui)

        # So now the 'callbackFunc' is called, and is fed with 'msgForGui'

        # as parameter. That is what you want. You just sent a message to

        # your GUI application! - Note: I suppose here that 'callbackFunc'

        # is one of the functions in your GUI.

        # This procedure is thread safe.


    ''' End while '''


''' End myThread '''

在GUI应用程序代码中,应该创建新的Thread,为其提供正确的回调函数,然后使其运行。


from PyQt4 import QtGui

from PyQt4 import QtCore

import sys

import os


# This is the main window from my GUI


class CustomMainWindow(QtGui.QMainWindow):


    def __init__(self):

        super(CustomMainWindow, self).__init__()

        self.setGeometry(300, 300, 2500, 1500)

        self.setWindowTitle("my first window")

        # ...

        self.startTheThread()


    ''''''


    def theCallbackFunc(self, msg):

        print('the thread has sent this message to the GUI:')

        print(msg)

        print('---------')


    ''''''



    def startTheThread(self):

        # Create the new thread. The target function is 'myThread'. The

        # function we created in the beginning.

        t = threading.Thread(name = 'myThread', target = myThread, args = (self.theCallbackFunc))

        t.start()


    ''''''


''' End CustomMainWindow '''



# This is the startup code.


if __name__== '__main__':

    app = QtGui.QApplication(sys.argv)

    QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Plastique'))

    myGUI = CustomMainWindow()

    sys.exit(app.exec_())


''' End Main '''

编辑


三菠萝先生和布伦丹·阿贝尔先生指出了我的作风。确实,该方法在这种特定情况下效果很好,因为您可以直接生成/发射信号。当处理按钮和小部件上的内置Qt信号时,您应该采用另一种方法(如Brendan Abel先生的回答中所指定)。


three_pineapples先生建议我在StackOverflow中启动一个新主题,以比较与GUI进行线程安全通信的几种方法。我将深入研究问题,明天再做:-)


查看完整回答
反对 回复 2019-11-20
?
白猪掌柜的

TA贡献1893条经验 获得超10个赞

您应该使用QThreadQt提供的内置功能。您可以将文件监视代码放在从其继承的工作程序类中,QObject以便它可以使用Qt Signal / Slot系统在线程之间传递消息。


class FileMonitor(QObject):


    image_signal = QtCore.pyqtSignal(str)


    @QtCore.pyqtSlot()

    def monitor_images(self):

        # I'm guessing this is an infinite while loop that monitors files

        while True:

            if file_has_changed:

                self.image_signal.emit('/path/to/image/file.jpg')



class MyWidget(QtGui.QWidget):


    def __init__(self, ...)

        ...

        self.file_monitor = FileMonitor()

        self.thread = QtCore.QThread(self)

        self.file_monitor.image_signal.connect(self.image_callback)

        self.file_monitor.moveToThread(self.thread)

        self.thread.started.connect(self.file_monitor.monitor_images)

        self.thread.start()


    @QtCore.pyqtSlot(str)

    def image_callback(self, filepath):

        pixmap = QtGui.QPixmap(filepath)

        ...


查看完整回答
反对 回复 2019-11-20
?
哔哔one

TA贡献1854条经验 获得超8个赞

Brendan @Brendan Abel,您好:您是否可以澄清:“通常也建议不要从那些对象外部向其他对象发出信号,而其他答案可以,而正式工作者模型则不能”?我有兴趣进一步了解。因为我在最近的应用程序中经常使用信号/时隙机制。非常感谢您:-) 

查看完整回答
反对 回复 2019-11-20
  • 3 回答
  • 0 关注
  • 449 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信