代码之家  ›  专栏  ›  技术社区  ›  Vesnog

Python上Qt中的QThread

  •  1
  • Vesnog  · 技术社区  · 7 年前

    我雇用 QThread 在阅读了关于如何使用QThread的扩展讨论之后使用worker对象,并通过子类化覆盖其run方法,这不是合适的方法。但是,在我打算使用的方法中,我需要传递一个在启动线程时不可用的附加函数参数,并使用 moveToThread . 此信息(参数)在按下按钮时可用,并传达移动对象的信息。

    在我的代码的完整版本中,有三个单独的控制器用于三个单独的对象,您可以在下面找到一个最小的工作示例,演示我试图传递的参数。该代码也可在 pastebin 感兴趣的行号是10-28、46-50和133-135。

    到目前为止,我已经尝试在连接到worker中实际函数的行中使用lambda构造函数。这就是路线 self.thread.started.connect(self.obj.moveLeftIncrement) 然后尝试使用 ,但我不太了解他们。此外,尽管使用QThread,GUI有时会挂起,并且在程序退出后会出现错误,其中一个错误如下:

    我的问题如下:

    1. 如何在运行时传递参数和/或使用插槽?
    2. 如何防止退出时出现程序错误?
    3. 为什么子类化QThread在这种情况下直接起作用,尽管不建议这样做?

    from PySide2.QtCore import *
    from PySide2.QtWidgets import *
    from PySide2.QtGui import *
    import sys
    import time
    
    class Worker(QObject):
        finished = Signal(int)
    
        @Slot(str)
        def moveLeftIncrement(self, controller_name):
            # controller_name = "Controller 1"
            print("Controller name is ", controller_name)
            if controller_name == "Controller 1":
                print("Starting controller 1")
                time.sleep(2)
                print("Finishing sleep")
            elif controller_name == "Controller 2":
                print("Starting controller 2")
                time.sleep(2)
                print("Finishing sleep")
            elif controller_name == "Controller 3":
                print("Starting controller 3")
                time.sleep(2)
                print("Finishing sleep")
            else:
                raise Exception("No such controller found!")
            self.finished.emit(0)
    
    
    class Window(QWidget):
        """ Inherits from QWidget """
        def closeEvent(self, *args, **kwargs):
            print("\nClosing")
    
        def __init__(self):
            super().__init__()
            self.CONTINUOUS_MOVE_SWITCH = False
            self.title = 'Control Controllers'
            self.left = 10
            self.top = 10
            self.width = 320
            self.height = 100
            self.AxesMapping = [0, 1, 2, 3]
            self.initUI()
            self.thread = QThread()
            self.obj = Worker()
            self.obj.moveToThread(self.thread)
            self.thread.started.connect(self.obj.moveLeftIncrement)
            self.obj.finished.connect(self.thread.quit)
    
        def initUI(self):
            """ Initializes the GUI either using the grid layout or the absolute position layout"""
            self.setWindowTitle(self.title)
            self.setGeometry(self.left, self.top, self.width, self.height)
            Comp1 = self.createGridLayout("Controller 2")
            windowLayout = QGridLayout()
    
            windowLayout.addWidget(Comp1, 0, 0)
            self.setLayout(windowLayout)
            self.show()
    
        def createGridLayout(self, controller):
            """Creates a grid layout for the buttons"""
            box_size = QSize(640, 440)
            HGroupBox = QGroupBox(controller)
            layout = QGridLayout()
            layout.addWidget(self.createButton("left", controller), 2, 1)
            layout.addWidget(self.createButton("right", controller), 2, 3)
            layout.addWidget(self.createButton("forward", controller), 1, 2)
            layout.addWidget(self.createButton("backward", controller), 3, 2)
            HGroupBox.setLayout(layout)
            HGroupBox.setFixedSize(box_size)
            return HGroupBox
    
        def createButton(self, name, controller):
            """Creates a button with the specified size"""
            button_size = QSize(100, 40)
            icon_size = 40
            button = QPushButton()
            button.Name = name
            button.Controller = controller
            button.Moving = 0
            button.clicked.connect(lambda: self.buttonPresssed(button))
            button.setFixedSize(button_size)
            return button
    
        def moveLeftIncrement(self, controller, button):
            if controller == "Controller 1":
                time.sleep(2)
            elif controller == "Controller 2":
                time.sleep(2)
            elif controller == "Controller 3":
                time.sleep(2)
            else:
                raise Exception("No such controller found!")
    
        def moveRightIncrement(self, controller, button):
            if controller == "Controller 1":
                time.sleep(2)
            elif controller == "Controller 2":
                time.sleep(2)
            elif controller == "Controller 3":
                time.sleep(2)
            else:
                raise Exception("No such controller found!")
    
        def moveForwardIncrement(self, controller, button):
            if controller == "Controller 1":
                time.sleep(2)
            elif controller == "Controller 2":
                time.sleep(2)
            elif controller == "Controller 3":
                time.sleep(2)
            else:
                raise Exception("No such controller found!")
    
        def moveBackwardIncrement(self, controller, button):
            if controller == "Controller 1":
                time.sleep(2)
            elif controller == "Controller 2":
                time.sleep(2)
            elif controller == "Controller 3":
                time.sleep(2)
            else:
                raise Exception("No such controller found!")
    
        def buttonPresssed(self, button):
            name = button.Name
            if hasattr(button, 'Controller'):
                controller = button.Controller
                print("The controller selected is", controller)
            if name == 'left':
                self.thread.start()
            elif name == 'right':
                print("Moved controller right for a single step")
                self.moveRightIncrement(controller, button)
            elif name == 'forward':
                self.moveForwardIncrement(controller, button)
                print("Moved controller forward for a single step")
            elif name == 'backward':
                self.moveBackwardIncrement(controller, button)
                print("Moved controller backward for a single step")
            elif name == "up":
                print("Moving controller up for a single step")
                self.moveUpIncrement(controller, button)
            elif name == "down":
                print("Moving controller down for a single step")
                self.moveDownIncrement(controller, button)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        ex = Window()
        sys.exit(app.exec_())
    
    1 回复  |  直到 7 年前
        1
  •  7
  •   eyllanesc    7 年前

    -如何在运行时传递参数和/或使用插槽?

    -如何防止退出时出现程序错误?

    在您的情况下,错误是由于您有一个正在运行的线程而没有停止它而导致的,一个可能的选项是使用closeEvent来停止它。

    -为什么子类化QThread在这种情况下直接起作用,尽管不建议这样做?

    这并不是说我们不推荐它,但它非常有限,有更好的选择,比如使用另一个线程中的工作线程,这样我们就可以使用不同的方法,而不仅仅是在run方法中执行任务。此外,通过辅助线程选项,您可以在一个线程中拥有多个对象。


    对于工人,方法如下:

    • 创建一个QThread并启动处理的线程。
    • 创建一个将位于另一个线程中的对象并移动另一个线程
    • 连接调用对象插槽的信号,还连接将向GUI发送对象信息的信号。

    from PySide2 import QtCore, QtGui, QtWidgets
    import time
    
    class Worker(QtCore.QObject):
        error = QtCore.Signal()
    
        @QtCore.Slot(str)
        def moveLeftIncrement(self, controller):
            if controller == "Controller 1":
                time.sleep(2)
            elif controller == "Controller 2":
                time.sleep(2)
            elif controller == "Controller 3":
                time.sleep(2)
            else:
                self.error.emit("No such controller found!")
    
        @QtCore.Slot(str)
        def moveRightIncrement(self, controller):
            if controller == "Controller 1":
                time.sleep(2)
            elif controller == "Controller 2":
                time.sleep(2)
            elif controller == "Controller 3":
                time.sleep(2)
            else:
                self.error.emit("No such controller found!")
    
        @QtCore.Slot(str)
        def moveForwardIncrement(self, controller, button):
            if controller == "Controller 1":
                time.sleep(2)
            elif controller == "Controller 2":
                time.sleep(2)
            elif controller == "Controller 3":
                time.sleep(2)
            else:
                self.error.emit("No such controller found!")
    
        @QtCore.Slot(str)
        def moveBackwardIncrement(self, controller, button):
            if controller == "Controller 1":
                time.sleep(2)
            elif controller == "Controller 2":
                time.sleep(2)
            elif controller == "Controller 3":
                time.sleep(2)
            else:
                self.error.emit("No such controller found!")
    
    class Window(QtWidgets.QWidget):
        leftClicked = QtCore.Signal(str)
        rightClicked = QtCore.Signal(str)
        forwardClicked = QtCore.Signal(str)
        backwardClicked = QtCore.Signal(str)
    
        def __init__(self):
            super().__init__()
            self.CONTINUOUS_MOVE_SWITCH = False
            self.title = 'Control Controllers'
            self.left, self.top, self.width, self.height = 10, 10, 320, 100
            self.AxesMapping = [0, 1, 2, 3]
    
            self.initUI()
    
            self.thread = QtCore.QThread(self)
            self.thread.start()
            self.obj = Worker()
            self.obj.moveToThread(self.thread)
            self.leftClicked.connect(self.obj.moveLeftIncrement)
            self.rightClicked.connect(self.obj.moveRightIncrement)
            self.forwardClicked.connect(self.obj.moveForwardIncrement)
            self.backwardClicked.connect(self.obj.moveBackwardIncrement)
            self.obj.error.connect(self.on_error)
    
        def initUI(self):
            self.setWindowTitle(self.title)
            self.setGeometry(self.left, self.top, self.width, self.height)
            Comp1 = self.createGridLayout("Controller 2")
            windowLayout = QtWidgets.QGridLayout(self)
            windowLayout.addWidget(Comp1, 0, 0)
    
        def createGridLayout(self, controller):
            """Creates a grid layout for the buttons"""
            box_size = QtCore.QSize(640, 440)
            HGroupBox = QtWidgets.QGroupBox(controller)
            layout = QtWidgets.QGridLayout()
            layout.addWidget(self.createButton("left", controller), 2, 1)
            layout.addWidget(self.createButton("right", controller), 2, 3)
            layout.addWidget(self.createButton("forward", controller), 1, 2)
            layout.addWidget(self.createButton("backward", controller), 3, 2)
            HGroupBox.setLayout(layout)
            HGroupBox.setFixedSize(box_size)
            return HGroupBox
    
        def createButton(self, name, controller):
            button_size = QtCore.QSize(100, 40)
            icon_size = 40
            button = QtWidgets.QPushButton()
            button.Name = name
            button.Controller = controller
            button.Moving = 0
            button.clicked.connect(self.buttonPresssed)
            button.setFixedSize(button_size)
            return button
    
        @QtCore.Slot()
        def buttonPresssed(self):
            button = self.sender()
            name = button.Name
            if hasattr(button, 'Controller'):
                controller = button.Controller
                print("The controller selected is", controller)
                if name == 'left':
                    self.leftClicked.emit(controller)
                elif name == 'right':
                    print("Moved controller right for a single step")
                    self.rightClicked.emit(controller)
                elif name == 'forward':
                    print("Moved controller forward for a single step")
                    self.forwardClicked.emit(controller)
                elif name == 'backward':
                    print("Moved controller backward for a single step")
                    self.backwardClicked.emit(controller)
    
        @QtCore.Slot(str)
        def on_error(self, error):
            print(error)
    
        def closeEvent(self, event):
            self.thread.quit()
            self.thread.wait()
            super(Window, self).closeEvent(event)
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        ex = Window()
        ex.show()
        sys.exit(app.exec_())
    
    推荐文章