Получение closeEvent при выходе из приложения - PullRequest
0 голосов
/ 12 апреля 2020

Я пытаюсь сделать небольшую python программу, которая может иметь несколько windows. Проблема в том, что я пытаюсь реализовать пункт меню для выхода из программ, закрывая сразу все windows. Я пытался использовать qApp.close() и qApp.exit(), но если они позволяют эффективно выйти из программы, нет событий закрытия, сгенерированных для все еще открытого windows, которые не позволяют мне сохранять измененные данные или не выходить из приложения. , Какова лучшая практика для этого? Я мог понять, что не могу отменить процесс выхода, но я действительно хочу предложить сохранить измененные данные.

import sys
from PyQt5.QtWidgets import *

opened_windows = set()


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.create_actions()
        opened_windows.add(self)

    def closeEvent(self, ev):
        if QMessageBox.question(self, 'Closing', 'Really close?') == QMessageBox.Yes:
            ev.accept()
            opened_windows.remove(self)
        else:
            ev.ignore()

    def create_action(self, action_callback, menu, action_name):
        action = QAction(action_name, self)
        action.triggered.connect(action_callback)
        menu.addAction(action)

    def create_actions(self):
        _file_menu = self.menuBar().addMenu('&File')
        self.create_action(self.on_new, _file_menu, '&New')
        _file_menu.addSeparator()
        self.create_action(self.on_close, _file_menu, '&Close')
        self.create_action(self.on_quit, _file_menu, '&Quit')
        self.create_action(self.on_exit, _file_menu, '&Exit')

    def on_new(self):
        win = MainWindow()
        win.show()

    def on_close(self):
        self.close()

    def on_quit(self):
        qApp.quit()

    def on_exit(self):
        qApp.exit(1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainWindow()
    win.show()
    status = app.exec()
    print(len(opened_windows), ' window(s) opened')
    print('status = ', status)
    sys.exit(status)

В настоящее время я изменяю on_close и on_exit вот так :

    def on_exit(self):
        for w in opened_windows.copy():
            w.on_close()
        if len(opened_windows) == 0:
            qApp.exit(1)

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

Ответы [ 2 ]

0 голосов
/ 13 апреля 2020

Редактировать: Интересно, как я пропустил это раньше. Есть слот QApplication :: closeAll Windows, который делает именно то, что я хочу, и пример которого является привязкой к выходу.


Есть способ предложить сохранить измененный данные о quit и exit, сигнал QCoreApplication::aboutToQuit.

Обратите внимание, что хотя в документации Qt говорится, что взаимодействие с пользователем невозможно, по крайней мере с PyQt5 я мог бы использовать QMessageBox без явных проблем.

0 голосов
/ 13 апреля 2020

Причина

Важно понимать, что приложение и главное окно связаны, но это не одно и то же. Поэтому, когда вы хотите закрыть программу, не беспокойтесь о закрытии приложения. Вместо этого закройте главное окно. Из документации QCloseEvent :

События закрытия отправляются в виджеты, которые пользователь хочет закрыть, обычно выбирая «Закрыть» в меню окна или нажав X кнопка строки заголовка. Они также отправляются, когда вы вызываете QWidget :: close () для программного закрытия виджета.

Решение

  1. Подключите сигнал triggered вашего выходного действия в close слот вашего MainWindow. В вашем случае вместо:

    self.create_action(self.on_exit, _file_menu, '&Exit')
    

    напишите:

    self.create_action(self.close, _file_menu, '&Exit').
    
  2. Определите в MainWindow сигнал closed и испустите его из вашей реализации closedEvent, например, вместо opened_windows.remove(self)

  3. В on_new подключите win.closed к self.close

Пример

Вот как я предлагаю вам изменить код для реализации предложенного решения:

import sys
from PyQt5.QtWidgets import * 

class MainWindow(QMainWindow):

    closed = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.create_actions()

    def closeEvent(self, ev):
        if QMessageBox.question(self, 'Closing', 'Really close?') == QMessageBox.Yes:
            ev.accept()
            self.closed.emit()
        else:
            ev.ignore()

    def create_action(self, action_callback, menu, action_name):
        action = QAction(action_name, self)
        action.triggered.connect(action_callback)
        menu.addAction(action)

    def create_actions(self):
        _file_menu = self.menuBar().addMenu('&File')
        self.create_action(self.on_new, _file_menu, '&New')
        _file_menu.addSeparator()
        self.create_action(self.close, _file_menu, '&Exit')

    def on_new(self):
        win = MainWindow()
        win.show()
        win.closed.connect(self.close)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainWindow()
    win.show()
    status = app.exec()
    print('status = ', status)
    sys.exit(status)
...