PySide: почему QMainWindow флашировался и исчезал при запуске QAction в другом QmainWIndow(Main)

Я новичок в PySide. Я столкнулся с проблемой: новый QMainWindow вспыхнул и исчез, когда я запустил QAction из другого QmainWIndow (основной пользовательский интерфейс). Здесь я размещаю пример кода, чтобы проиллюстрировать вышеизложенное:

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent = None):
       super(MainWindow, self).__init__(parent)
       ...
       self.execTaskAct = QtGui.QAction("execute", self,  triggered=self.executeTask)
       ...

    def  executeTask(self):
      task = TaskWindow()

class  TaskWindow(QtGui.QMainWindow):
    def __init__(self, parent = None):
       super(TaskWindow, self).__init__(parent)
       ...
      self.show()


if __name__ == '__main__':

    import sys

    app = QtGui.QApplication(sys.argv)
    mainWin = MainWindow()
    mainWin.show()
    sys.exit(app.exec_())

person tao4yu    schedule 14.01.2014    source источник
comment
Просто добавьте self перед переменной task. self.task = TaskWindow()   -  person qurban    schedule 14.01.2014


Ответы (2)


Вы не сохраняете ссылку на новое окно QMainWindow после его создания, и, поскольку это новое окно (TaskWindow) не имеет родителя, окно удаляется сборщиком мусора после запуска метода executeTask.

Вам просто нужно сохранить ссылку на новое окно, изменив executeTask на:

def  executeTask(self):
    self.task = TaskWindow()

Обратите внимание, что если действие выполняется дважды, оно перезапишет первое TaskWindow и заставит его исчезнуть или произойдет сбой приложения. Вы можете решить, что должно произойти в этом случае, или лучший метод хранения ссылок на несколько TaskWindow (например, в списке).

Обратите внимание, что вам нужно хранить ссылки на QWidget только в том случае, если у них нет родителя (что верно в вашем текущем случае). Если у QWidget есть родитель, Qt сохраняет внутреннюю ссылку.

person three_pineapples    schedule 14.01.2014

Прежде всего, ваш код содержит синтаксическую ошибку из-за непоследовательного отступа, который является проблемой в python.

Что еще более важно, у вас есть локальный объект, созданный в методе execute, и как только ваш метод завершится, локально созданный объект будет уничтожен.

Это потому, что метод show() для qwidget не блокирует. Они просто поставят событие в очередь для цикла событий Qt, чтобы обработать запрос, когда цикл событий станет доступным.

Вы можете сделать переменную с областью действия класса в MainWindow, но тогда вы можете переместить создание TaskWindow в метод init, чтобы избежать ненужного создания объекта каждый раз, когда испускается сигнал, и вы будете отображать TaskWindow только в методе выполнения следующим образом. :

def __init__(self, parent = None):
   super(MainWindow, self).__init__(parent)
   ...
   self.execTaskAct = QtGui.QAction("execute", self,  triggered=self.executeTask)
   ...
   self.task = TaskWindow()

def  executeTask(self):
  task.show()

Если вы действительно хотите создавать новый объект каждый раз, когда запускается выполнение, вы можете просто добавить ключевое слово «self», чтобы сделать каждый вновь созданный объектный класс ограниченным. Тем не менее, убедитесь, что вы не оставляете окно без ссылок в неопределенном поведении. Итак, вы бы написали что-то вроде этого:

def  executeTask(self):
  self.task = TaskWindow()

Тогда вам нужно будет удалить вызов show() из метода инициализации TaskWindow.

При этом я бы также назначил родителя для TaskWindow для полноты, либо MainWindow, либо сам объект приложения.

self.task = TaskWindow(self)

Также обратите внимание, что если вы хотите видеть только одно окно, вы можете скрыть MainWindow, вызвав его метод hide(). Если вы хотите показать оба одновременно, вы можете рассмотреть TaskDialog, а не два MainWindow.

Кроме того, как только вы закончите выполнение, вы можете явно скрыть () ваше TaskWindow, если ваш пользователь не должен закрывать его явно. Это зависит от вашего варианта использования.

person lpapp    schedule 14.01.2014
comment
Могу я спросить, почему вы должны перенести создание метода TaskWindow в метод __init__? Кажется, у меня нет проблем с созданием нового окна в методе, запускаемом сигналом. - person three_pineapples; 14.01.2014
comment
Меня не особенно интересуют соревнования по писсингу. Моя цель - просто улучшить предоставленные ответы, что вы сейчас и сделали, отредактировав свой ответ, чтобы удалить / уточнить ту часть, с которой я не согласен. Однако ваш ответ, насколько я вижу, по-прежнему предполагает, что одновременно никогда не будет открыто более двух окон (MainWindow и TaskWindow), и вместо этого предполагается, что одно дополнительное окно будет отображаться/скрываться неоднократно. Плакат может захотеть открыть 10 окон задач, насколько нам известно из минимальной предоставленной информации. - person three_pineapples; 14.01.2014
comment
Вы сказали «надо», я перефразировал «надо». Вы все равно изменили его сейчас. (единственная причина, по которой я потрудился ответить на это еще раз, заключается в том, что я не хочу, чтобы меня исказили. Если разница между должен и должен иметь для вас большое значение, то я извиняюсь.) - person three_pineapples; 14.01.2014
comment
@three_pineapples: я больше не могу понять, что вы пытаетесь донести. Чтобы каждый раз не строить (как я писал), нужно было бы переносить ее в конструктор. Что в этом плохого? - person lpapp; 14.01.2014