PyQt - Диалог в друга нишка

моята програма има главен прозорец и в този прозорец изпълнява нишка, за да прочете мощността от фотодетектор, след което изпраща сигнал, който се улавя от слот в главния прозорец, който актуализира графичния интерфейс на главния прозорец.

След това имам друга джаджа (да я наречем програмна джаджа), която изскача от главния прозорец, което е основно обикновен текст, в който потребителят може да вмъква команди, така че програмата да ги изпълни. Сега идва въпросът:

Когато просто отворя приспособлението за програмиране с „покажи“, главният прозорец продължава да актуализира фотодетектора. Въпреки това, когато започна да изпълнявам последователност от приспособлението за програмиране, главният прозорец замръзва и показанията на фотодетектора спират с него, докато изпълнява командите (предполагам, че продължава да чете, защото е в друга нишка, но спира да актуализира графичния интерфейс на основния прозорец).

Въпросът ми е: джаджата за програмиране вече е по подразбиране в друга нишка, тъй като главният прозорец продължава да работи, когато се отвори. И така, защо той (главният прозорец) замръзва, когато програмният модул е ​​в цикъл?

Ето кода на темата:

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

Благодарим за подкрепата.


person Eduardo    schedule 19.09.2016    source източник
comment
Нито един обект, получен от QWidget, не може да бъде в нито една нишка, различна от основната нишка. Вашият код не е многонишков, той просто блокира потребителския интерфейс, когато сте в цикъл. UI кодът работи чрез изпълнение на цикъл на събития, който изпраща събития, когато сте заседнали в някакви слотове или манипулатори на събития, цикълът на събития не се изпълнява. Обърнете потока на контрол: вместо да чакате нещата в цикъл, използвайте таймер, който извиква кода ви от време на време, за да чете нещата или да реагира на нови данни, когато станат достъпни, ако използвате напр. a QSerialPort.   -  person Kuba hasn't forgotten Monica    schedule 20.09.2016
comment
Може да разгледате страницата с документация на Stack Overflow на PyQt за нишките също.   -  person three_pineapples    schedule 20.09.2016


Отговори (2)


Като цяло начинът, по който се прави това, е да се създаде клас, извлечен от QObject, който обработва цялото събиране на данни, различни от Qt, и да го преместите в отделна нишка, като използвате модел на работник.

След това можете да използвате сигнали, за да предавате данни напред и назад между основната (GUI) нишка и работната нишка и да задействате събития (като изскачащ диалогов прозорец в главната нишка поради събитие в работната нишка).

person Brendan Abel    schedule 19.09.2016
comment
Опитах се да преместя метода Execute в друга нишка, използвайки работния модел, както предложихте, но той все още замразява графичния интерфейс. За мен няма смисъл защо не работи сега. - person Eduardo; 21.09.2016

Опитах се да преместя метода Execute в друга нишка, използвайки работния модел, както беше предложено, но той също замрази графичния интерфейс, не знам защо. Вероятно съм направил нещо нередно.

Въпреки това, когато създадох друга нишка директно в класа, внедрена за изпълнение на цикъла, и тя работи. Следвах този пример: 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)
person Eduardo    schedule 21.09.2016