tkinter: loading file before entering mainloop

Eric Brunel eric.brunel at nospam-pragmadev.com
Mon Mar 16 03:53:37 EDT 2009


Peter Billam wrote:
>> Peter Billam wrote:
>>   window = MainWindow(application)
>>   if (len(sys.argv) > 1) and os.path.exists(sys.argv[1]):
>>       window.loadFile(sys.argv[1])
>>   application.mainloop()
>>   File "./midimix", line 465, in loadFile
>>     space0.grid(row=grid_row,
>>      pady=round(0.5*(ymid[track_num]-ymid[track_num-1]))-50)
>>   ...
>>   _tkinter.TclError: bad pad value "-50": must be positive screen distance
>> presumably because the window doesn't have dimensions before mainloop
>> is entered.  Can I force the window to be laid out before entering
>> mainloop? Or can I invoke loadFile() after mainloop has started ?
>
> On 2009-03-14, Peter Otten <__peter__ at web.de> wrote:
>> The latter. Try
>>         application.after_idle(window.loadFile, sys.argv[1])
>
> Thank you! That almost worked :-) It opened a window (which it didn't
> do last time), and it laid out the frames and so on apparently OK,
> and even posted a "Loaded v.mid" message on the StatusBar, but then
> just drew a couple of zero-thickness lines right at the top of the
> canvas, and failed with the same message:
>   File "./midimix", line 465, in loadFile
>     space0.grid(row=grid_row,
>      pady=round(0.5*(ymid[track_num]-ymid[track_num-1]))-50)
>   File "/usr/local/lib/python3.0/tkinter/__init__.py",
>    line 1845, in grid_configure
>     + self._options(cnf, kw))
>   _tkinter.TclError: bad pad value "-50": must be positive screen distance
>
> but I say "almost" because I googled after_idle, and the very similar:
>     application.after(500, window.loadFile, sys.argv[1])
> does work, exactly as intended :-) except of course that it's a
> race condition, and will fail for very impatient people or on very
> slow machines.  On my machine it still works with 20ms, but fails
> with 10ms.  Is there one extra magic trick I need to know?

I had the same kind of problems with the latest tcl/tk version (8.5):
apparently, the interface goes idle before all widgets are completely
displayed, and tricks like these - that used to work with former tcl/tk
version - now fail...

You may have a better chance with a binding on the '<<Configure>>' virtual
event, which will trigger when your widget changes its size. You just have to
make sure it'll trigger only once, even if the user resizes the window while
your script is running... The binding should be set on the widget you query to
get its dimensions.

> I also tried invoking after_idle on the canvas widget:
>    window.canvas.after_idle(window.loadFile, sys.argv[1])
> but that fails with the same message.
> (I am using python 3.0.1 in case that's, er, relevant.)

On tcl/tk level, 'after idle' is actually a command that doesn't act on a
widget, so calling after_idle on any widget will have exactly the same
behaviour.


On a more general level, if you want to have the same script that can be
called either from a GUI or from the command line, you might want to separate
your "functional" code from the GUI aspects, meaning have a module or a set of
modules containing the part that actually does something, and doesn't know
anything about from where it is called, and another module or set of modules
for the GUI and/or the CLI, which display things nicely and call the first
part when it has to actually do something. This would avoid problems like the
one you have.

> Thanks for your help,  Regards,  Peter

HTH
 - Eric -



More information about the Python-list mailing list