2016-09-19 5 views
0

В моей программе есть главное окно, и в этом окне он запускает поток для считывания мощности с фотодетектора, затем посылает сигнал, который фиксируется слотом в главном окне, который обновляет основной окно gui.PyQt - Dialog в другом потоке

Тогда у меня есть еще один виджет (назовем его программным виджнем), который появляется из главного окна, которое в основном представляет собой обычный текст, в который пользователь может вставлять команды, чтобы программа выполняла их. Теперь возникает вопрос:

Когда я просто открываю программный виджет с помощью «show», основное окно обновляет фотодетектор. Однако, когда я начинаю выполнение последовательности из виджета программирования, главное окно зависает, и показания фотодетектора останавливаются с ним во время выполнения команд (я думаю, он продолжает читать, потому что находится в другом потоке, но он перестает обновлять 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() 

Благодарим вас за поддержку.

+1

Нет 'QWidget'-производный объект не может быть в любом потоке, отличном от основного потока. Ваш код не многопоточен, он просто блокирует пользовательский интерфейс, когда вы находитесь в цикле. Код UI работает, выполняя цикл событий, который отправляет события, когда вы застряли в любых слотах или обработчиках событий, цикл событий не запускается.Инвертируйте поток управления: вместо того, чтобы ждать вещей в цикле, используйте таймер, который каждый раз вызывает ваш код, чтобы читать что-либо или реагировать на новые данные, когда он становится доступным, если вы используете, например. 'QSerialPort'. –

+0

Возможно, вы захотите посмотреть на страницу стека Overflow PyQt [документация по потокам] (http://stackoverflow.com/documentation/pyqt/2775/using-threads-with-pyqt#t=201609200232140019483). –

ответ

0

Я попытался переместить метод 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) 
0

Как правило, это делается для создания класса, полученного из QObject, который обрабатывает все данные, отличные от Qt, и перемещает их в отдельный поток, используя worker model.

Затем вы можете использовать сигналы для передачи данных назад и вперед между потоком основного (GUI) и потоком Worker и инициировать события (например, вызывать диалог в основном потоке из-за события в рабочем потоке).

+0

Я попытался переместить метод Execute в другой поток, используя рабочую модель, как вы предложили, но она по-прежнему замораживает gui. Мне не имеет смысла, почему он сейчас не работает. – Eduardo

Смежные вопросы