9

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!

vicd
  • 573
  • 4
  • 10

2 Answers2

11

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.

A. Rodas
  • 20,171
  • 8
  • 62
  • 72
  • However, I checked the fields "Tkinter.TkVersion" and "Tkinter.TclVersion", both of them are 8.5. and it seems only partially support some options refer to http://www.tcl.tk/man/tcl8.4/TkCmd/event.htm I'm sorry to hear Python doesn't support those missing options for now, I gogled that someone has filed an issue on python.org as a feature request, hopefully they will fix it http://bugs.python.org/issue3405 – vicd May 04 '13 at 03:19
  • @vicd You're welcome. There is a patch but it was posted on 2008. I've added myself to the nosy list of the issue, so if there are any news I'll let you know. – A. Rodas May 04 '13 at 10:48
  • 2
    Is it already supported in later Python versions? – SoleSoul Mar 18 '21 at 10:41
6

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.

FabienAndre
  • 4,514
  • 25
  • 38