how to extend an instance of visual class: was using RADs in OO way

Alex Martelli aleaxit at yahoo.com
Fri May 23 05:50:49 EDT 2003


Serge Boiko wrote:
   ...
> I create a code for a very simple PyQt application, but usage of this
> library doesn't matter here. I used Qt Designer -- a very nice and
> powerful RAD for C++/Python. Designer generated a code that I put in the
> module called form1 (attached to the end of this message). Then I created
> a code that is called form2.py and it is shown below:
> 
> from form1 import *
> 
> class Form2(Form1):
>     def __init__(self, *args):
>         Form1.__init__(self, *args)
>         self.setCaption("Form2")
>         #self.pushButton1=MyButton(self, "pushButton2")
> 
> class MyButton(QPushButton):
>     def __init__(self, *args):
>         QPushButton.__init__(self, *args)
>         self.setText("Button2")
> 
> if __name__ == "__main__":
>     a = QApplication(sys.argv)
>     QObject.connect(a,SIGNAL("lastWindowClosed()"),a,SLOT("quit()"))
>     w = Form2()
>     a.setMainWidget(w)
>     w.show()
>     a.exec_loop()
> 
> What's going on here? I created a new class Form2 that inherits from
> class Form 1 defined in the module form1 and modify it here, changing
> the form caption. Let's imagine that one day I decided that functionality
> provided by QPushButton is not sufficient for my needs. So I create
> class MyButton derived from QPushButton that somehow modifies its
> behavior. I cannot simply add line
> 
> self.pushButton1=MyButton(self, "pushButton2")
> 
> because if do this I loose all settings of pushButton1, so I actually
> have to put this line into module form1. But this is not an especially
> good idea, because form1.py is machine generated code and all manual
> modifications will be lost when I open this code in the IDE next
> time.

You have several possible options here.  The trickypython way is to
tell module form1 that the global name QPushButton actually refers to
your class MyButton:

import qt
import form1

class Form2(form1.Form1):
   "etc etc"

class MyButton(qt.QPushButton):
   "etc etc"

# tricky part comes here
form1.QPushButton = MyButton

# end of tricky part

if __name__ == '__main__':
    " etc etc "


Not sure I would call this 'elegant', mind you -- it only works well
when EVERY pushbutton instantiated in module form1 is of class MyButton
rather than qt.QPushButton... there is no way to pick and choose out
of say a dozen pushbuttons which ones should be MyButton instances,
which ones qt.QPushButton instances, and perhaps even which ones should
be from yet other buttonesque classes.  

A more 'surgical' approach would reach specifically for those buttons
you do want to change, leaving others alone.  But that's very close to 
what you say you "cannot simply add ... because" you would "loose all
settings".  The only variation is that the buttonesque classes must
KNOW their instances are going to be used, in at least some cases,
specifically to be inserted in lieu of other plainer button instances
AND thus must be ready to (optionally) pick up all relevant settings
from the latter.  I.e., and I DO think this pattern IS rather elegant
(has some similarity to Decorator as well as the obvious differences).

I'm not quite sure which settings are "relevant" to you here, i.e.
which ones you want to pick up from the 'other button' -- as you
appear to want to override the text, it seems that only the geometry
(layout) might perhaps be relevant.  But anyway, more generally, your
code clear DOES have to know what to pick up from the other widget
you're replacing and what to override, so you might as well code that
knowledge into appropriate 'clonestate' methods of your specialized
widgets (optionally and appropriately called from their __init__).

There are of course many other approaches, such as ensuring that your
specialized widgets get onto the widget palette available to the GUI
builder tool so that the form designer can choose them if desired;-).


Alex





More information about the Python-list mailing list