tags:

views:

315

answers:

5

Hi all,

I couldn't understand the connectSlotsByName() method which is predominently used by pyuic4.. As far the class is single in a PyQt file it's ok since we can use self which will be associated with a single object throughout.. But when we try to use various classes from different files the problem and the need to use connectSlotsByName() arises.. Here's what i encountered which is weird..

I created a stacked widget..

  • I placed my first widget on it.. It has a button called "Next >".

  • On clicking next it hides the current widget and adds another widget which has the "click me" button..

The problem here is the click event for "click me" button in second is not captured.. It's a minimal example that i can give for my original problem.. Please help me..

This is file No.1..(which has the parent stacked widget and it's first page). On clicking next it adds the second page which has "clickme" button in file2..

from PyQt4 import QtCore, QtGui

import file2

class Ui_StackedWidget(QtGui.QStackedWidget):

    def __init__(self,parent=None):

        QtGui.QStackedWidget.__init__(self,parent)

        self.setObjectName("self")
        self.resize(484, 370)
        self.setWindowTitle(QtGui.QApplication.translate("self", "stacked widget", None, QtGui.QApplication.UnicodeUTF8))

        self.createWidget1()

    def createWidget1(self):

        self.page=QtGui.QWidget()
        self.page.setObjectName("widget1")


        self.pushButton=QtGui.QPushButton(self.page)        
        self.pushButton.setGeometry(QtCore.QRect(150, 230, 91, 31))
        self.pushButton.setText(QtGui.QApplication.translate("self", "Next >", None, QtGui.QApplication.UnicodeUTF8))


        self.addWidget(self.page)


        QtCore.QMetaObject.connectSlotsByName(self.page)

          QtCore.QObject.connect(self.pushButton,QtCore.SIGNAL('clicked()'),self.showWidget2)


    def showWidget2(self):

        self.page.hide()

        obj=file2.widget2()
        obj.createWidget2(self)


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    ui = Ui_StackedWidget()
    ui.show()
    sys.exit(app.exec_()) 

Here's file2

from PyQt4 import QtGui,QtCore

class widget2():

    def createWidget2(self,parent):

        self.page = QtGui.QWidget()
        self.page.setObjectName("page")

        self.parent=parent

        self.groupBox = QtGui.QGroupBox(self.page)
        self.groupBox.setGeometry(QtCore.QRect(30, 20, 421, 311))
        self.groupBox.setObjectName("groupBox")
        self.groupBox.setTitle(QtGui.QApplication.translate("self", "TestGroupBox", None, QtGui.QApplication.UnicodeUTF8))

        self.pushButton = QtGui.QPushButton(self.groupBox)
        self.pushButton.setGeometry(QtCore.QRect(150, 120, 92, 28))
        self.pushButton.setObjectName("pushButton")
        self.pushButton.setText(QtGui.QApplication.translate("self", "Click Me", None, QtGui.QApplication.UnicodeUTF8))        

        self.parent.addWidget(self.page)
        self.parent.setCurrentWidget(self.page)

        QtCore.QMetaObject.connectSlotsByName(self.page)

        QtCore.QObject.connect(self.pushButton,QtCore.SIGNAL('clicked()'),self.printMessage)


    def printMessage(self):

        print("Hai")

Though in both the widgets(i mean pages)

QtCore.QMetaObject.connectSlotsByName(self.page)

the clicked signal in second dialog isn't getting processed. Thanks in advance.. Might be a beginner question..

+2  A: 

You do not need to call connectSlotsByName(), just remove those lines.

In file2, calling QtCore.QMetaObject.connectSlotsByName(self.page) tries to do this:

QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL('clicked()'), self.on_pushButton_clicked())

That will not work for you since self.on_pushBotton_clicked() slot is not defined. I find it is easiest to create your own connections in PyQt... I recommend removing the calls to connectSlotsByName from your both classes... you do not need it.

Also, your wdiget1 class should set the name of it's pushButton (preferably something other then "pushButton" to avoid confusion with the button in widget2).

jcoon
A: 

Thanks Jcoon.. But even after removing the lines from two files and changing the pushbutton name in widget2 nothing is printed.. Can u please correct me..

from PyQt4 import QtGui,QtCore

class widget2():

    def createWidget2(self,parent):

        self.page = QtGui.QWidget()
        self.page.setObjectName("page")

        self.parent=parent

        self.groupBox = QtGui.QGroupBox(self.page)
        self.groupBox.setGeometry(QtCore.QRect(30, 20, 421, 311))
        self.groupBox.setObjectName("groupBox")
        self.groupBox.setTitle(QtGui.QApplication.translate("self", "TestGroupBox", None, QtGui.QApplication.UnicodeUTF8))

        self.pushButtoninWidget2 = QtGui.QPushButton(self.groupBox)
        self.pushButtoninWidget2.setGeometry(QtCore.QRect(150, 120, 92, 28))
        self.pushButtoninWidget2.setObjectName("pushButtoninWidget2")
        self.pushButtoninWidget2.setText(QtGui.QApplication.translate("self", "Click Me", None, QtGui.QApplication.UnicodeUTF8))        

        self.parent.addWidget(self.page)
        self.parent.setCurrentWidget(self.page)

        #QtCore.QMetaObject.connectSlotsByName(self.page)

        QtCore.QObject.connect(self.pushButtoninWidget2,QtCore.SIGNAL('clicked()'),self.printMessage)


    def printMessage(self):

        print("Hai")

Actually i tried to poat this in comment section.. but could not..

Jebagnanadas
I think I see your problem... set the parent this way: `self.page = QtGui.QWidget(parent)`. Let us know if that works
jcoon
A: 

Thank you so much jcoon for your reply.. But after a very long time banging my head against the wall i found the solution..

The problem was..

self.obj=test_reuse_stacked1.widget2()
self.obj.createWidget2(self)

instead of obj..

Jebagnanadas
+1  A: 

At first, here is the minimal working example:

from sys import argv, exit
from PyQt4 import QtCore, QtGui

class widget2(QtGui.QWidget):

    def __init__(self, args):
        self.app = MainApp(args)
        QtGui.QWidget.__init__(self)
        self.setObjectName('I')

        self._layout = QtGui.QVBoxLayout(self)
        self.setLayout(self._layout)

        self.pushButtoninWidget2 = QtGui.QPushButton(self)
        self.pushButtoninWidget2.setObjectName("pushButtoninWidget2")
        self.pushButtoninWidget2.setText('Click NOW!')
        self._layout.addWidget(self.pushButtoninWidget2)

        QtCore.QMetaObject.connectSlotsByName(self)

    @QtCore.pyqtSlot()
    def on_pushButtoninWidget2_clicked(self):
        print("Hai")

class MainApp(QtGui.QApplication):
    def __init__(self, args):
        QtGui.QApplication.__init__(self, args)

if __name__ == "__main__":
    main = widget2(argv)
    main.show()
    exit(main.app.exec_())

When you trying to connect slots by name, you must give proper names to the slots and then someone (moc, uic, or you by calling connectSlotsByName) must connect them. Proper name for such a slot is: "on_PyQtObjectName_PyQtSignalName".

Note, that, if I'd omitted @QtCore.pyqtSlot() in the example, slot would be executed once for every appropriate overload (twice in this case).

You DO need to call connectSlotsByNames directly, cause there is no moc, which do it for you when you use QT in C++, and you do not use uic and .ui file. If you want to connect slots implicitly (I'm always doing so, except slots, connected directly in .ui), you'd better use more pytonish syntaxe: button.clicked.connect(self._mySlot).

And take a look at http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#connecting-slots-by-name

Max
Thanks max.. It helps me a lot in understanding the concepts..
Jebagnanadas
+1  A: 

A better question is "Why not just use new-style signals and slots?". They're much simpler and don't require any weird naming conventions:

from sys import argv, exit
from PyQt4 import QtCore, QtGui

class MyWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)

        self._layout = QtGui.QVBoxLayout()
        self.setLayout(self._layout)

        self._button = QtGui.QPushButton()
        self._button.setText('Click NOW!')
        self._layout.addWidget(self._button)

        self._button.clicked.connect(self._printMessage)

    @QtCore.pyqtSlot()
    def _printMessage(self):
        print("Hai")

if __name__ == "__main__":
    app = QtGui.QApplication(argv)

    main = MyWidget()
    main.show()
    exit(app.exec_())
markv
Thanks for your cotribution.. 'll look into it..
Jebagnanadas