Hi,

I have a window and open another window with a button. Then, when the other window is closed I need to update some fields in the first one. Here's what I currently do:

MainWindow:

...
        self.connect(self.actionCustomFactors, SIGNAL("triggered()"), self.OnCustomFactorsTriggered)
...
    def OnCustomFactorsTriggered(self):
        self.customWin = CustomWindow(self.factorsFile)
        self.customWin.show()
        self.connect(self.customWin, SIGNAL("destroyed()"), self.OnCustomWinClosed)

    def OnCustomWinClosed(self):
        self.cbProperty.clear()
        ...

CustomWindow:

...
        self.connect(self.actionQuit, SIGNAL("triggered()"), self.Close)
...
    def Close(self):
        self.close()
...

which obviously only works once as the CustomWindow is only closed, not destroyed. If I open it again and then close, the whole thing crashes, I guess due to some object conflicts. What I need to do is to destroy the CustomWindow and update the MainWindow stuff on CustomWindow destruction. How can I do that?

If I replace the close() method and closed() signal for destroy() and destroyed(), the whole thing crashes with access violation errors.

Thank you.

Recommended Answers

All 13 Replies

Hi,

What are you using as module for creating your windows? I am currently handling a lot of GUI elements, but I'm using PyQt. I'll explain how I do it. The app's mais window is a QMainWindow inherited class. All the windows popping from actions triggered by the user in the main window are dialog instances.

I have dialog classes, inside the slot handling the user action a dialog instance is created, after calling dialog_instance.exec_() (in my PyQt case) the dialog will run and close, and then all widgets in the dialog, which have to be attributes of the dialog class, are accessible by dialog_instance.its_widget.text() or value or...depending on what the widget is.

In PyQt there's a difference between how a dialog is made: using this exec_() means it is a modal dialog (won't allow you to touch the mainwindow until it is closed) and once closed, it's set for garbage collection. When you call only show(), it is non-modal and will be kept in the background, so you can opt for only creating once, and keep just showing it when you need it.

Plase tell me more and I could help maybe..

T

I have a main window as QMainWindow and open another window from it also as QMainWindow (as I need all the menus, toolbar and status bar in it) but it's not modal. It can be modal, but it doesn't have to be.

So are you saying that, for example, to open my other window as modal instead of

self.customWin.show()

I need to do

self.customWin.exec_()

Thank you.

No,

self.customWin.exec_()

doesn't work, it crashes.

Hi,

I haven't ever tried to launch MainWindows from MainWindows. What I explained goes for opening a dialog from a MainWindow, usually only a MainWindow has a menu. I don't know what your app is supposed to do, but it is a bit strange for me.

Maybe one other thing you could try is to have the instance of customWin have your main app window as parent (you create the instance with :

customWin = customWin_class(my_main_win)

I'm going to try something simple that looks like what you have to see how it goes.

Hope it helps,

T

I just need 2 windows with menus, toolbar and status bar and QMainWindow is the one which has them.

The problem is with destroying the 2nd window on closing it - it doesn't get destroyed with close(), but if I destroy it with destroy() it crashes, don't know why.

Here's an example I built rapidly using a sort of duplicate of a simple version of my main window. In the first one, the About action will open the secondary one, which has a toolbar and menu, and for which the About action only pops up a Message Box, and Quit will close. After the secondary one has closed, I call a del(win) which normally should erase if return from the slot hasn't.

I never said modality works for QMAinWindows, I was talking about dialogs only. And I still think that dialogs are better for secondary windows in an app there should be one main window only. Still, if your app needs it, go 4 it!

I have no errors with this, it may not match your version of PyQt so take care.

import sys

from PyQt4.QtCore import *
from PyQt4.QtGui  import *

#a secondary mainwindow class to be opened with the About slot in the main one
class win_about(QMainWindow):
    
    def __init__(self, parent=None):
        #make dialog link to its parent window, center it above and no extra taskbar entry
        super(win_about, self).__init__(parent)
        
        #Main window settings
        self.setWindowTitle("Secondary Main Win")
        
        #Create the Menu Bar
        self.menu = self.menuBar()
        
        #Create the File menu entry in the bar
        self.file_menu = self.menu.addMenu('&File')
        #Create the File entry actions
        self.file_quit = self.file_menu.addAction('&Quit')
        self.file_quit.setShortcut(QKeySequence('Ctrl+Q'))
        #self.file_quit.setIcon(QIcon('img/icon.png'))
        self.connect(self.file_quit, SIGNAL("triggered()"), self.quit)
        
        #create the help meny entry in the Bar
        self.help_menu = self.menu.addMenu('&Help')
        #Create the help menu actions
        self.help_about = self.help_menu.addAction('About')
        #self.help_about.setIcon(QIcon('img/ico_about.png'))
        self.connect(self.help_about, SIGNAL("triggered()"), self.about)
        
        #TOOLBAR--------------------------------------------------------------------------
        self.toolbar = QToolBar(self)
        self.addToolBar(self.toolbar)
        
        #add menu actions to toolbar
        self.toolbar.addAction(self.file_quit)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.help_about)
        
        
        #main widget is a 2 tab one - for user and script application modes
        self.mainWidget  = QTabWidget()
        self.setCentralWidget(self.mainWidget)

        self.tabuser = QWidget()
        
        self.u_layout = QVBoxLayout()
        
        
        self.tabuser.setLayout(self.u_layout)
        
        self.mainWidget.addTab(self.tabuser, 'User')

    def about(self):
        QMessageBox.warning(self, 'MSG TITLE', 'Secondary window')
        
    #########################################################################################
    ##@brief Slot:Application exit, accessible through menu or toolbar icon.
    #########################################################################################
    def quit(self):
        #pop up goodBye dialog
        self.close()



class main_win(QMainWindow):
    
    def __init__(self, parent=None):
        
        QMainWindow.__init__(self)
        
        #Main window settings
        self.setWindowTitle("MainApp Win")
        self.setMinimumSize(800 , 600)
        
        #Create the Menu Bar
        self.menu = self.menuBar()
        
        #Create the File menu entry in the bar
        self.file_menu = self.menu.addMenu('&File')
        #Create the File entry actions
        self.file_quit = self.file_menu.addAction('&Quit')
        self.file_quit.setShortcut(QKeySequence('Ctrl+Q'))
        #self.file_quit.setIcon(QIcon('img/icon.png'))
        self.connect(self.file_quit, SIGNAL("triggered()"), self.quit)
        
        #create the help meny entry in the Bar
        self.help_menu = self.menu.addMenu('&Help')
        #Create the help menu actions
        self.help_about = self.help_menu.addAction('About')
        #self.help_about.setIcon(QIcon('img/ico_about.png'))
        self.connect(self.help_about, SIGNAL("triggered()"), self.about)
        
        #TOOLBAR--------------------------------------------------------------------------
        self.toolbar = QToolBar(self)
        self.addToolBar(self.toolbar)
        
        #add menu actions to toolbar
        self.toolbar.addAction(self.file_quit)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.help_about)
        
        
        #main widget is a 2 tab one - for user and script application modes
        self.mainWidget  = QTabWidget()
        self.setCentralWidget(self.mainWidget)

        self.tabuser = QWidget()
        
        self.u_layout = QVBoxLayout()
        
        
        self.tabuser.setLayout(self.u_layout)
        
        self.mainWidget.addTab(self.tabuser, 'User')


    #########################################################################################
    ##@brief Slot:About user action - pop application information dialog.
    #########################################################################################
    def about(self):
        #create the dialog
        win = win_about(self)
        
        #show and execute as modal
        win.show()
        
        #to make sure it's gone, although the instance is local to the slot.
        del(win)


    #########################################################################################
    ##@brief Slot:Application exit, accessible through menu or toolbar icon.
    #########################################################################################
    def quit(self):
        #pop up goodBye dialog
        self.close()






def mymain():
    app = QtGui.QApplication(sys.argv)
    app.setApplicationName('app')
    
    form = main_win()
    form.show()
    app.exec_()



if __name__ == "__main__":
    
    mymain()

Copy+Paste in one file will do

Good Luck!

T

Oups, scratch the QtGui from QtGui. QApplication call (I imported QtGui directly)

I've tried the 'del()' like:

...
       self.connect(self.actionCustomFactors, SIGNAL("triggered()"), self.OnCustomFactorsTriggered)
      ...

      def OnCustomFactorsTriggered(self):
          self.customWin = CustomWindow(self.factorsFile)
          self.customWin.show()
          self.connect(self.customWin, SIGNAL("destroyed()"), self.OnCustomWinClosed)
          del(self.customWin)

     def OnCustomWinClosed(self):
         self.cbProperty.clear()
      ...

but it still crashes. I tried passing the parent - no difference.

Hi again,

I don't know the implications of having your customWin become an attribute of the parent window. Neither for giving it a slot after 'show()', neither of deleting an attribute.

The example I had given was much simpler, I had no exceptions, errors or crashes at all... I'm going to try and make it look like yours, but other factors in the complexity of your program may be causing this. I still have troubles not having a slot call twice for a table cell double click, so tiny problems creep up in PyQt sometimes...

So, I tried making it look like yours, there is still no exception.

BUT:
- what is this destroyed() Signal you're using? Is it you that emits it at the secondary window close? I haven't seen such a signal in the QMainWindow description, neither for its parent class QWidget.
- I still recommend a change in the app, QMainWindows are really meant to be alone and other types of widgets pop around them like I said for dialogs.

- What is the error you get when it crashes?

Sorry for long silence, I gave up first but I couldn't rest, it still bugs me.

I'll try to explain what I'm doing.
1. I have a main windows with comboboxes filled in from an xml file
2. The main window does some calculations based on selected combobox values (the main window works perfectly)
3. The xml data should be edited from another window - I need this window to have a menu bar, a tool bar and a status bar, + to be non-modal, essentially one can do whatever they want with the xml data on their own without affecting the main window and a QMainWindow suits well for this purpose. (I could do the same with a QDialog but then I need to add much more inputs to emulate the bars functionality)
4. But when the other window is closed, all combobox values are updated from the just refreshed xml file

This all works perfectly well if the new data editing window is opened and closed once. This is because I instantiate a new window, show() it and then close() it. All fine once. But when I open another window again (if one wanted to edit the data again), it opens fine but on closing that window the whole application simply crashes without error.

I think the problem is because I close the other window with self.close() which simply closes the window but doesn't destroy it. And I update the main window on the second window closed() signal. Then when I open another window (new object) and close that there's a conflict between the first window object and the second which both try to emit the closed() signal and update the main window, so it crashes. This is my take on this.

If I change the close() to destroy() it crashes straight on closing the window with "Access violation at address 652B8AEE in module 'QtGui4.dll'. Read of address 0000000C."

So my initial question was how to destroy a window in Python? If I can properly destroy the second window and update the main one on either its destroyed() or closed() signal, I think it should work.

Is there not way to hide instead of close the window in QT? Then you could create window hidden and then only show it when needed and afterwards hide it again.

If that window have different menus and even tool bar, I would call it different application and implement it separately, then use passing of data between programs. Or I would integrate the menus together with main menus, inactivate when they are not usable and swap the form in the main window for the action, of it needs not much space, expand the main window with new frame for the activity and remove(hide) it after action is finished.

It is also possible that your secondary main window is really the main window as it seems to have much functionality and you could have the other one only as secondary windos. Looks like your first main window is open file dialog with some preview/calc added. What kind of interactive activity happens in that window and why should it be separated from editing the file?

Yes, I can hide the second window. Well, this is what actually sort of happens right now, but the window instance doesn't get destroyed. If I just hide the window, then it's a pain in one place to reset all the UI elements to their initial state every time I bring up the window again. It can be done but it looks like a lot of unnecessary code.

ALL I need is to destroy a window instance. How can I get it destroyed? In Python? I read a lot of people have the same problem so it's not just my unique peculiarity.

Are you saying there's no way to destroy the 2nd window instance? If this is the case, then I guess there's no other choice but to make it a 2nd application instead.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.