I'm having problems with a "New Window" function in PyQt4/PySide with Python 2.7. I connected a initNewWindow()
function, to create a new window, to an action and put it in a menu bar. Once a common function in desktop software. Instead of giving me a new persistent window alongside the other one the new window pops up and closes. The code I'm working on is proprietary so I created an example that does the same thing with the same error below. Is there any way to get this to work? Runs in PySide with Python 2.7. It was written in and tested in Windows.
from PySide.QtCore import QSize
from PySide.QtGui import QAction
from PySide.QtGui import QApplication
from PySide.QtGui import QLabel
from PySide.QtGui import QMainWindow
from PySide.QtGui import QMenuBar
from PySide.QtGui import QMenu
from sys import argv
def main():
application = QApplication(argv)
window = QMainWindow()
window.setWindowTitle('New Window Test')
menu = QMenuBar(window)
view = QMenu('View')
new_window = QAction('New Window', view)
new_window.triggered.connect(initNewWindow)
view.addAction(new_window)
menu.addMenu(view)
label = QLabel()
label.setMinimumSize(QSize(300,300))
window.setMenuBar(menu)
window.setCentralWidget(label)
window.show()
application.exec_()
def initNewWindow():
window = QMainWindow()
window.setWindowTitle('New Window')
window.show()
if __name__ == '__main__':
main()
When initNewWindow()
returns, the window
variable is deleted and the window's reference count drops to zero, causing the newly created C++ object to be deleted. This is why your window closes immediately.
If you want to keep it open, make sure to keep a reference around. The easiest way to do this is to make your new window a child of the calling window, and set its WA_DeleteOnClose
widget attribute (see Qt::WidgetAttribute
).
If a function creates a PyQt object that the application needs to continue using, you will have to ensure that a reference to it is kept somehow. Otherwise, it could be deleted by the Python garbage collector immediately after the function returns.
So either give the object a parent, or keep it as an attribute of some other object. (In principle, the object could also be made a global variable, but that is usually considered bad practice).
Here's a revised version of your example script that demonstrates how to fix your problem:
from PySide import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
menu = self.menuBar().addMenu(self.tr('View'))
action = menu.addAction(self.tr('New Window'))
action.triggered.connect(self.handleNewWindow)
def handleNewWindow(self):
window = QtGui.QMainWindow(self)
window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
window.setWindowTitle(self.tr('New Window'))
window.show()
# or, alternatively
# self.window = QtGui.QMainWindow()
# self.window.setWindowTitle(self.tr('New Window'))
# self.window.show()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(300, 300)
window.show()
sys.exit(app.exec_())