0

I have a function that is supposed to build a window according to which option in a dropdown menu is selected:

def buildview():
    value = StringVar()
    options = ["one", "two", "three"]

    menu = OptionMenu(*(root, value) + tuple(options))

    ### Some window building accoring to the value selected... ###

    value.trace_variable("w", buildview)

The exception that is raised looks like this (EDIT: Entire Traceback):

Traceback (most recent call last):
  File "D:\Dropbox\PRO\infograbber\Infograbber 0.1.py", line 102, in <module>
    mainloop()
  File "C:\Python35\Python3564\lib\tkinter\__init__.py", line 405, in mainloop
    _default_root.tk.mainloop(n)
  File "C:\Python35\Python3564\lib\tkinter\__init__.py", line 1553, in __call__
    self.widget._report_exception()
AttributeError: 'StringVar' object has no attribute '_report_exception'

What exactly is causing this? Can I not have a method call back itself like this? I don't even know where to start fixing this problem, so I'd appreciate any help.

I'm using Python 3.5 64 bit, Sublime Text 2, Windows 10.

EDIT: Added a test callback function:

def test(*args):
        print("test")

and changed the above trace to

value.trace_variable("w", test)

Now the exception changed to this:

Traceback (most recent call last):
  File "C:\Python35\Python3564\lib\tkinter\__init__.py", line 1549, in __call__
    return self.func(*args)
  File "D:\Dropbox\PRO\infograbber\Infograbber 0.1.py", line 56, in buildview
    root.trace_variable("w", self.printcurrentarticle)
  File "C:\Python35\Python3564\lib\tkinter\__init__.py", line 1948, in __getattr__
    return getattr(self.tk, attr)
AttributeError: '_tkinter.tkapp' object has no attribute 'trace_variable'
gowner
  • 327
  • 1
  • 4
  • 11
  • Please post the entire Traceback – vrs Jan 05 '16 at 19:47
  • So, you've created a function named `buildview` that sets up a trace to call `buildview`? Is that _really_ your code? – Bryan Oakley Jan 05 '16 at 20:19
  • @BryanOakley Yes. It's supposed to re-run every time the value of the option menu is changed, so it made sense to me to call back on itself. – gowner Jan 05 '16 at 20:55
  • @FloKlar: each time the variable changes, you create another variable and another binding. So, you have one variable. It changes. You get notified. You create another variable. You now have two variables, each with a callback. When it changes, the callback is fired twice. Each time it creates another variable and sets another trace, so you now have four. Then eight, then sixteen, and so on. – Bryan Oakley Jan 05 '16 at 21:05

1 Answers1

1

I'm not entirely sure if this is the only problem, but it's definitely a problem. When a trace fires it passes in three arguments. The function you've defined takes no arguments. You need to pass in a reference to a function that takes at least three arguments.

You also have the problem that each time the trace fires, you are creating another variable and another trace. On the surface that seems like a bad idea, unless you really do want to create a new option menu every time an optionmenu changes.

Community
  • 1
  • 1
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Well, I seem to have totally misunderstood what the trace and trace_variable methods do. I thought they watch one single variable and call the callback function as soon as that value is changed. Is there a way of doing that with this method? – gowner Jan 05 '16 at 21:01
  • @FloKlar: you seem to understand it fine. When the variable changes, the callback is called. – Bryan Oakley Jan 05 '16 at 21:03
  • But how do I specify which variable to watch in root.trace_variable("w", buildview) ? Or does it watch all variables at all time? – gowner Jan 05 '16 at 21:06
  • @FloKlar: I'm sorry, I'm an idiot. I was thinking about something else. I'll update my answer. – Bryan Oakley Jan 05 '16 at 21:09
  • I've had another look at the documentation at effbot.org and there's actually an example where the trace is bound to a variable like var.trace("w", callback). I've also now modified my callback to call on a different function doing just some print() functions in a row for debugging purposes. (I'll add it in the original question). Unfortunately, I still get the same exception. – gowner Jan 05 '16 at 21:36
  • * a different exception. But still an exception. – gowner Jan 05 '16 at 21:40
  • @FloKlar: that's a completely different problem. Please include a _complete_ and _minimal_ program that illustrates the problem. Though, this new error ought to be self-explanatory. See http://www.stackoverflow.com/help/mcve – Bryan Oakley Jan 05 '16 at 21:42
  • You're right, the problem was completely disconnected. I managed to get it working. Thanks, though for your help! – gowner Jan 05 '16 at 21:58