PyQt5 closeEvent method
Asked Answered
A

6

11

I'm currently learning how to build an application with pyqt5 and encountered some problem with closeEvent method, overriden so user gets asked for confirmation by QMessageBox object. It seems working well with X button - event gets 'accepted' when action is confirmed and 'canceled' when cancel button is clicked. However, when I use my Quit button from dropdown File menu, no matter which button I click, program gets closed with exit code 1. Seems strange, because I use same closeEvent method in both cases.

import sys

from PyQt5.QtWidgets import QApplication, QMessageBox, QMainWindow, QAction


class window(QMainWindow):
    def __init__(self):

        super().__init__()

    def createUI(self):


        self.setGeometry(500, 300, 700, 700)

        self.setWindowTitle("window")


        quit = QAction("Quit", self)
        quit.triggered.connect(self.closeEvent)

        menubar = self.menuBar()
        fmenu = menubar.addMenu("File")
        fmenu.addAction(quit)

    def closeEvent(self, event):
        close = QMessageBox()
        close.setText("You sure?")
        close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
        close = close.exec()

        if close == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

main = QApplication(sys.argv)
window = window()
window.createUI()
window.show()
sys.exit(main.exec_())

Thanks for suggestions!

Alongside answered 16/11, 2016 at 0:25 Comment(2)
did you run it in console/terminal ? You have error message. AttributeError: 'bool' object has no attribute 'accept'Hochman
when you click button then system call your function but with different event object which doesn't have accept() and ignore() so you get error message and program ends with exit code 1.Hochman
H
10

When you click button then program calls your function but with different event object which doesn't have accept() and ignore() so you get error message and program ends with exit code 1.

You can assign self.close and program will call closeEvent() with correct event object.

quit.triggered.connect(self.close)
Hochman answered 16/11, 2016 at 0:53 Comment(1)
In my case, self.close gives AttributeError and self.closeEvent works but doesn't trigger closeEvent()Ade
I
9

The problem is accept is a method while ignore is just an attribute.
This code works for me:

def closeEvent(self, event):
            close = QtWidgets.QMessageBox.question(self,
                                         "QUIT",
                                         "Are you sure want to stop process?",
                                         QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
            if close == QtWidgets.QMessageBox.Yes:
                event.accept()
            else:
                event.ignore()
Intermezzo answered 10/4, 2019 at 5:1 Comment(1)
How can this code work for you? What does the 'self' refer to in your code? In my code 'self' refers to QMainWindow. Your code does not work for me.Infancy
E
3

I had the same problem and fixed with a type-check-hack. It might be an ugly hack, but it works (tested on macOS 10.15 with python 3.8.0 and PyQt 5.14.2).

class Gui(QtWidgets.QMainWindow):
    def __init__(self):
        super(Gui, self).__init__()
        uic.loadUi("gui.ui", self)

        # ...

        self.actionExit = self.findChild(QtWidgets.QAction, "actionExit")
        self.actionExit.triggered.connect(self.closeEvent)

        # ...

    def closeEvent(self, event):
        reply = QMessageBox.question(self, 'Quit?',
                                     'Are you sure you want to quit?',
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            if not type(event) == bool:
                event.accept()
            else:
                sys.exit()
        else:
            if not type(event) == bool:
                event.ignore()
Erne answered 3/6, 2020 at 6:50 Comment(0)
A
1

If you want to close an PyQt5 app from a menu:

  1. When menu event triggered call: self.MainWindow.close() (or what window do you want to close
  2. Add this code before sys.exit(app.exec()): self.MainWindow.closeEvent = lambda event:self.closeEvent(event)
  3. Declare def closeEvent(self,event): method when you really want to close call event.accept() (and perhaps return 1) and if you don't want to close the window call event.ignore() (not event.reject() (it's not working for me))
Athletics answered 24/2, 2022 at 20:22 Comment(0)
G
0
def exit_window(self, event):
    close = QtWidgets.QMessageBox.question(self,
                                           "QUIT?",
                                           "Are you sure want to STOP and EXIT?",
                                           QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
    if close == QtWidgets.QMessageBox.Yes:
        # event.accept()
        sys.exit()
    else:
        pass
Gyron answered 25/11, 2020 at 9:34 Comment(1)
After going through all the answers, I decided to make a simple improvement. Hope it helps someone else facing the same problem in future. Thanks to all.Gyron
I
0

you need add this line is line to CreateUi your function

QMainWindow.closeEvent = self.closeEvent
Ironsides answered 9/11, 2023 at 8:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.