Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

[Python/Tkinter]How can I fetch the value of data which was set in function "event_generate"

I'm using Python 2.7.4 and new to Tkinter, and I'm stuck with the following code. I generated an event "test" and set the "data" option with a string, but an error occurred when retrieving it from event.

Error -> AttributeError: Event instance has no attribute 'data'

from Tkinter import *

def handle_it(event):
    # print "event handler"
    print event.data

root = Tk()
root.after(1, lambda: root.event_generate('<<test>>', data="hi there"))
root.bind('<<test>>', handle_it)
root.mainloop()

I can't find the related Python docs for this case, so I referred to the tcl document as below http://www.tcl.tk/man/tcl8.5/TkCmd/event.htm#M14

Does TKinter of Python 2.7 support "data" option? Thanks!

like image 529
vicd Avatar asked May 04 '13 02:05

vicd


2 Answers

No, unfortunately it doesn't. The Tcl interpreter recognizes it as a valid option, but it is one of the missing options that are not included in the Event class, like warp. You can take a look at the line 1188 of the Tkinter source code to see the rest of the missing options.

like image 138
A. Rodas Avatar answered Sep 22 '22 10:09

A. Rodas


Tkinter does not handle properly the data field of event_generate.

Here is a snippet using private API of Tkinter (in fact Tcl...) that allows to read this field. This function only works with literals and I usually pass data a dictionary with literals.

from Tkinter import *

def handle_it(event):
    # print "event handler"
    print event.data

def bind_event_data(widget, sequence, func, add = None):
    def _substitute(*args):
        e = lambda: None #simplest object with __dict__
        e.data = eval(args[0])
        e.widget = widget
        return (e,)

    funcid = widget._register(func, _substitute, needcleanup=1)
    cmd = '{0}if {{"[{1} %d]" == "break"}} break\n'.format('+' if add else '', funcid)
    widget.tk.call('bind', widget._w, sequence, cmd)

root = Tk()

# unfortunately, does not work with my snippet (the data argument is eval-ed)
# you can adapt it to handle raw string.
root.after(100, lambda : root.event_generate('<<test>>', data="hi there"))
# works, but definitely looks too hacky
root.after(100, lambda : root.event_generate('<<test>>', data="'hi there'"))
# the way I typically use it
root.after(100, lambda : root.event_generate('<<test>>', data={"content": "hi there"}))

#should be:
#  root.bind('<<test>>', handle_it)
bind_event_data (root, '<<test>>', handle_it)

root.mainloop()

Note: there seems to be a race condition that prevent the event to be catched with a too small delay in after.

like image 24
FabienAndre Avatar answered Sep 24 '22 10:09

FabienAndre