Avoiding garbage collection? [Solved]



  • So I'm trying to learn Python and PyQt4 at the same time, and I've sort of hit a little dead end while trying to build a simple test application. It's simply a menubar and a toolbar that will switch the central widget between two seperate text fields. Unfortunately, no matter how I try to avoid it - they get garbage collected as soon as you switch from one to the other, and I can't seem to find a nice way to prevent it. I've tried to keep the reference to the object, but it just doesn't seem to work. I'm guessing I'm simply going about this the wrong way and that there's a better way to achieve a simple functionality like this where you temporarily hide one element while displaying another. Can you point me in a better direction, please?

    Appending the test program, that doesn't work due to garbage collection.

    maclypse

    @#!/usr/bin/python

    -- coding: utf-8 --

    import sys
    from PyQt4 import QtGui

    class Example(QtGui.QMainWindow):

    def __init__(self):
        super(Example, self).__init__()
        self.initUI()
    
    def modeA(self):
        self.setCentralWidget(self.widgetA)
    
    def modeB(self):
        self.setCentralWidget(self.widgetB)
    
    def initUI(self):
        self.widgetA = QtGui.QTextEdit()
        self.widgetB = QtGui.QTextEdit()
        self.setCentralWidget(self.widgetA)
    
        exitAction = QtGui.QAction('Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)
    
        aAction = QtGui.QAction('Mode A', self)
        aAction.setStatusTip('Go to mode A')
        aAction.triggered.connect(self.modeA)
    
        bAction = QtGui.QAction('Mode B', self)
        bAction.setStatusTip('Go to mode B')
        bAction.triggered.connect(self.modeB)
    
        self.statusBar()
    
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(aAction)
        fileMenu.addAction(bAction)
        fileMenu.addAction(exitAction)
    
        toolbar = self.addToolBar('Tools')
        toolbar.addAction(aAction)
        toolbar.addAction(bAction)
        toolbar.addAction(exitAction)
    
        self.setGeometry(300, 300, 350, 250)
        self.setWindowTitle('Main window')
        self.show()
    

    def main():

    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())
    

    if name == 'main':
    main()
    @



  • The problem is that when you call setCentralWidget, the MainWindow becomes the parent of your widget and takes over ownership. The MainWindow is now responsible for destroying the widget at an appropriate time. You could probably use setParent to reparent the widget, but a look into the documentation of that function reveals the correct solution to your problem:

    [quote]
    Warning: It is very unlikely that you will ever need this function. If you have a widget that changes its content dynamically, it is far easier to use QStackedWidget.
    [/quote]



  • Ahah! Yes, that sounds precisely like the thing I'm looking for! Thank you very much.

    I figured there was a nice and easy way to achieve the functionality without ever touching the central widget after it's been set. I just couldn't find it. :)

    maclypse



  • For future reference in case anyone ever needs this again, this is functional version of it, using QStackedWidget. A nice and simple way to hide away one element and display another. Lovely.

    maclypse

    @#!/usr/bin/python

    -- coding: utf-8 --

    import sys
    from PyQt4 import QtGui

    class Example(QtGui.QMainWindow):
    def init(self):
    super(Example, self).init()
    self.initUI()

    def modeA(self):
        self.centralWidget().setCurrentIndex(0)
    
    def modeB(self):
        self.centralWidget().setCurrentIndex(1)
    
    def initUI(self):
        exitAction = QtGui.QAction('Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)
    
        aAction = QtGui.QAction('Mode A', self)
        aAction.setStatusTip('Go to mode A')
        aAction.triggered.connect(self.modeA)
    
        bAction = QtGui.QAction('Mode B', self)
        bAction.setStatusTip('Go to mode B')
        bAction.triggered.connect(self.modeB)
    
        self.statusBar()
    
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(aAction)
        fileMenu.addAction(bAction)
        fileMenu.addAction(exitAction)
    
        toolbar = self.addToolBar('Tools')
        toolbar.addAction(aAction)
        toolbar.addAction(bAction)
        toolbar.addAction(exitAction)
    
        a = QtGui.QTextEdit()
        b = QtGui.QTextEdit()
        cent = QtGui.QStackedWidget()
        cent.insertWidget(0, a)
        cent.insertWidget(1, b)
        self.setCentralWidget(cent)
    
        self.setGeometry(300, 300, 350, 250)
        self.setWindowTitle('Main window')
        self.show()
    

    def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

    if name == 'main':
    main()@


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.