views:

207

answers:

3

Hello everyone. I have another problem with PyQT, this time I have an example that will be far more useful since it contains part of my code (defanged of course!) I have a hard time figuring out how to close the 'PROGRAM SELECT' dialog window by only using the 'LOGOUT' button. I could simply use the close button on the form, but I want to do it with the 'LOGOUT' button.

Could anyone help me solve this conundrum?

Here is some compilable code for you all to chew on.

connectionName = 'example'

class SelectProgramForm(QtGui.QDialog):   
    def __init__(self, connName, connPrivilege):
        QtGui.QWidget.__init__(self)
        self.fooA = connName
        self.fooB = connPrivilege

        self.widgetWidth = 100
        self.formWidth = self.widgetWidth + 40

    def setupUi(self, programSelectForm):
        programSelectForm.setObjectName("programSelectForm")
        programSelectForm.resize(400, self.formWidth)
        self.widget = QtGui.QWidget(programSelectForm)
        self.widget.setGeometry(QtCore.QRect(20, 20, 360, self.widgetWidth))
        self.widget.setObjectName("widget")
        self.verticalLayout = QtGui.QVBoxLayout(self.widget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.instructionLabel = QtGui.QLabel(self.widget)
        self.instructionLabel.setObjectName("instructionLabel")
        self.verticalLayout.addWidget(self.instructionLabel)
        spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem)
        self.optionsGridLayout = QtGui.QGridLayout()
        self.optionsGridLayout.setObjectName("optionsGridLayout")


        self.verticalLayout.addLayout(self.optionsGridLayout)
        spacerItemUpper = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItemUpper)
        self.horizontalLayout = QtGui.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        spacerItemLower = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItemLower)
        self.pushButtonLogout = QtGui.QPushButton(self.widget)
        self.pushButtonLogout.setObjectName("pushButtonLogout")
        self.horizontalLayout.addWidget(self.pushButtonLogout)
        self.verticalLayout.addLayout(self.horizontalLayout)

        self.connect(self.pushButtonLogout, QtCore.SIGNAL("clicked()"), self.reject)

        self.retranslateUi(programSelectForm)
        QtCore.QMetaObject.connectSlotsByName(programSelectForm)


    def retranslateUi(self, programSelectForm):
        programSelectForm.setWindowTitle(QtGui.QApplication.translate("programSelectForm", "Program Select", None, QtGui.QApplication.UnicodeUTF8))
        self.instructionLabel.setText(QtGui.QApplication.translate("programSelectForm", "Select the program that you wish to access:", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButtonLogout.setText(QtGui.QApplication.translate("programSelectForm", "Logout", None, QtGui.QApplication.UnicodeUTF8))


class LoginForm(QtGui.QDialog): 
    def __init__(self, connName):
        self.fooA = connName

    def setupUi(self, LoginForm):
        LoginForm.setObjectName("LoginForm")
        LoginForm.resize(275, 175)
        self.widget = QtGui.QWidget(LoginForm)
        self.widget.setGeometry(QtCore.QRect(10, 10, 251, 147))
        self.widget.setObjectName("widget")
        self.verticalLayout = QtGui.QVBoxLayout(self.widget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.dataInputLayout = QtGui.QHBoxLayout()
        self.dataInputLayout.setObjectName("dataInputLayout")
        self.labelVerticalLayout = QtGui.QVBoxLayout()
        self.labelVerticalLayout.setObjectName("labelVerticalLayout")
        self.userIDLabel = QtGui.QLabel(self.widget)
        self.userIDLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.userIDLabel.setObjectName("userIDLabel")
        self.labelVerticalLayout.addWidget(self.userIDLabel)
        self.passwordLabel = QtGui.QLabel(self.widget)
        self.passwordLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.passwordLabel.setObjectName("passwordLabel")
        self.labelVerticalLayout.addWidget(self.passwordLabel)
        self.dataInputLayout.addLayout(self.labelVerticalLayout)
        self.labelButtonVerticalLayout = QtGui.QVBoxLayout()
        self.labelButtonVerticalLayout.setObjectName("labelButtonVerticalLayout")
        self.userIDLineEdit = QtGui.QLineEdit(self.widget)
        self.userIDLineEdit.setObjectName("userIDLineEdit")
        self.labelButtonVerticalLayout.addWidget(self.userIDLineEdit)
        self.passwordLineEdit = QtGui.QLineEdit(self.widget)
        self.passwordLineEdit.setObjectName("passwordLineEdit")
        self.labelButtonVerticalLayout.addWidget(self.passwordLineEdit)
        self.dataInputLayout.addLayout(self.labelButtonVerticalLayout)
        self.verticalLayout.addLayout(self.dataInputLayout)
        spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem)
        self.buttonLayout = QtGui.QHBoxLayout()
        self.buttonLayout.setObjectName("buttonLayout")
        self.newUserPushButton = QtGui.QPushButton(self.widget)
        self.newUserPushButton.setObjectName("newUserPushButton")
        self.buttonLayout.addWidget(self.newUserPushButton)
        self.loginPushButton = QtGui.QPushButton(self.widget)
        self.loginPushButton.setObjectName("loginPushButton")
        self.buttonLayout.addWidget(self.loginPushButton)
        self.verticalLayout.addLayout(self.buttonLayout)

        self.retranslateUi(LoginForm)
        QtCore.QMetaObject.connectSlotsByName(LoginForm)

        QtCore.QObject.connect(self.loginPushButton, QtCore.SIGNAL("clicked()"), self.confirmUser)

    def confirmUser(self):
        programWindow = QtGui.QDialog()
        self.fooA = 'fooA'   # these are needed in real program
        self.fooB = 'fooB'   # these are needed in real program
        programDialog = SelectProgramForm(self.fooA, self.fooB)
        programDialog.setupUi(programWindow)
        programWindow.exec_()

    def retranslateUi(self, LoginForm):
        LoginForm.setWindowTitle(QtGui.QApplication.translate("LoginForm", "Login", None, QtGui.QApplication.UnicodeUTF8))
        self.userIDLabel.setText(QtGui.QApplication.translate("LoginForm", "Username:", None, QtGui.QApplication.UnicodeUTF8))
        self.passwordLabel.setText(QtGui.QApplication.translate("LoginForm", "Password:", None, QtGui.QApplication.UnicodeUTF8))
        self.newUserPushButton.setText(QtGui.QApplication.translate("LoginForm", "New User?", None, QtGui.QApplication.UnicodeUTF8))
        self.loginPushButton.setText(QtGui.QApplication.translate("LoginForm", "Log In", None, QtGui.QApplication.UnicodeUTF8))


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    window = QtGui.QDialog()
    newUser = LoginForm(connectionName)
    newUser.setupUi(window)
    window.show()
    sys.exit(app.exec_())

Here is another compilable example that shows what I am looking for. Each window is able to close. Notice that there are three levels of windows, one activated by the other, that there are no close icons (aka 'X' buttons) on the second and third windows. If only this code would work with the other code...

'''
Created on 2010-06-18

@author: dhatt
'''

import sys
from PyQt4 import QtGui, QtCore

class WindowLV3(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setWindowFlags(QtCore.Qt.CustomizeWindowHint|QtCore.Qt.WindowTitleHint|QtCore.Qt.WindowMaximizeButtonHint)
        self.setGeometry(300, 300, 120, 150)
        self.setWindowTitle('LV3')

        quit = QtGui.QPushButton('Close', self)
        quit.setGeometry(10, 10, 60, 35)

        self.connect(quit, QtCore.SIGNAL('clicked()'),
            self.reject)


class WindowLV2(QtGui.QDialog):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.Window3 = WindowLV3()

        self.setWindowFlags(QtCore.Qt.CustomizeWindowHint|QtCore.Qt.WindowTitleHint|QtCore.Qt.WindowMaximizeButtonHint)
        self.setGeometry(300, 300, 120, 150)
        self.setWindowTitle('LV2')

        self.quit = QtGui.QPushButton('Close', self)
        self.quit.setGeometry(10, 10, 60, 35)

        next = QtGui.QPushButton('Lv3', self)
        next.setGeometry(10, 50, 60, 35)

        self.connect(self.quit, QtCore.SIGNAL('clicked()'),
            self.reject)

        self.connect(next, QtCore.SIGNAL('clicked()'),
            self.nextWindow)

    def nextWindow(self):
        self.Window3.show()


class WindowLV1(QtGui.QDialog):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.Window2 = WindowLV2()

        self.setGeometry(300, 300, 120, 150)
        self.setWindowTitle('LV1')

        next = QtGui.QPushButton('Lv2', self)
        next.setGeometry(10, 50, 60, 35)

        quit = QtGui.QPushButton('Close', self)
        quit.setGeometry(10, 10, 60, 35)

        self.connect(next, QtCore.SIGNAL('clicked()'),
            self.nextWindow)

        self.connect(quit, QtCore.SIGNAL('clicked()'),
             self.reject)
        #QtGui.qApp, QtCore.SLOT('quit()'))

    def nextWindow(self):
        self.Window2.show()


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    Window1 = WindowLV1()
    Window1.show()
    sys.exit(app.exec_())

Happy hunting!

A: 

I answered your earlier question. The solution here is the same, simply replace

self.connect(self.pushButtonLogout, QtCore.SIGNAL("clicked()"), self.reject)

with

self.connect(self.pushButtonLogout, QtCore.SIGNAL("clicked()"), self.close)

This should close the dialog.

apt
I have tried that before. I tried again, and I got this error: "RuntimeError: underlying C/C++ object has been deleted" Maybe your version of PyQt is different from mine (which is why it works for you)? I am using: Python 2.6.5; C/C++ CDT Plugin 4.0; PyDev 1.5.7; Eclipse 3.5; and Qt Eclipse Integration package from Nokia. I am using Linux as my OS.
Danny Hatt
A: 

I didn't actually run the code, but from the error it seems like it is trying to access a local object.

The following code could be the issue:

def confirmUser(self):
        programWindow = QtGui.QDialog()
        self.fooA = 'fooA'   # these are needed in real program
        self.fooB = 'fooB'   # these are needed in real program
        programDialog = SelectProgramForm(self.fooA, self.fooB)
        programDialog.setupUi(programWindow)
        programWindow.exec_()

There are two possibilities here. 1) Make programWindow as an instance variable. i.e. make self.programWindow = QtGui.QDialog()

2) Ideally you should create a single instance of self.programWindow and may be just call self.programWindow.show() here. i.e. some of the code in confirmUser can be moved to the initialization method. But I didn't actually study your code in depth to say 'this is the right way' ... just try it.

apt
I apologize for not responding sooner, in actuality, I found out a solution a few days later without even reading this, so I did not try it. I'm new to this, so I don't see where you are coming from for the second possibility, but the problem did lie in that area. Thanks anyways.
Danny Hatt
A: 

Hi, I'm here again, and I managed to scratch up an answer.

I tried switching gears, and using a QWizard instead, but when even the QWizard still had some of the same issues as my dialogs had (RuntimeError: underlying C/C++ object has been deleted) , I took one more look at my code, and found this out.

I figured out a way to finally close the forms using just a dialog. Turns out the LoginForm was not setup as a QDialog properly because it is actually two objects, the window and the object iteself (Which is not a true QDialog object).

The code before:

# a QDialog inside a LoginForm object (as a QDialog class), if I close this, the 'window' QDialog object is left hanging and raises an error
window = QtGui.QDialog()
newUser = LoginForm(connectionName)
newUser.setupUi(window)
window.show() code here

The code after:

# a LoginForm object as a QDialog class.  When closed, nothing is left hanging
window = LoginForm(connectionName)
window.setupUi(window)
window.show()

Add to that the work of changing several lines in the LoginForm class itself (namely, refactoring the SetupUI method out of the LoginForm class entirely)

And add this to the class itself (the LoginForm class)

class LoginForm(QtGui.QDialog):
"""
This makes the LoginForm object subclassed from a QDialog object.
"""

def __init__(self, parent, fooA, fooB):
    super(LoginForm, self).__init__(parent)
    # Add whatever code you want afterwards

This may not be the best way, but it is the way I managed to do it, and I find my code is cleaner without all of that mess that SetupUI set up for me from QtDesigner.

Danny Hatt