2016-03-14 2 views
3

Я создал небольшой проект pyqt5. Вот PrintScreen приложения во время работы:Общайтесь между двумя окнами без нарушения класса инкапсуляции

application while running

Когда пользователь нажимает на QPushButton из главного окна, появится диалоговое окно, и пользователь пишет что-то в QlineEdit. Затем, щелкая по окну QPushButton диалогового окна, диалоговое окно отправляет сигнал в главное окно и удаляется. Сигнал содержит текст, набранный пользователем.

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

  • Класс MainWindow.

  • Класс DialogWindow (я хочу создать свой собственный Dialog Class без использования ранее существующих окон Dialog).

  • Мой главный сценарий

enter image description here

У меня есть несколько вопросов:

ли это правильный способ использования сигналов для того, чтобы общаться между окнами? Я не думаю, что я нарушаю инкапсуляцию класса. Однако я не хотел бы подключить сигнал на дочерний класс, написав:

self.mySignal.connect(parent.updatelabelAnswer) 

В этой строке я использую атрибут parent - это нормально? Мне кажется, что это не очень хороший способ использовать сигналы.

Мой второй вопрос:

Правильно ли я позвонить self.deleteLater() в on_pushButton_clicked слот DialogWindow? Кажется, нет, поскольку я проверил с интерактивной оболочкой python, и объект myDialogWindow по-прежнему доступен.

+0

Проверьте свой ответ на эту тему [здесь] (http://stackoverflow.com/a/35744748/1559401). Что касается 'deleteLater()', хотя слоты можно вызывать вручную, не выделяя ни одного, это вообще не нужно и не знаю, почему вы это делаете здесь. : P Также, пожалуйста, не публикуйте ** скриншоты ** вашего кода, когда вы можете просто скопировать его здесь. Это облегчает людям работу с ним и быстрее решать вашу проблему. – rbaleksandar

+0

благодарим за ответ. Мне кажется, что я не могу использовать третий скрипт для подключения двух виджетов, потому что экземпляр диалогового окна будет создан только при нажатии на кнопку главного окна, поэтому я должен создать этот экземпляр в слоте on_pushButton_clicked , Для удаления вопроса, как я могу удалить экземпляр диалогового окна? Я вставил код, потому что у меня он был с другого компьютера: p. Но вы правы, должно быть лучшее решение – Matias

ответ

1

Как правило, родитель должен всегда который выполняет соединение с сигналом. Наличие дочернего виджета делает соединение с родителем проблематичным, поскольку оно накладывает ограничения на родителя и вызывает побочные эффекты и полностью ломается в случаях, когда родительское право собственности перегружается для дочернего виджета.

В вашем примере есть два варианта, которые я считаю «правильными». Если диалоговое окно должно быть по крайней мере несколько постоянным и не предназначено для запуска модально, тогда он должен определить сигнал, к которому подключается родительский класс. Диалог не должен удалять сам, который должен отвечать родительскому классу после получения сигнала.

MainWindow

def on_pushbutton_clicked(self): 
    if not self.dlg: 
     self.dlg = DialogWindow(self) 
     self.dlg.mySignal.connect(self.on_mySignal) 
     self.dlg.show() 

def on_mySignal(value): 
    self.dlg.mySignal.disconnect() 
    self.dlg.close() 
    self.dlg.deleteLater() 
    self.dlg = None 
    self.updateLabelAnswer(value) 

Ваш диалог, как представляется, временный диалог, который существует только для сбора информации и, вероятно, следует запустить модально. В этом случае вам даже не нужно определять какие-либо сигналы. Просто создайте класс и предоставите API, чтобы получить значение текстового поля.

DialogWindow

class DialogWindow(...) 
    ... 
    def on_pushbutton_clicked(self): 
     self.accept() 

    def getValue(self): 
     return self.lineEdit.text() 

В MainWindow

def on_pushbutton_clicked(self): 
    dlg = DialogWindow(self) 
    if dlg.exec_(): 
     value = dlg.getValue() 
+0

Спасибо, Брендан Абель, за разъяснение! Теперь я знаю, как сделать модальный диалог ввода и не модальные постоянные периферийные окна. – Matias

1

Хорошо, так что я думаю, я должен отправить ответ вместо того чтобы писать комментарии раздутые: P

О делеции Процитирую Qt documentation:

Как QWidget :: близко(), сделано () удаляет диалог, если установлен флаг Qt :: WA_DeleteOnClose. Если диалоговым окном является главный виджет приложения , приложение завершается. Если диалоговое окно закрывается последним , выдается сигнал QApplication :: lastWindowClosed().

Однако, если вы хотите обработать закрытие (и удаление) диалогового окна от вашего другого виджета, который его открывает, следует использовать слоты и сигналы. Просто подключите кнопку или что-нибудь от вашего основного виджета и ее сигнал clicked() к слоту done() вашего диалога, и вы хорошо пойдете.

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


Теперь о сигналах и слотах они имеют довольно прямолинейную семантику. Как я уже писал в комментариях, а другой answer, чтобы подключить слот к сигналу, вам нужно, чтобы он присутствовал в той же области. Если это не так, перейдите один (или оба) в место, где ситуация исправлена. В вашем случае вы должны иметь общее место для обоих. Если оба являются виджетами верхнего уровня, вам необходимо выполнить соединения внутри вашего main(). Я предпочел бы добавить диалог в качестве дополнения к вашему MainWindow класса (в качестве члена класса) и к конкретизации плюс соединения там - например, в конструкторе MainWindow:

class MainWindow(QMainWindow, Ui_MainWindow): 

    def __init__(self, parent=None): 
    super(MainWindow, self).__init__(parent) 
    self.setupUi(self) 
    self.dialog = DialogWindow(self) 

    # Connect mainwindow's signals to dialog's slots 
    # Connect dialog's signals to mainwindow's slots 
    # And even connect dialog's signals to dialog's slots 
+0

Большое спасибо rbaleksandar за ваш ответ! Я написал себе.dialog = DialogWindow (self) в init MainWindow, как вы сказали, и прямо под ним я также написал: self.dialog.getMySignal(). connect (self.updateLabelAnswer). Это хороший способ доступа к атрибуту mySignal self.dialog? Потому что я не хочу нарушать инкапсуляцию, написав непосредственно self.dialog.mySignal. Однако мое решение напоминает мне уродливое. Что касается удаления диалогового окна, я следовал вашим советам и не заботился об этом. Я просто пишу show() и hide(), как вы сказали. – Matias

+0

Вы можете подключить диалоговые сигналы из своего основного окна, так как там видно. Вы даже можете подключить сигнал диалога к слоту диалога внутри вашего главного окна. Нет ничего плохого в доступе к членам класса диалога из вашего основного класса окна. Это не ** ** C++. Модель инкапсуляции данных в Python намного более гибкая. Все, что вы определяете с помощью 'self.XXX' (без двойных подчеркиваний' __'), является общедоступным. См. [Здесь] (http://stackoverflow.com/a/1641236/1559401) для получения дополнительной информации о частных данных в классах Python. – rbaleksandar

+0

Спасибо за ваш ответ! Я хорошо понимаю, как позвонить в свое диалоговое окно. – Matias

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