Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct
Override closeEvent with multiple window instances
I'm using qt designer to create the ui files, then pyuic to create the ui .py file and another file to handle them for every ui file. Basiclly something like this:
main executable file:
#!/usr/bin/env python3 import mainwindow if __name__ == "__main__": import sys sys.exit(mainwindow.run())
mainwindow_ui.ui (created in qt designer)
mainwindow_ui.py (from pyuic)
from mainwindow_ui import Ui_MainWindow class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) .... def run(): app = QtWidgets.QApplication(sys.argv) app.setQuitOnLastWindowClosed(True) ui = MainWindow() ui.show() return app.exec()
With above I create and show the mainwindow.
In my current project(a text editor) I have a method, which creates a new window instance like this:
def new(self): self.update_title() self.ui=Notepad() self.ui.show()
Notepad is the name of mainwindow
I have also override the closeEvent to open a message dialog with save, cancel, close buttons:
def closeEvent(self, event): event.ignore() self.confirmDlg()
The buttons of confirmDlg() dialog:
if box.clickedButton() == btnS: self.save() self.parent.close() elif box.clickedButton() == btnCl: self.parent.close() elif box.clickedButton() == btnC: box.close() print("Canceled ")
The problem is that I want to close only the current Notepad instance and not all instances of notepad, when I press the button of dialog. The above code is wrong and gives the error:
self.parent.close() AttributeError: 'builtin_function_or_method' object has no attribute 'close'
So, how to access to the current Notepad instance and close it from dialog's button, and don't close all instances?
I have also override the closeEvent
In which class?
Why do you call self.parent.close()?
The mainwindow has one class with name Notepad.
The confirmDlg() is a method inside this class. It's a QMessageBox in which I just have rename the standard buttons.
About self.parent.close(), I just trying things. Because self.close() closes the dialog itself, I tried the parent because I thought(obviously wrong), that with this I will access the Notepad window instance.
@dancaer69 You did not answer the question about closeEvent. So, in which class did you override it?
Also, parent is a method. The error message already suggests that.
The closeEvent method is inside Notepad class. I use it to prevent the default behaviour when click on window' s 'X' button. I think that the class is the Ui_Notepad which is the class in notepad_ui.py file which generated from the qt designer' s notepad_ui.ui file.
dancaer69 last edited by dancaer69
After some search about this I've made some changes from info I collected from different sources. I don't fully understand them all but with these changes seems that it works.
First I changed the "new" method:
def new(self) self.update_title() self.ui=Notepad() self.ui.show() widgetList.append(self.ui)
Then I added a wigetList variable and append the opened windows in "run' and "new" methods.:
def run(): app = QtWidgets.QApplication(sys.argv) app.setQuitOnLastWindowClosed(True) ui = Notepad() if len(app.arguments())>1: filename = app.arguments() if filename!=None: fileContent = open(filename, 'r', encoding=ui.detEnc(filename)).read() ui.teEditor.setText(fileContent) ui.show() widgetList.append(ui) return app.exec()
I think that the change of "new" method made possible to close one window when press "X" button and not all.
Because I couldn't close the window from confirmDlg method, I created a variable "self.reply", and I changed the confirmDlg' s buttons if condition and the closeEvent method:
if box.clickedButton() == btnS: self.save() elif box.clickedButton() == btnCl: pass elif box.clickedButton() == btnC: self.reply="cancel" box.close() print("Canceled "))
and in closeEvent:
def closeEvent(self, event): if self.teEditor.toPlainText()!="": event.ignore() self.confirmDlg() if self.reply!="cancel": event.accept() else: event.accept() And with this I can close the window from "save" or "close" dialog's buttons only.