passing data to Tkinter call backs

N

Nick Keighley

Hi,

If this is the wrong place for Tkinter in python please direct me
elsewhere!

I'm trapping mouse clicks using

canvas.bind("<ButtonRelease-1>", mouse_clik_event)

def mouse_clik_event (event) :
stuff

What mouse_clik_event does is modify some data and trigger a redraw.
Is there any way to pass data to the callback function? Some GUIs give
you a user-data field in the event, does Tkinter?

Or am I reduced to using <spit> global data? A Singleton is just
Global Data by other means.
 
B

Bruno Desthuilliers

Nick Keighley a écrit :
Hi,

If this is the wrong place for Tkinter in python please direct me
elsewhere!

I'm trapping mouse clicks using

canvas.bind("<ButtonRelease-1>", mouse_clik_event)

def mouse_clik_event (event) :
stuff

What mouse_clik_event does is modify some data and trigger a redraw.
Is there any way to pass data to the callback function? Some GUIs give
you a user-data field in the event, does Tkinter?

Never used TkInter much, but if event is a regular Python object, you
don't need any "user-data field" - just set whatever attribute you want, ie:

Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
But I fail to see how this would solve your problem here - where would
you set this attribute ???
Or am I reduced to using <spit> global data? A Singleton is just
Global Data by other means.
.... data['foo'] = "bar"
.... print event
....
Note that data doesn't have to be global here.
 
N

Nick Keighley

Nick Keighley a crit :
I'm trapping mouse clicks using
canvas.bind("<ButtonRelease-1>", mouse_clik_event)
def mouse_clik_event (event) :
     stuff
What mouse_clik_event does is modify some data and trigger a redraw.
Is there any way to pass data to the callback function? Some GUIs give
you a user-data field in the event, does Tkinter?

Never used TkInter much, but if event is a regular Python object, you
don't need any "user-data field" - just set whatever attribute you want, ie: [...]
 >>> class Event(object): pass
...
 >>> e = Event()
 >>> e.user_data = "here are my data"
 >>> e.user_data
'here are my data'
 >>>

But I fail to see how this would solve your problem here - where would
you set this attribute ???

Those other GUIs also give you a mechanism to pass the data. Say
another parameter in the bind call
Or am I reduced to using <spit> global data? A Singleton is just
Global Data by other means.

 >>> from functools import partial
 >>> data = dict()
 >>> def handle_event(event, data):
...     data['foo'] = "bar"
...     print event
...
 >>> p = partial(handle_event, data=data)

ah! the first time I read this I didn't get this. But in the mean time
cobbled something together using lambda. Is "partial" doing the same
thing but a little more elegantly?
 >>> p(e)
<__main__.Event object at 0xb75383ec>
 >>> data
{'foo': 'bar'}
 >>>

Note that data doesn't have to be global here.

# callback for mouse click event
def mouse_clik_event (event, data) :
dosomething (event.x, event.y, data)
draw_stuff (display, data)

data = Data(6.0, 0.2, 0.3)
draw_stuff (display, data)

# snag mouse
display.canvas.bind("<ButtonRelease-1>", lambda event:
mouse_clik_event (event, mandelbrot))




--
There are known knowns; there are things we know we know.
We also know there are known unknowns; that is to say we
know there are some things we do not know. But there are
also unknown unknowns -- the ones we don't know we don't
know.
 
B

Bruno Desthuilliers

Nick Keighley a écrit :
Nick Keighley a crit :
I'm trapping mouse clicks using
canvas.bind("<ButtonRelease-1>", mouse_clik_event)
def mouse_clik_event (event) :
stuff
What mouse_clik_event does is modify some data and trigger a redraw.
Is there any way to pass data to the callback function? Some GUIs give
you a user-data field in the event, does Tkinter?
Never used TkInter much, but if event is a regular Python object, you
don't need any "user-data field" - just set whatever attribute you want, ie: [...]
class Event(object): pass ...
e = Event()
e.user_data = "here are my data"
e.user_data 'here are my data'

But I fail to see how this would solve your problem here - where would
you set this attribute ???

Those other GUIs also give you a mechanism to pass the data. Say
another parameter in the bind call

Ok, so my suggestion should work, as well as any equivalent (lambda,
closure, custom callable object etc).
from functools import partial
data = dict()
def handle_event(event, data):
... data['foo'] = "bar"
... print event
...
p = partial(handle_event, data=data)

ah! the first time I read this I didn't get this. But in the mean time
cobbled something together using lambda. Is "partial" doing the same
thing

Mostly, yes - in both cases you get a callable object that keeps a
reference on the data. You could also use a closure:

def make_handler(func, data):
def handler(event):
func(event, data)
return handler

def mouse_clik_event (event, data) :
dosomething (event.x, event.y, data)
draw_stuff (display, data)

display.canvas.bind(
"<ButtonRelease-1>",
make_handler(mouse_click_event, data)
)
but a little more elegantly?

Depending on your own definition for "elegantly"...

Note that the lambda trick you used is very idiomatic - functool.partial
being newer and probably not as used - so one could argue that the most
common way is also the most "elegant" !-)
 
N

Nick Keighley

Nick Keighley a écrit :




Nick Keighley a crit :
I'm trapping mouse clicks using
canvas.bind("<ButtonRelease-1>", mouse_clik_event)
def mouse_clik_event (event) :
     stuff
What mouse_clik_event does is modify some data and trigger a redraw.
Is there any way to pass data to the callback function? Some GUIs give
you a user-data field in the event, does Tkinter?
Never used TkInter much, but if event is a regular Python object, you
don't need any "user-data field" - just set whatever attribute you want, ie: [...]
 >>> class Event(object): pass
...
 >>> e = Event()
 >>> e.user_data = "here are my data"
 >>> e.user_data
'here are my data'
But I fail to see how this would solve your problem here - where would
you set this attribute ???
Those other GUIs also give you a mechanism to pass the data. Say
another parameter in the bind call

Ok, so my suggestion should work, as well as any equivalent (lambda,
closure, custom callable object etc).
 >>> from functools import partial
 >>> data = dict()
 >>> def handle_event(event, data):
...     data['foo'] = "bar"
...     print event
...
 >>> p = partial(handle_event, data=data)
ah! the first time I read this I didn't get this. But in the mean time
cobbled something together using lambda. Is "partial" doing the same
thing

Mostly, yes - in both cases you get a callable object that keeps a
reference on the data. You could also use a closure:

def make_handler(func, data):
    def handler(event):
        func(event, data)
    return handler

def mouse_clik_event (event, data) :
     dosomething (event.x, event.y, data)
     draw_stuff (display, data)

display.canvas.bind(
   "<ButtonRelease-1>",
    make_handler(mouse_click_event, data)
   )
but a little more elegantly?

Depending on your own definition for "elegantly"...

Note that the lambda trick you used is very idiomatic - functool.partial
being newer and probably not as used - so one could argue that the most
common way is also the most "elegant" !-)

I'm somewhat newbie at Python but I'd seen lambda elsewhere (scheme).
I like the closure trick... I'm using "Python In a Nutshell" as my
guide.
 
B

Bruno Desthuilliers

Nick Keighley a écrit :
On 9 June, 13:50, Bruno Desthuilliers <bruno. (snip)

I'm somewhat newbie at Python but I'd seen lambda elsewhere (scheme).
I like the closure trick...

Well... Python is not Scheme - specially wrt/ lambdas and closures.
While it has some restricted support for some FP idioms, Python is
definitly an OO language.

FWIW, you could implement the functool.partial class using closures /
HOF (and it's been done before), but it's easier and just more "obvious"
to take the OO route here.
 
R

rantingrick

What mouse_clik_event does is modify some data and trigger a redraw.
Is there any way to pass data to the callback function? Some GUIs give
you a user-data field in the event, does Tkinter?

I don't know "how" you're triggering redraws but you need to read this
first...

w.update()
This method forces the updating of the display. It should be used only
if you know what you're doing, since it can lead to unpredictable
behavior or looping. It should never be called from an event callback
or a function that is called from an event callback.

w.update_idletasks()
Some tasks in updating the display, such as resizing and redrawing
widgets, are called idle tasks because they are usually deferred until
the application has finished handling events and has gone back to the
main loop to wait for new events.

If you want to force the display to be updated before the application
next idles, call the w.update_idletasks() method on any widget.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top