【问题标题】:PyQt - Dialog in another threadPyQt - 另一个线程中的对话框
【发布时间】:2017-01-27 13:47:00
【问题描述】:

我的程序有一个主窗口,在这个窗口中它运行一个线程来读取光电探测器的功率,然后它发送一个信号,该信号由主窗口中的一个插槽捕获,该插槽更新主窗口的 gui。

然后我有另一个从主窗口弹出的小部件(我们称之为编程小部件),它基本上是一个纯文本,用户可以在其中插入命令,以便程序执行它们。现在问题来了:

当我用“显示”打开编程小部件时,主窗口会不断更新光电探测器。但是,当我开始从编程小部件执行序列时,主窗口会冻结,并且在执行命令时光电探测器读数会随之停止(我猜它会继续读取,因为它在另一个线程中,但它会停止更新主窗口的 gui)。

我的问题是:默认情况下,编程小部件已经在另一个线程中,因为主窗口在弹出时会继续工作。那么,为什么当编程小部件处于循环状态时它(主窗口)会冻结?

这里是线程代码:

class PDThread(QtCore.QThread):

valueupdate = QtCore.pyqtSignal(float)
state = 1

def __init__(self, state, port):
    QtCore.QThread.__init__(self)
    self.photodetector = PM100D()
    self.port = port

def run(self):
        while True:
            try:
                self.photodetector.connect(self.port)
                break
            except:
                self.dialog = dialog_classes.DialogPort()
                self.dialog.set_instrument('PM100D')
                self.dialog.exec_()
                ret = self.dialog.pm100d.itemText(self.dialog.pm100d.currentIndex())
                if ret == QtGui.QDialog.Accepted:
                    self.port = str(ret)
                else:
                    self.photodetector.__del__()
                    self.quit()
                    return

        window.PDState = 1
        window.startpd.setText('Stop PD')     
        while self.state == 1:
            time.sleep(0.1)
            value = self.photodetector.get_pow()
            self.valueupdate.emit(value)

这是在主窗口中创建线程和槽的函数:

def ActionConnect_PM100D(self):
    if self.PDState == 0:
        self.PD = PDThread(self.PDState, self.PDport)
        self.PD.valueupdate.connect(self.PDHandler)
        self.threads = []
        self.threads.append(self.PD)
        self.PD.start()
    else:
        self.PDState = 0
        self.PD.state = 0
        self.startpd.setText('Start PD')


def PDHandler(self, value):
    ref = float(self.refpd.value())
    self.outputpd.setText(str(value-ref))

这里也是在主窗口中,创建小部件的函数:

    def ActionSetup(self):
    self.program = dialog_classes.Programming(self.newport, self.output, self.outputpd)
    self.program.show()

最后是小部件代码:

class Programming(QtGui.QDialog, Ui_Programming_Dialog, gui.MyApp):

def __init__(self, ESP300, output, outputpd):
    QtGui.QDialog.__init__(self)
    self.setupUi(self)
    self.setWindowTitle('Programming Setup')
    self.openbuttom.clicked.connect(self.Open)
    self.save.clicked.connect(self.Save)
    self.execute.clicked.connect(self.Execute)
    self.newport = ESP300
    self.output = output
    self.outputpd = outputpd

def Open(self):
    self.fileName = QtGui.QFileDialog.getOpenFileName(self, 'OpenFile', '', '*.txt')
    try:
        text = open(self.fileName).read()
    except:
        None
    else:
        self.program.setPlainText(text)

def Save(self):
    self.fileName = QtGui.QFileDialog.getSaveFileName(self, 'Save File', '', '*.txt')
    try:
        open(self.fileName, 'w').write(str(self.program.toPlainText()))
    except:
        None

def Execute(self):
    text = str(self.program.toPlainText())
    lines = text.split('\n')
    for line in lines:
        arg = []
        List = line.split(',')
        for word in List:
            arg.append(word.strip())

        if arg[0].lower() == 'move':
            if arg[1].lower() == 'x':
                self.newport.move_x(float(arg[2]))
            elif arg[1].lower() == 'y':
                self.newport.move_y(float(arg[2]))
            elif arg[1].lower() == 'z':
                self.newport.move_z(float(arg[2]))
        elif arg[0].lower() == 'wait':
            self.newport.wait()
        elif arg[0].lower() == 'home':
            self.newport.home()
            while True:
                try:
                    self.GetPosition()
                except:
                    time.sleep(0.5)
                else:
                    if self.newport.x == 0 and self.newport.y == 0 and self.newport.z == 0:
                        break
        elif arg[0].lower() == 'power on':
            self.newport.power_on(arg[1])
        elif arg[0].lower() == 'power off':
            self.newport.power_off(arg[1])
        elif arg[0].lower() == 'pos':
            self.newport.pos_x(arg[1])
            self.newport.pos_y(arg[2])
            self.newport.pos_z(arg[3])
            while True:
                try:
                    self.GetPosition()
                except:
                    time.sleep(0.5)
                else:
                    time.sleep(1)
                    break
        elif arg[0].lower() == 'get pos':
            self.GetPosition()
        elif arg[0].lower() == 'get error':
            self.GetError()
        elif arg[0].lower() == 'get pow':
            print(self.outputpd.toPlainText())

        time.sleep(2)


def closeIt(self):
    self.close()

感谢您的支持。

【问题讨论】:

  • 没有QWidget-derived 对象可以在除主线程之外的任何线程中。您的代码不是多线程的,它只是在您处于循环中时阻塞 UI。 UI 代码通过执行分发事件的事件循环来工作,当您卡在任何插槽或事件处理程序中时,事件循环不会运行。反转控制流程:不要在循环中等待,而是使用一个计时器,每隔一段时间调用你的代码来读取内容,或者在新数据可用时做出反应,如果你正在使用例如QSerialPort.
  • 你不妨也看看 Stack Overflow PyQt documentation page on threads

标签: python multithreading qt dialog pyqt


【解决方案1】:

通常,这样做的方法是创建一个派生自 QObject 的类,该类处理所有非 Qt 数据收集,并使用 worker model 将其移动到单独的线程中。

然后,您可以使用信号在主(GUI)线程和工作线程之间来回传递数据,并触发事件(例如由于工作线程中的事件而在主线程中弹出对话框) .

【讨论】:

  • 我尝试按照您的建议使用工作模型将 Execute 方法移动到另一个线程,但它仍然冻结 gui。为什么它现在不起作用,对我来说没有意义。
【解决方案2】:

我尝试按照建议使用 worker 模型 将 Execute 方法移动到另一个线程,但它也冻结了 gui,我不知道为什么。可能我做错了什么。

但是,当我直接在实现循环的类中创建另一个线程时,它就起作用了。我按照这个例子:https://nikolak.com/pyqt-threading-tutorial/

另外,这是我的代码。我希望它也可以帮助其他人,谢谢。

self.worker_thread = []

def Execute(self):
    self.execution = ProgramExecution(self.newport, self.output, self.outputpd, self.program)
    self.worker_thread.append(self.execution)
    self.execution.start()

这里是线程类:

class ProgramExecution(QtCore.QThread):

_signalStatus = QtCore.pyqtSignal(str)

def __init__(self, ESP300, output, outputpd, program):
    QtCore.QThread.__init__(self)
    self.newport = ESP300
    self.output = output
    self.outputpd = outputpd
    self.program = program

def __del__(self):
    self.wait()

def run(self):
    text = str(self.program.toPlainText())
    lines = text.split('\n')
    for line in lines:
        arg = []
        List = line.split(',')
        for word in List:
            arg.append(word.strip())

        if arg[0].lower() == 'move':
            if arg[1].lower() == 'x':
                self.newport.move_x(float(arg[2]))
            elif arg[1].lower() == 'y':
                self.newport.move_y(float(arg[2]))
            elif arg[1].lower() == 'z':
                self.newport.move_z(float(arg[2]))
        elif arg[0].lower() == 'wait':
            self.newport.wait()
        elif arg[0].lower() == 'home':
            self.newport.home()
            while True:
                try:
                    self.GetPosition()
                except:
                    time.sleep(0.5)
                else:
                    if self.newport.x == 0 and self.newport.y == 0 and self.newport.z == 0:
                        break
        elif arg[0].lower() == 'power on':
            self.newport.power_on(arg[1])
        elif arg[0].lower() == 'power off':
            self.newport.power_off(arg[1])
        elif arg[0].lower() == 'pos':
            self.newport.pos_x(arg[1])
            self.newport.pos_y(arg[2])
            self.newport.pos_z(arg[3])
            while True:
                try:
                    self.GetPosition()
                except:
                    time.sleep(0.5)
                else:
                    time.sleep(1)
                    break
        elif arg[0].lower() == 'get pos':
            self.GetPosition()
        elif arg[0].lower() == 'get error':
            self.GetError()
        elif arg[0].lower() == 'get pow':
            print(self.outputpd.toPlainText())

        time.sleep(2)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-05
    • 2015-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-05
    相关资源
    最近更新 更多