Re: [pygtk] Glade XML wrapper and easy callbacks
Doug Quale wrote: Graham Ashton <[EMAIL PROTECTED]> writes: On Wed, 2004-07-28 at 16:54, Doug Quale wrote: Christian Robottom Reis <[EMAIL PROTECTED]> writes: The issue I raised was "fear of namespace conflicts" that would be introduced by this, but I think it's rather minor. I don't actually have a strong opinion whether that change would be good, bad or indifferent, so I was hoping someone smarter than me could give some good arguments one way or the other :) Smarter? Not me. But I have experienced it both ways. At work we've got a rather large app (80k lines of Python), a fair chunk of which is GUI code. We use libglade and some classes that wrap it up in a similar manner to many of the examples posted here. The basic principle is that your GUI class inherits from our own GWidget type thing, in which you write lines like this: list_store = self._widget.treeview.get_model() We had minor disagreement when we initially started with these classes as to whether that was more sensible than the aesthetically cleaner: list_store = self._treeview.get_model() We approached it conservatively and ended up with _widget everywhere. A year later I can confirm that it's a right pain in the arse. Thanks. This is valuable experience. I agree that name collisions seem like an unlikely problem. An interesting question is whether a glade controller (or widget wrapper) class should automatically provide attribute bindings for the glade widgets or if they should be specified explicitly. I think Sridhar is automatically providing bindings to the widgets. You can automatically provide the bindings by looking up the widgets in __getattr__() in the WidgetWrapper base class: class WidgetWrapper: def __init__(self, ...): ... def __getattr__(self, attr): widget = self._xml.get_widget(attr) if widget is None: raise AttributeError, attr setattr(self, attr, widget) return widget Another possibility is to make the programmer create these bindings explicitly. This could be done in __init__(): class MyController(WidgetWrapper): def __init__(self): WidgetWrapper.__init__(self, 'window1') # window1 is in glade self._treeview = self._xml.get_widget('treeview1') I use something like this: WidgetWrapper.__init__(self, 'window1', ( 'treeview1', 'entry2', 'other_names', ) ) # window1 is in glade It would bind all the widgets in the list as class attributes. It is simple but also doesn't clutter the class' __dict__. -- Regards, Jakub Piotr CÅapa ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On Thu, Aug 05, 2004 at 04:37:45PM -0500, Doug Quale wrote: > An interesting question is whether a glade controller (or widget > wrapper) class should automatically provide attribute bindings for the > glade widgets or if they should be specified explicitly. My feeling is that "it depends". For the simplest UIs, then it probably makes sense to allow grabbing widgets transparently via the widget wrapper -- you don't want the newbie to have to declare everything under the sun up there. However, for more involved interfaces, there are a couple of issues: - The documentation potential of indicating what widgets are special to your application. You have a hundred hboxes and vboxes, but that button and that entry and that label there are really the essential parts, and that's not always obvious -- you can have spacer labels, and content labels, for instance. - The potential of specifying additional special behaviour for these widgets. - The extensibility of the solution (which means adding behaviour -- even unforseen behaviour -- to existing interfaces). For instance, you might want to start validating a certain widget in the future. That's easy -- implement a validation property and tie it into the "descriptor". > Another possibility is to make the programmer create these bindings > explicitly. This could be done in __init__(): > > class MyController(WidgetWrapper): > >def __init__(self): >WidgetWrapper.__init__(self, 'window1') # window1 is in glade >self._treeview = self._xml.get_widget('treeview1') This I feel lacks syntactic sugar. In Kiwi you just need to say widgets = ["treeview1", ... ] and any GladeView attaches them for you. This doesn't need to be a class attribute (it's probably better off not being, since mutable class attributes are Bad Ideas), but it needs to be intuitive and easy to use. > How do readers of this group use widget proxies? I know the Kiwi > framework uses them extensively internally. Yep. Note that proxies need a model to be able to set their data to. All we do in that case is prefix the widget name (in the widgets list) with a colon -- that means it's "proxied". This is a fairly constrained setup and I'd be much happier if you could say Widget("entry1", proxy_for="name", validator=self.validate_name, ...) but that's a bit more wordy. Maybe we could have proxy and proxy_for: Widget("entry1", proxy=1, ...) Widget("entry1", proxy_for="name", ...) which would makes things quite easy to manage. Take care, -- Christian Robottom Reis | http://async.com.br/~kiko/ | [+55 16] 3361 2331 ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Graham Ashton <[EMAIL PROTECTED]> writes: > On Wed, 2004-07-28 at 16:54, Doug Quale wrote: > > Christian Robottom Reis <[EMAIL PROTECTED]> writes: > > > > > The issue I raised was "fear of namespace conflicts" that would be > > > introduced by this, but I think it's rather minor. > > > > I don't actually have a strong opinion whether that change would be > > good, bad or indifferent, so I was hoping someone smarter than me > > could give some good arguments one way or the other :) > > Smarter? Not me. But I have experienced it both ways. At work we've got > a rather large app (80k lines of Python), a fair chunk of which is GUI > code. We use libglade and some classes that wrap it up in a similar > manner to many of the examples posted here. The basic principle is that > your GUI class inherits from our own GWidget type thing, in which you > write lines like this: > >list_store = self._widget.treeview.get_model() > > We had minor disagreement when we initially started with these classes > as to whether that was more sensible than the aesthetically cleaner: > >list_store = self._treeview.get_model() > > We approached it conservatively and ended up with _widget everywhere. A > year later I can confirm that it's a right pain in the arse. Thanks. This is valuable experience. I agree that name collisions seem like an unlikely problem. An interesting question is whether a glade controller (or widget wrapper) class should automatically provide attribute bindings for the glade widgets or if they should be specified explicitly. I think Sridhar is automatically providing bindings to the widgets. You can automatically provide the bindings by looking up the widgets in __getattr__() in the WidgetWrapper base class: class WidgetWrapper: def __init__(self, ...): ... def __getattr__(self, attr): widget = self._xml.get_widget(attr) if widget is None: raise AttributeError, attr setattr(self, attr, widget) return widget Another possibility is to make the programmer create these bindings explicitly. This could be done in __init__(): class MyController(WidgetWrapper): def __init__(self): WidgetWrapper.__init__(self, 'window1') # window1 is in glade self._treeview = self._xml.get_widget('treeview1') or you can use a Python data descriptor class GladeWidget(object): "Data descriptor to bind glade widgets within a WidgetWrapper subclass" def __init__(self, widget_name): self.widget_name = widget_name def __get__(self, ob): return ob._xml.get_widget(self.widget_name) class MyController(WidgetWrapper): _treeview = GladeWidget('treeview1') Christian pointed out the possibility of using different data descriptors for different widget types. This provides an easy way to proxy the widgets. The proxy can decorate the widget with extra methods and attributes. It can also take extra arguments specific to the widget type to specify radio button groups or other things. _treeview = TreeViewProxy('treeview1', ...) _up = ButtonProxy('up1', ...) How do readers of this group use widget proxies? I know the Kiwi framework uses them extensively internally. ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Lorenzo Gil Sanchez <[EMAIL PROTECTED]> writes: > Talking about Gazpacho I'll share with you the way I plan to implement > signal_autoconnect in Gazpacho: > > 1. First check if there is a method named > [on|after]_widgetname__signalname and if so connect the signal > 'signalname' to the widget 'widgetname' > > 2. Then check if the glade file has any signal definition (specified in > Gazpacho signal editor) and then also connect these. > > So basically, we wouldn't need the signal editor and all connection > could be done from the source code of the user program. Why don't > removing Gazpacho signal editor?. Well I can think on at least one > scenario where it could be usefull: connecting two signals of two > different objects to the same signal handler. Good point. I haven't often needed to connect signals from different widgets to the same handler, but I've done it two ways when necessary. Either do the connection by hand in the controller __init__() method or simply delegate from one handler to the other by calling it. Sometimes connection by hand in __init__() will be necessary anyway because you want to connect to a widget that doesn't appear in the glade file. This happens a lot with textbuffers in textviews and with treeview selections. I think I remember reading a comment by Damon Chaplin that he wanted to change glade to expose these widgets but I'm not sure how that would work. Gazpacho uses a checkbox on the Editor signal page to specify signal connection using connect_after() instead of connect(). That doesn't seem to allow specifying two handlers for the same widget, one to connect and the other to connect_after. Since this is rarely needed and it's easy to do by hand I don't see the need to clutter Gazpacho's GUI to allow doing this directly. ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On Thu, 2004-08-05 at 13:09, Sridhar R wrote: > So you *manually* enter the handler name for each widget in glade > signal editor right? That's a bit inconvinient, if you want to add > another callback, say--Add callback in glade signal editor and define > the method in code. GWidget [1] automates this. Ah, I see. I hadn't gathered that bit. I can see the attraction for the automation, but it had never even occurred to me do it. Thanks. -- Graham Ashton ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
El jue, 05-08-2004 a las 16:09, Doug Quale escribió: > Christian Robottom Reis <[EMAIL PROTECTED]> writes: > > > On Thu, Aug 05, 2004 at 08:56:22AM -0500, Doug Quale wrote: > > > Like Sridhar I also find it inconvenient to have to specify signal > > > names in the glade file and then match them up in my code. I think > > > it's much easier to forget about setting the signals in the glade file > > > and simply connect them based on method names. > > > > And to be honest, I'd appreciate it if Gazpacho could offer a way to > > avoid even displaying this tab. It might be nice to have a "signal list" > > button to display signals associated with a widget, but maybe that's > > better dealt with via online docs. > Talking about Gazpacho I'll share with you the way I plan to implement signal_autoconnect in Gazpacho: 1. First check if there is a method named [on|after]_widgetname__signalname and if so connect the signal 'signalname' to the widget 'widgetname' 2. Then check if the glade file has any signal definition (specified in Gazpacho signal editor) and then also connect these. So basically, we wouldn't need the signal editor and all connection could be done from the source code of the user program. Why don't removing Gazpacho signal editor?. Well I can think on at least one scenario where it could be usefull: connecting two signals of two different objects to the same signal handler. > The signal list in gazpacho is very cool because it's nice to be able > to see all the appropriate signals in one place. The docs are good, > but it's inconvenient to have to check the entire class hierarchy. > > > Maybe Gazpacho should offer a way to browse John's reference manual in a > > hypertext thingy. Or maybe I should stop giving people ideas . > > An excellent idea. Now all we have to do is contribute some code to > do it Go for it! Seriously, I think we don't have enought signal introspection in pygtk (or even GTK) but generating xml files with that info and making Gazpacho use them should no be hard. Lorenzo > ___ > pygtk mailing list [EMAIL PROTECTED] > http://www.daa.com.au/mailman/listinfo/pygtk > Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/ ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On Thu, Aug 05, 2004 at 09:09:22AM -0500, Doug Quale wrote: > Christian Robottom Reis <[EMAIL PROTECTED]> writes: > > > On Thu, Aug 05, 2004 at 08:56:22AM -0500, Doug Quale wrote: > > > Like Sridhar I also find it inconvenient to have to specify signal > > > names in the glade file and then match them up in my code. I think > > > it's much easier to forget about setting the signals in the glade file > > > and simply connect them based on method names. > > > > And to be honest, I'd appreciate it if Gazpacho could offer a way to > > avoid even displaying this tab. It might be nice to have a "signal list" > > button to display signals associated with a widget, but maybe that's > > better dealt with via online docs. > > The signal list in gazpacho is very cool because it's nice to be able > to see all the appropriate signals in one place. The docs are good, > but it's inconvenient to have to check the entire class hierarchy. Yeah, definitely true. That's one thing GTK+ docs could deal with in a nicer way -- showing inherited characteristics. I know epydoc does this automatically and it's just so useful. Take care, -- Christian Robottom Reis | http://async.com.br/~kiko/ | [+55 16] 3361 2331 ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Christian Robottom Reis <[EMAIL PROTECTED]> writes: > On Thu, Aug 05, 2004 at 08:56:22AM -0500, Doug Quale wrote: > > Like Sridhar I also find it inconvenient to have to specify signal > > names in the glade file and then match them up in my code. I think > > it's much easier to forget about setting the signals in the glade file > > and simply connect them based on method names. > > And to be honest, I'd appreciate it if Gazpacho could offer a way to > avoid even displaying this tab. It might be nice to have a "signal list" > button to display signals associated with a widget, but maybe that's > better dealt with via online docs. The signal list in gazpacho is very cool because it's nice to be able to see all the appropriate signals in one place. The docs are good, but it's inconvenient to have to check the entire class hierarchy. > Maybe Gazpacho should offer a way to browse John's reference manual in a > hypertext thingy. Or maybe I should stop giving people ideas . An excellent idea. Now all we have to do is contribute some code to do it ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On Thu, 2004-08-05 at 06:23, Sridhar R wrote: > Graham Ashton <[EMAIL PROTECTED]> wrote: > > On Wed, 2004-08-04 at 01:40, Sridhar R wrote: > > > Graham Ashton <[EMAIL PROTECTED]> wrote: > > > > > > > If anybody wants a really simple implementation to this kind of wrapper > > > > class feel free to rip off the WidgetWrapper class hierarchy that I've > > > > knocked up here (it's tiny): > > > > > > > > http://cvs.sourceforge.net/viewcvs.py/bandsaw/bandsaw/src/bandsaw.py?view=markup > > > > > > But the signal connection part is a little bit weak. How do you > > > connect signals to some deeply nested widgets in that hierarchy? > > > > What do you mean by deeply nested? > > child of child of .. the toplevel widget. (may be wrong terminology). Thanks. I don't understand why you think it doesn't work. signal_autoconnect() does the nested widgets for you. Or am I missing the point? -- Graham Ashton ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Graham Ashton <[EMAIL PROTECTED]> wrote: > On Wed, 2004-08-04 at 01:40, Sridhar R wrote: > > Graham Ashton <[EMAIL PROTECTED]> wrote: > > > > > If anybody wants a really simple implementation to this kind of wrapper > > > class feel free to rip off the WidgetWrapper class hierarchy that I've > > > knocked up here (it's tiny): > > > > > > http://cvs.sourceforge.net/viewcvs.py/bandsaw/bandsaw/src/bandsaw.py?view=markup > > > > But the signal connection part is a little bit weak. How do you > > connect signals to some deeply nested widgets in that hierarchy? > > What do you mean by deeply nested? child of child of .. the toplevel widget. (may be wrong terminology). -- Sridhar - http://www.cs.annauniv.edu/~rsridhar Blog: http://www.livejournal.com/users/sridharinfinity ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On Wed, 2004-08-04 at 01:40, Sridhar R wrote: > Graham Ashton <[EMAIL PROTECTED]> wrote: > > > If anybody wants a really simple implementation to this kind of wrapper > > class feel free to rip off the WidgetWrapper class hierarchy that I've > > knocked up here (it's tiny): > > > > http://cvs.sourceforge.net/viewcvs.py/bandsaw/bandsaw/src/bandsaw.py?view=markup > > But the signal connection part is a little bit weak. How do you > connect signals to some deeply nested widgets in that hierarchy? What do you mean by deeply nested? -- Graham Ashton ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Graham Ashton <[EMAIL PROTECTED]> wrote: > If anybody wants a really simple implementation to this kind of wrapper > class feel free to rip off the WidgetWrapper class hierarchy that I've > knocked up here (it's tiny): > > http://cvs.sourceforge.net/viewcvs.py/bandsaw/bandsaw/src/bandsaw.py?view=markup But the signal connection part is a little bit weak. How do you connect signals to some deeply nested widgets in that hierarchy? -- Sridhar - http://www.cs.annauniv.edu/~rsridhar Blog: http://www.livejournal.com/users/sridharinfinity ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On Wed, 2004-07-28 at 16:54, Doug Quale wrote: > Christian Robottom Reis <[EMAIL PROTECTED]> writes: > > > The issue I raised was "fear of namespace conflicts" that would be > > introduced by this, but I think it's rather minor. > > I don't actually have a strong opinion whether that change would be > good, bad or indifferent, so I was hoping someone smarter than me > could give some good arguments one way or the other :) Smarter? Not me. But I have experienced it both ways. At work we've got a rather large app (80k lines of Python), a fair chunk of which is GUI code. We use libglade and some classes that wrap it up in a similar manner to many of the examples posted here. The basic principle is that your GUI class inherits from our own GWidget type thing, in which you write lines like this: list_store = self._widget.treeview.get_model() We had minor disagreement when we initially started with these classes as to whether that was more sensible than the aesthetically cleaner: list_store = self._treeview.get_model() We approached it conservatively and ended up with _widget everywhere. A year later I can confirm that it's a right pain in the arse. I don't know of a single situation where the _widget has protected us from a name space collision. You could reasonably point out that I wouldn't be likely to notice as nothing is going to go blow up in my face. Still, I attribute the lack of evidence to support _widget to the fact that we try and keep our classes fairly small and directed, and put business logic and UI control code in different classes (so there's nothing more than widgets and callbacks in the GUI code in the first place). I recently started an open soure app of my own and decided to experiment with a different style. In my own app I would do this: list_store = self.treeview.get_model() So far I'm enjoying the extra simplicity, but then my OS app is still less than 1k lines. My classes aren't coming out larger or smaller than they do at work though, and that's surely a more important issue. If anybody wants a really simple implementation to this kind of wrapper class feel free to rip off the WidgetWrapper class hierarchy that I've knocked up here (it's tiny): http://cvs.sourceforge.net/viewcvs.py/bandsaw/bandsaw/src/bandsaw.py?view=markup It's small and clean and plenty good enough for small projects. Apart from the automatic attribute access I'm a fan of being able to write multiple classes to manage different parts of a GUI that just happen to have been layed out in a single glade file. Band Saw's WidgetWrapper allows you to do this: class Window(WidgetWrapper): def __init__(self): WidgetWrapper.__init__(self, 'window1') # window1 is in glade menu = Menu(self) ... blah blah ... class Menu(WidgetWrapper): def __init__(self, window): WidgetWrapper.__init__(self, 'menu1', window) The thing to note is that the Menu is passed the window, which already has a glade.XML object within it. The Menu just re-uses the one that the Window has already made, saving you the overhead of loading the glade file twice (and saving you from having two windows pop up in the event that your top level window is visible by default). Not rocket science, but very handy. It's by no means as clever as the one we've got at work, but that's proprietary and I can't rip it off. It supports clever stuff like window stacking (i.e. transiency), object tracking (to catch memory leaks) and other nice goodies. None of it has been that hard to do. -- Graham ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Christian Robottom Reis <[EMAIL PROTECTED]> writes: > On Wed, Jul 28, 2004 at 09:27:10AM -0500, Doug Quale wrote: > > There are some things we can discuss whether they should be in pygtk. > > For instance, people have considered in the past whether widget > > properties should be attributes. That would allow properties to be > > get and set directly using attribute syntax in addition to using > > get_property() and set_property(). > > There's actually a bug open for this that was considered for the freeze > but eventually left out; IÃaki wrote the patch that is up at: > > http://bugzilla.gnome.org/show_bug.cgi?id=81879 > > jpe, Johan and I have commented on it -- maybe others should chime in > too. The issue I raised was "fear of namespace conflicts" that would be > introduced by this, but I think it's rather minor. I don't actually have a strong opinion whether that change would be good, bad or indifferent, so I was hoping someone smarter than me could give some good arguments one way or the other :) ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On Wed, Jul 28, 2004 at 09:27:10AM -0500, Doug Quale wrote: > There are some things we can discuss whether they should be in pygtk. > For instance, people have considered in the past whether widget > properties should be attributes. That would allow properties to be > get and set directly using attribute syntax in addition to using > get_property() and set_property(). There's actually a bug open for this that was considered for the freeze but eventually left out; Iñaki wrote the patch that is up at: http://bugzilla.gnome.org/show_bug.cgi?id=81879 jpe, Johan and I have commented on it -- maybe others should chime in too. The issue I raised was "fear of namespace conflicts" that would be introduced by this, but I think it's rather minor. Take care, -- Christian Robottom Reis | http://async.com.br/~kiko/ | [+55 16] 3361 2331 ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Christian Robottom Reis <[EMAIL PROTECTED]> writes: > On Wed, Jul 28, 2004 at 12:06:38PM +0530, Sridhar R wrote: > > we can make use of 'property' to do this .. > > txt = button.text > > button.text = txt Right. Python 2.2+ descriptors are the general mechanism upon which 'property' is built. One of the big reasons I hacked up the widget descriptor was that I didn't want to have to remember the correct gtk+ property to get or set for the widget value for every kind of widget. For 98% of my GUI code I really don't care if the value I'm getting or setting is a Label, an Entry, a SpinButton, etc. (This is a little lie: for labels it's nice to use pango markup so I sometimes treat them differently than the other simple widget types.) It's annoying to have to remember the widget type everywhere, and if you change a widget from an Entry to a ComboBox then you've got a bunch of fairly pointless changes to make. > > Another important thing is writting proxy widgets doesn't help if UI > > is loaded from glade XML. > > Why not? It shouldn't matter if the widget already exists or not -- just > avoid building one if it already exists. This is the importance of frameworks like kiwi. Let the framework manage the most tedious and/or difficult programming tasks. If you can get Christian to do the hard parts for you you come out ahead. > > so putting it in a line, is this discussion all about making the pygtk > > api much better and easy to use some which includes the one given > > above ? > > Probably not -- it's about raising good design ideas for high-level UI > programming so I can steal them and put them in Kiwi . Right. I don't think most of this belongs inside of pygtk but rather in frameworks built on pygtk. I hope this doesn't discourage Sridar from contributing his good ideas. I find the discussion helpful, and I think others reading this list do too. For instance, I think we can save new pygtk programmers a lot of frustration and tedium if we can get everyone to use signal autoconnection based on method names as Sridar and others have demonstrated instead of libglade-style dictionary-based autoconnection. Even so, this doesn't belong inside pygtk itself. There are some things we can discuss whether they should be in pygtk. For instance, people have considered in the past whether widget properties should be attributes. That would allow properties to be get and set directly using attribute syntax in addition to using get_property() and set_property(). ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On Wed, Jul 28, 2004 at 12:06:38PM +0530, Sridhar R wrote: > Well, writing widget classes for each GWidget class is certainly > painful for the programmers. All he can do concisely is to write > lambda functions as wrappers. This is not the application programmer's task -- it should be encapsulated in the framework. > we can make use of 'property' to do this .. > txt = button.text > button.text = txt > > Another important thing is writting proxy widgets doesn't help if UI > is loaded from glade XML. Why not? It shouldn't matter if the widget already exists or not -- just avoid building one if it already exists. > so putting it in a line, is this discussion all about making the pygtk > api much better and easy to use some which includes the one given > above ? Probably not -- it's about raising good design ideas for high-level UI programming so I can steal them and put them in Kiwi . Take care, -- Christian Robottom Reis | http://async.com.br/~kiko/ | [+55 16] 3361 2331 ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Doug Quale <[EMAIL PROTECTED]> wrote: > > There's one other possibility that I don't really understand, but I'd > like to look into it. PEAK is a Python framework for enterprise > applications (http://peak.telecommunity.com/). PEAK implements many > fascinating ideas. In particular its domain model module does > something very interesting with metaclasses and nested classes. > Applied to our area of interest it might look something like this: > > class MyApp(GWidget): > > class name(Widget.TextEntry): > > max_length = 40 > > def validate(self, ...): > # some validation code here > > # other properties for the name TextEntry widget > > class age(Widget.SpinButton): > > step = 1 > digits = 0 > lower = 1 > upper = 120 > > ... > > PEAK uses metaclasses to do extensive processing of the nested classes > so that users of instances of the object see regular looking > attributes with the same names as the nested classes. This permits > associating a lot of metadata with each attribute without using an > absurd number of keyword parameters in the descriptor constructors. > Compare this to: > > class MyApp(GWidget): > > def validate_name(self, ...): > ... > > name = Widget.TextEntry('name', max_length=40, > validate_fn=validate_name, > ...) > > age = Widget.SpinButton('age', step=1, digits=0, > lower=1, upper=120, ...) > > Well, writing widget classes for each GWidget class is certainly painful for the programmers. All he can do concisely is to write lambda functions as wrappers. But surely I'm looking for easy usage for GTK+ widgets. Instead of this txt = button.get_text() button.set_text(txt) we can make use of 'property' to do this .. txt = button.text button.text = txt Another important thing is writting proxy widgets doesn't help if UI is loaded from glade XML. so putting it in a line, is this discussion all about making the pygtk api much better and easy to use some which includes the one given above ? I have the implementation of StringValidator class that is used in validation of changeable data in widgets. Look for the python module in this snapshot http://cs.annauniv.edu/~rsridhar/pub/pythondevelop/snapshots/ (That was a quick hack, though) -- Sridhar - http://www.cs.annauniv.edu/~rsridhar Blog: http://www.livejournal.com/users/sridharinfinity ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Christian Robottom Reis <[EMAIL PROTECTED]> writes: > On Sun, Jul 25, 2004 at 01:53:08PM +0530, Sridhar R wrote: > > > def __set__(self, obj, value): > > > widget = obj[self.widget_name] > > > > > > if isinstance(widget, gtk.Label): > > > widget.set_label(str(value)) > > > elif isinstance(widget, gtk.SpinButton): > > > widget.set_value(value) > > > elif isinstance(widget, gtk.Entry): > > > widget.set_text(str(value)) > > > elif isinstance(widget, gtk.Combo): > > > widget.get_entry().set_text(value) > > > elif isinstance(widget, gtk.ToggleButton): > > > widget.set_active(value) > > > widget.set_inconsistent(value is None) > > > elif isinstance(widget, gtk.TextView): > > > buffer = widget.get_buffer() > > > buffer.set_text(value) > > > else: > > > raise ValueError, 'Unrecognized widget type %r' % (type(widget),) > > > > Introspection can be used to remove those if..else part. > > Sure, you could also have a dictionary and look up an appropriate > function to handle that widget. Maybe Doug is concerned that calling a > function every time you want to get or set a value is going to be > expensive? Using a dictionary would be a better way to write this big switch and it would be easier to maintain. I thought when Sridar recommended introspection that he might have meant code like: if hasattr(widget, 'set_label'): widget.set_label(value) elif hasattr(widget, 'set_value'): widget.set_value(value) ... This seems fine. The alternative of doing this in try ... except ... seems too painful in this case. The best plan is to take the suggestion you made in the other post and create a separate descriptor class for each widget type. That eliminates the need for the switch entirely and provides other benefits as you mentioned. When writing that ugly code I didn't consider efficiency at all. In general in GUI code I tend not to worry too much about efficiency unless I've tried it out and found it is too slow. I just used the simplest code that could possibly work, but it certainly wasn't the best. There's one other possibility that I don't really understand, but I'd like to look into it. PEAK is a Python framework for enterprise applications (http://peak.telecommunity.com/). PEAK implements many fascinating ideas. In particular its domain model module does something very interesting with metaclasses and nested classes. Applied to our area of interest it might look something like this: class MyApp(GWidget): class name(Widget.TextEntry): max_length = 40 def validate(self, ...): # some validation code here # other properties for the name TextEntry widget class age(Widget.SpinButton): step = 1 digits = 0 lower = 1 upper = 120 ... PEAK uses metaclasses to do extensive processing of the nested classes so that users of instances of the object see regular looking attributes with the same names as the nested classes. This permits associating a lot of metadata with each attribute without using an absurd number of keyword parameters in the descriptor constructors. Compare this to: class MyApp(GWidget): def validate_name(self, ...): ... name = Widget.TextEntry('name', max_length=40, validate_fn=validate_name, ...) age = Widget.SpinButton('age', step=1, digits=0, lower=1, upper=120, ...) ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Christian Robottom Reis <[EMAIL PROTECTED]> writes: > On Sun, Jul 25, 2004 at 02:52:24AM -0500, Doug Quale wrote: > This is interesting, though I question the design of that > if-looks-like-a-switch-with-a-load-of-isinstances . Yes, my implementation is ugly and should be improved. It was a quick hack. > Kiwi Proxies do this by creating individualized "descriptors" -- each > widget gets its own WidgetProxy which has read() and update() methods, > and there are WidgetProxies for every widget type [for which a > descriptor would make sense]. This is used internally by the Kiwi Proxy, > but could be made generally available (and even transparently available, > as your descriptor class really is). > > So in this case you could hack around them a bit and have > > class MyController(GWidget): > name = LabelProxy('name') > age = SpinButtonProxy('name') > > Maybe the StudlyCaps isn't what you're looking for (and that's the > easiest part to change), but this solution tends to scale nicely (and > you can add extra stuff to specific proxies, such as automatic format > and type conversion). That's a better idea than using the single descriptor class. I don't recall if I ever considered using a separate descriptor class for each widget type. Probably I never thought about it, but I certainly should have. Fortunately he amount of code I have using the ugly implementation is small enough that I can take advantage of your good advice and fix it. ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On Sun, Jul 25, 2004 at 01:53:08PM +0530, Sridhar R wrote: > > def __set__(self, obj, value): > > widget = obj[self.widget_name] > > > > if isinstance(widget, gtk.Label): > > widget.set_label(str(value)) > > elif isinstance(widget, gtk.SpinButton): > > widget.set_value(value) > > elif isinstance(widget, gtk.Entry): > > widget.set_text(str(value)) > > elif isinstance(widget, gtk.Combo): > > widget.get_entry().set_text(value) > > elif isinstance(widget, gtk.ToggleButton): > > widget.set_active(value) > > widget.set_inconsistent(value is None) > > elif isinstance(widget, gtk.TextView): > > buffer = widget.get_buffer() > > buffer.set_text(value) > > else: > > raise ValueError, 'Unrecognized widget type %r' % (type(widget),) > > Introspection can be used to remove those if..else part. Sure, you could also have a dictionary and look up an appropriate function to handle that widget. Maybe Doug is concerned that calling a function every time you want to get or set a value is going to be expensive? Take care, -- Christian Robottom Reis | http://async.com.br/~kiko/ | [+55 16] 3361 2331 ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On Sun, Jul 25, 2004 at 02:52:24AM -0500, Doug Quale wrote: > The real reason I chose dictionary syntax over attribute syntax is > that I use the widget names as attributes for another purpose. The > Python 2.2+ data descriptor facility allows using descriptors to > provide attribute syntax to get and set widget values. > > class widget(object): [snip] This is interesting, though I question the design of that if-looks-like-a-switch-with-a-load-of-isinstances . Kiwi Proxies do this by creating individualized "descriptors" -- each widget gets its own WidgetProxy which has read() and update() methods, and there are WidgetProxies for every widget type [for which a descriptor would make sense]. This is used internally by the Kiwi Proxy, but could be made generally available (and even transparently available, as your descriptor class really is). > To use this, you put something like this in your class: > > class MyController(GWidget): > > name = widget('name') # name entry > age = widget('age')# age spinbutton So in this case you could hack around them a bit and have class MyController(GWidget): name = LabelProxy('name') age = SpinButtonProxy('name') Maybe the StudlyCaps isn't what you're looking for (and that's the easiest part to change), but this solution tends to scale nicely (and you can add extra stuff to specific proxies, such as automatic format and type conversion). Take care, -- Christian Robottom Reis | http://async.com.br/~kiko/ | [+55 16] 3361 2331 ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
On 25 Jul 2004 11:19:27 -0500, Doug Quale <[EMAIL PROTECTED]> wrote: > Sridhar R <[EMAIL PROTECTED]> writes: > > > Doug Quale <[EMAIL PROTECTED]> wrote: > > > Sridhar R <[EMAIL PROTECTED]> writes: > > > > > > About class GWidget itself, I have a few thoughts. The __init__() > > > method lets the caller optionally turn off autoconnection of signals. > > > This does no harm, but are there cases in which this is useful? I > > > thought about this but decided that if you derive from a glade > > > controller class you do it because you expect the on_widget__signal() > > > methods to be connected as signal handlers. > > > > It will be useful if the some handlers need to be called before the > > on_widget__signal methods. > > > > super(.. > > connect_my_custom_first_handlers() > > self.autoconnect_signals() > > I see, that makes sense. I hadn't run into that situation myself. It > should be possible instead to override autoconnect_signals() in the > subclass > >def autoconnect_signals(self): >connect_my_custom_first_handlers() >super(...).autoconnect_signals() > > but that certainly isn't better than using a parameter to __init__. > It's probably worse because it requires overriding two methods instead > of just one. > One more way is to have another named method (say 'connect_handlers'), that will be called by base's __init__ before calling autoconnect_signals. -- Sridhar - http://www.cs.annauniv.edu/~rsridhar Blog: http://www.livejournal.com/users/sridharinfinity ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Sridhar R <[EMAIL PROTECTED]> writes: > Doug Quale <[EMAIL PROTECTED]> wrote: > > Sridhar R <[EMAIL PROTECTED]> writes: > > > > About class GWidget itself, I have a few thoughts. The __init__() > > method lets the caller optionally turn off autoconnection of signals. > > This does no harm, but are there cases in which this is useful? I > > thought about this but decided that if you derive from a glade > > controller class you do it because you expect the on_widget__signal() > > methods to be connected as signal handlers. > > It will be useful if the some handlers need to be called before the > on_widget__signal methods. > > super(.. > connect_my_custom_first_handlers() > self.autoconnect_signals() I see, that makes sense. I hadn't run into that situation myself. It should be possible instead to override autoconnect_signals() in the subclass def autoconnect_signals(self): connect_my_custom_first_handlers() super(...).autoconnect_signals() but that certainly isn't better than using a parameter to __init__. It's probably worse because it requires overriding two methods instead of just one. ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Glade XML wrapper and easy callbacks
Doug Quale <[EMAIL PROTECTED]> wrote: > Sridhar R <[EMAIL PROTECTED]> writes: > > > I have made an utility class for making the job of using glade XML > > file much easier. Can this be added to pygtk? > > > > Main class: > > http://cs.annauniv.edu/~rsridhar/pub/python/snippets/glade/gwidget.py > > > > Example (not standalone, pulled from source tree): > > http://cs.annauniv.edu/~rsridhar/pub/python/snippets/glade/gwidget-example.py > > > > Thoughts? > > About class GWidget itself, I have a few thoughts. The __init__() > method lets the caller optionally turn off autoconnection of signals. > This does no harm, but are there cases in which this is useful? I > thought about this but decided that if you derive from a glade > controller class you do it because you expect the on_widget__signal() > methods to be connected as signal handlers. It will be useful if the some handlers need to be called before the on_widget__signal methods. super(.. connect_my_custom_first_handlers() self.autoconnect_signals() > > Specifying the glade file and toplevel widget name as class attributes > is inflexible. It's also hard to overide in subclasses since you have > to completely override the __init__() method if you want to specify > the widget name dynamically. I think the glade file and toplevel > widget name should be parameters to __init__(). To override that create similar Class Variables in derived classes too. I used class variables purposedly. For each GWidget class, the GLADE_FILE attribute is supposed to be constant for *all* instances, bcoz the methods are written assuming that glade file, so the glade file can't be changed for different instances as the methods remain the same. > For the signal handler method names I prefer to use > after_widget__signal() instead of on_widget__signal__(). This is just > a matter of taste. Using 'after_' has the disadvantage of taking > another prefix in addition to 'on_', but it is more explicit. One > tiny additional advantage that we don't often think of is that the > on/after prefixes are easier to read aloud than the silent trailing > double underscore. That's probably right. Using 'after_' is more readable than suffix '__' > > Making the widgets available as attributes is a good idea. The > Pythonic way to do this is to set the attribute when it is first > accessed. Subsequent accesses won't trigger __getattr__() so you > don't need a cache: > > def __getattr__(self, attr): > new_widget = self._gladexml.get_widget(attr) > if new_widget is None: > raise AttributeError, 'Widget %r not found' % attr > setattr(self, attr, new_widget) > return new_widget > > Instead of making the widgets available as attributes, I use > __getitem__() to allow dictionary access. This again is a matter of > taste. Dictionary syntax is uglier than attribute syntax but it > avoids the chance of stepping on a name that you want to use for > another purpose. I feel dictionary acess is approriate. I though self.entry1 is much easier than self['entry'] > > The real reason I chose dictionary syntax over attribute syntax is > that I use the widget names as attributes for another purpose. The > Python 2.2+ data descriptor facility allows using descriptors to > provide attribute syntax to get and set widget values. > > class widget(object): > """A Python data descriptor that gets and sets values from widgets. > > Use inside a class that derives from Gwidget to allow getting > and setting widget values as attribute values. This works > only for widget types that have a reasonable notion of value > like gtk.Entry, gtk.SpinButton, gtk.Combo, gtk.ToggleButton, > gtk.Label and gtk.TextView. Widgets that don't have an > obvious value like gtk.TreeView are not supported. (Generally > tree views will be given their own controllers or > subcontrollers.) > """ > > def __init__(self, widget_name): > self.widget_name = widget_name > > def __get__(self, obj, objtype): > widget = obj[self.widget_name] > > if isinstance(widget, gtk.Label): > return widget.get_label() > elif isinstance(widget, gtk.SpinButton): > return widget.get_value() > elif isinstance(widget, gtk.Entry): > return widget.get_text() > elif isinstance(widget, gtk.Combo): > return widget.get_entry().get_text() > elif isinstance(widget, gtk.ToggleButton): > if widget.get_inconsistent(): > return None > else: > return widget.get_active() > elif isinstance(widget, gtk.TextView): > buf = widget.get_buffer() > start, end = buf.get_bounds() > return buf.get_text(start, end, include_hidden_chars=True) > else: > raise ValueError, 'Unrecognized widget type %r' % (typ
Re: [pygtk] Glade XML wrapper and easy callbacks
Sridhar R <[EMAIL PROTECTED]> writes: > I have made an utility class for making the job of using glade XML > file much easier. Can this be added to pygtk? > > Main class: > http://cs.annauniv.edu/~rsridhar/pub/python/snippets/glade/gwidget.py > > Example (not standalone, pulled from source tree): > http://cs.annauniv.edu/~rsridhar/pub/python/snippets/glade/gwidget-example.py > > Thoughts? This is nice. We've had good code submissions to the list recently. I can't speak for everyone, but I appreciate seeing how others solve problems and I learn a lot from their examples. I use something similar to your GWidget class. I don't know if it is the sort of thing that belongs in pygtk itself; it seems to be better suited for inclusion in frameworks like kiwi. It's small enough that it isn't too hard for users to supply it. About class GWidget itself, I have a few thoughts. The __init__() method lets the caller optionally turn off autoconnection of signals. This does no harm, but are there cases in which this is useful? I thought about this but decided that if you derive from a glade controller class you do it because you expect the on_widget__signal() methods to be connected as signal handlers. Specifying the glade file and toplevel widget name as class attributes is inflexible. It's also hard to overide in subclasses since you have to completely override the __init__() method if you want to specify the widget name dynamically. I think the glade file and toplevel widget name should be parameters to __init__(). The glade controller superclass I use takes 4 parameters in __init__() although only 2 or 3 out of the 4 are used in any individual call. The idea is that I find it useful to create subcontrollers that share a view (glade widgets) with their parent controllers. These subcontrollers don't create new widgets but just connect signals to widgets created by the parent controller. This can be useful in many cases. For example it can be used to add extra behavior to a widget, such as autocompletion for a text entry. def __init__(self, view_factory=None, view_name=None, parent=None, view=None): """Initializes a controller for a glade view. The view_factory parameter is a function that returns a glade view when given the view name. It is used to create the view named view_name. Alternatively an existing view can be passed directly using the view parameter. This allows creating subcontrollers that share a view with their parent. view_factory: factory function that creates a glade view from the view name view_name: name of the view to create unless view is given parent: parent controller (optional if view_name is given) view: gtk.glade.XML view to use for this controller if view_name is not given """ self.view = view or view_factory(view_name) ... For the signal handler method names I prefer to use after_widget__signal() instead of on_widget__signal__(). This is just a matter of taste. Using 'after_' has the disadvantage of taking another prefix in addition to 'on_', but it is more explicit. One tiny additional advantage that we don't often think of is that the on/after prefixes are easier to read aloud than the silent trailing double underscore. Making the widgets available as attributes is a good idea. The Pythonic way to do this is to set the attribute when it is first accessed. Subsequent accesses won't trigger __getattr__() so you don't need a cache: def __getattr__(self, attr): new_widget = self._gladexml.get_widget(attr) if new_widget is None: raise AttributeError, 'Widget %r not found' % attr setattr(self, attr, new_widget) return new_widget Instead of making the widgets available as attributes, I use __getitem__() to allow dictionary access. This again is a matter of taste. Dictionary syntax is uglier than attribute syntax but it avoids the chance of stepping on a name that you want to use for another purpose. The real reason I chose dictionary syntax over attribute syntax is that I use the widget names as attributes for another purpose. The Python 2.2+ data descriptor facility allows using descriptors to provide attribute syntax to get and set widget values. class widget(object): """A Python data descriptor that gets and sets values from widgets. Use inside a class that derives from Gwidget to allow getting and setting widget values as attribute values. This works only for widget types that have a reasonable notion of value like gtk.Entry, gtk.SpinButton, gtk.Combo, gtk.ToggleButton, gtk.Label and gtk.TextView. Widgets that don't have an obvious value like gtk.TreeView are not supported. (Generally tree views will be given their own controllers or subcontrollers.) """ def