PyQt - 另一个线程中的对话框

时间:2016-09-19 19:13:29

标签: python multithreading qt dialog pyqt

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

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

当我用" show"打开编程小部件时,主窗口不断更新光电探测器。但是,当我从编程小部件开始执行序列时,主窗口冻结并且光电探测器读数在执行命令时停止(我猜它会继续读取,因为它在另一个线程中但它停止更新主窗口' s 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()

感谢您的支持。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

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

然而,当我在实现循环的类中直接创建另一个线程时,它起作用了。我按照这个例子:{{3}}

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

>> y
y(:,:,1) =
       0.8314       0.3993       0.6569
       0.8034       0.5269        0.628
       0.0605       0.4168        0.292
y(:,:,2) =
       0.4317       0.1672       0.1981
       0.0155       0.1062       0.4897
       0.9841       0.3724       0.3395
>> reshape(permute(y,[2,1,3]),[],size(y,3))
ans =
       0.8314       0.4317
       0.3993       0.1672
       0.6569       0.1981
       0.8034       0.0155
       0.5269       0.1062
        0.628       0.4897
       0.0605       0.9841
       0.4168       0.3724
        0.292       0.3395

这是Thread Class:

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()