Tkinter callback arguments

Alf P. Steinbach alfps at start.no
Mon Nov 2 19:18:53 EST 2009


* Peter Otten:
> * Alf P. Steinbach wrote:
>> * Peter Otten:
>>> Every time someone has to read the code he will read, hesitate, read
>>> again, and then hopefully come to the conclusion that the code does
>>> nothing, consider not using it, or if it is not tied into a larger
>>> project removing it.
>> I don't understand what you mean.
> 
> Writing code is not fire and forget. It has to be debugged, tested, 
> maintained, and will be read quite a few times in the process. Therefore it 
> is important that you make it easy to read and understand.

No, I meant that I didn't understand why you find it hard to read and understand.


[snip]
> Couldn't
> 
> class IdButton(tkinter.Button):
>     def __init__(self, id, **kw):
>         self.id = id
>         tkinter.Button.__init__(self, **kw)
> 
> be customised as easily?

Not unless there's much more that I can learn about tkinter button 'command' 
callbacks. Which is of course possible. :-) Is it possible to pick up the 
relevant object from the handler?

But AFAIK it's not (I got no arguments supplied in the calls when I tested, 
although I don't know whether there are any options or whatever to make it 
supply an event object argument, say).

And so AFAICS with this code there's no way to get an id in the on-click 
(tkinter 'command') handler.


[snip]
>>> Example: Why do you introduce button.id_string() instead of
>>> str(button.id)?
>> Because the string representation of an id then /can/ be customized
>> independently of the id. For example, id's might be integers but for
>> string representation you might want symbolic action names (e.g., you
>> might have two or more buttons with same title but different actions, so
>> that title would be ungood to identify button). And for another example,
>> when debugging or testing you might want the string represention of an id
>> to provide more information about the button and/or its context, and then
>> id_string provides a single
>> central customization point  --  provided it's used, of course. <g>
> 
> And what about the IdEntry class?

The naming scheme doesn't hold up, but I'm pretty sure that's not what you mean?


> To me it would make more sense to 
> customize the type of the .id value.

That sounds rather complex, like introducing a command pattern or something just 
to support some debugging and testing.


[snippety]
>>>> This advantage of confidence in correctness can be realized even without
>>>> heavy reuse, because the encapsulation that's necessary for reuse, here
>>>> having the code in a class, also makes it possible with more centralized
>>>> testing.
>>> Was this sentence/paragraph produced by http://pdos.csail.mit.edu/scigen/
>>> ?
>> No. :-)  But you're right that testing isn't that much of an issue for
>> that class. If that's what you meant.
> 
> I read it twice but didn't understand it. You probably misplaced a word, but 
> I can't figure out which one.

In general, if you encapsulate functionality in a class or function definition 
or whatever, then you can move that code out to a module (or a package) and you 
can then test the module and gain some confidence in its correctness.

In contrast, if you have nearly the same code duplicated in umpteen places, 
doing just about the same but with local variations, then testing and especially 
fixing it becomes more difficult and time consuming, and doesn't give you added 
confidence about any new instances of that code pattern (with own variations).

But in this case the code to be duplicated is so small, just some glue for 
calling a handler with an id, that it's difficult to get wrong. Even though 
getting that wrong was exactly what this discussion thread started with. And so 
the possible savings in the amount of work for testing and fixing is probably 
(OK, weasel word) not that much of an issue in this case.


[snippety]
>>>
>>>>>>      def __on_tk_command( self ):
>>>>>>          if self.__specified_command != None:
>>>>>>              self.__specified_command( self )
>>>>>>          else:
>>>>>>              self.on_clicked()
>> Uh, could you expand on how that's redundant and how to make it less so?
> 
> How about
> 
> class IdButton(tkinter.Button):
>     def __init__(self, owner, id, command=None, **kwargs):
>          tkinter.Button.__init__(
>               self, owner, kwargs, command=self.on_clicked)
>          self.id = id
>          self.specified_command = command
> 
>     def on_clicked(self):
>          if self.specified_command is not None:
>               self.specified_command(self)

The only purpose I can see for on_clicked is that it can be overridden (that was 
the purpose in my code too, a central customization point). But if anyone does 
that then he or she now has to duplicate the original on_clicked() code, or else 
ditch the per button customization via a supplied command handler function. I 
feel that forced code duplication, forced redundancy, something you just have to 
remember to add in the code, for the only purpose, is ungood.


Cheers,

- Alf



More information about the Python-list mailing list