Solved 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)
and
mainwindow.py: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?
-
@dancaer69 said in Override closeEvent with multiple window 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.self.parent().close()
-
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.
-
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()[1] 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.