6

During regular intervals of my program, a block (of 3 stacked) widgets need to be added to a horizontal layout. Since the widgets within each block are important to eachother, I wish to encapsulate each stack as it's own widget (making the layout adding business much easier).

I'm having trouble getting PyQt4 to recognise my 'stack' as a widget.

I made the widget stack in Qt Designer (as form: widget) and converted it to a .py via
'pyuic4 DesignerFile.ui > ClassFile.py'.

Now I can't seem to add this 'stack' (parent widget of 3 child widgets) to the layout via .addWidget( Class ).

I tried constructing a super class of the stack class (because I need to add more functionality to the stack) but the instance of the class is either...

  • Not recognised as a widget
  • Invisible
  • defective because I've no idea on how to structure the super class.

Here's what I'm failing with at the moment (though it's about the 8th class structure I've tried):

from ClassFile import ClassCode

class Stack(ClassCode):
    def __init__(self,parent= None):
        QtGui.QWidget.__init__(self,parent)

Could somebody help me structure this or lead me to some good examples?
(I've mimicked the code in both the following sources but with no avail!!
http://lateral.netmanagers.com.ar/stories/27.html#what-you-need-to-follow-the-tutorial
http://zetcode.com/tutorials/pyqt4/customwidgets/ )

Thanks!

Specs:
python 2.7.2
PyQt4
Windows 7

2 Answers 2

5

When you compile a python module from a ui file with the default options, it will (amongst other things) generate a simple "setup" class. In outline, the setup class will look like this:

class Ui_ClassCode(object):
    def setupUi(self, ClassCode):
        ClassCode.setObjectName("ClassCode")
        # bunch of boiler-plate ui code goes here
        self.retranslateUi(ClassCode)
        QtCore.QMetaObject.connectSlotsByName(ClassCode)

    def retranslateUi(self, ClassCode):
        pass

There are a couple of issues to notice here that are relevant to the question.

Firstly, the setup class is designed to be used as a mixin rather than as a direct subclass. It's task is to "inject" ui into a host widget that is passed to the setupUI method.

Secondly, the setup class is given an ugly, unpythonic identifier that is created by prepending "Ui_" to the objectName property that was set in Designer.

Fortunately, pyuic4 provides a way to bypass these two issues. All that's required is to use the -w option when compiling the python module from the ui file:

pyuic4 -w designerfile.ui > classfile.py

This will add a wrapper class that (1) can be easily subclassed, and (2) has the class-name that you damn well gave it in Qt Designer.

The wrapper class will look something like this:

class ClassCode(QtGui.QWidget, Ui_ClassCode):
    def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
        QtGui.QWidget.__init__(self, parent, f)

        self.setupUi(self)

As you can see, it doesn't do anything special: you could easily replicate what it does in your own code. But, IMO, it does make the compiled modules much more intuitive to use.

For example:

from PyQt4 import QtGui, QtCore
from classfile import ClassCode

class Stack(ClassCode):
    def __init__(self, parent=None):
        ClassCode.__init__(self, parent)

class Window(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.stack = Stack(self)
        self.setCentralWidget(self.stack)
Sign up to request clarification or add additional context in comments.

2 Comments

Is it possible to be able to pass a string to the constructor (when instantiation the widget) to be used via the widget? Eg: x = Stack('cat')
@AntiEarth. Sure: you can design your Stack subclass in whatever way you like - just like subclassing any other Qt widget. So the signature of Stack.__init__ could be changed to e.g. __init__(self, name, parent=None).
1

First, it's more appropriate to call the parent __init__ with the use of super. That will ensure the method in the proper super class is invoked. Second, when using a class constructed with pyuic, you need to call self.setupUi(self) from your __init__ method. And lastly, you need to make sure and multiple inherit from both the proper Qt class and the pyuic generated class (which is really more of a mixin).

So, something like this:

from ClassFile import ClassCode

class Stack(QtGui.QWidget, ClassCode):
    def __init__(self,parent= None):
        super(Stack, self).__init__(parent)
        self.setupUi(self)

1 Comment

He actually should be inheriting first from the desired QWidget, and secondly from the ClassCode that was generated by pyuic

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.