tkinter window geometry

Z

Zora Honey

I'm trying to get a Tkinter window to open up in the same place on my
screen that I left it the last time I quit the application. To do this,
I simply write the position to a file at "exit" and at startup, I read
the file. Simple enough, but it doesn't work. Oftentimes it's "close",
but over several iterations, the window will wander all over the screen.
In the output below, you can see that the x offset is "off" by +4 each
iteration. Until I move the window. Then x and y are off for one
iteration. Then back to just x.

Anybody know what the heck is going on here?

Thanks,
Zora

------Output-------
> python alarmsend.py
in= +12+795
before=, 1x1+0+0
after= 200x200+16+795
out= +16+795
> python alarmsend.py
in= +16+795
before=, 1x1+0+0
after= 200x200+20+795
out= +20+795
> python alarmsend.py
in= +20+795
before=, 1x1+0+0
after= 200x200+24+795
out= +24+795

##move window##
> python alarmsend.py
in= +24+795
before=, 1x1+0+0
after= 200x200+28+795
out= +1045+856
> python alarmsend.py
in= +1045+856
before=, 1x1+0+0
after= 200x200+1049+795
out= +1049+795
> python alarmsend.py
in= +1049+795
before=, 1x1+0+0
after= 200x200+1053+795
out= +1053+795
> python alarmsend.py
in= +1053+795
before=, 1x1+0+0
after= 200x200+1057+795


-------Code--------
from Tkinter import *

if __name__=="__main__":
def die():
root.update_idletasks()
newGeometry='+%d+%d' % (root.winfo_x(), root.winfo_y())
print "out=", newGeometry
if (newGeometry!=geometryConfig):
config=open("alarm.config", 'w')
config.write(newGeometry+'\n')
sys.exit(0)

root=Tk()
try:
config=open("alarm.config")
geometryConfig=config.readline()[:-1]
config.close()
print "in=", geometryConfig
print "before=,", root.geometry(newGeometry=None)
root.geometry(newGeometry=geometryConfig)
root.update()
print "after=", root.geometry(newGeometry=None)
except :
pass

exitb=Button(root, text="Exit", command=die)
exitb.pack(side=LEFT)

root.mainloop()
 
E

Eric Brunel

Zora said:
I'm trying to get a Tkinter window to open up in the same place on my
screen that I left it the last time I quit the application. To do this,
I simply write the position to a file at "exit" and at startup, I read
the file. Simple enough, but it doesn't work. Oftentimes it's "close",
but over several iterations, the window will wander all over the screen.
In the output below, you can see that the x offset is "off" by +4 each
iteration. Until I move the window. Then x and y are off for one
iteration. Then back to just x.

Anybody know what the heck is going on here?

Window geometry is handled by the window manager you're using, so knowing your
platform and your window manager would help.

Anyway:

[snip script output]
-------Code--------
from Tkinter import *

if __name__=="__main__":
def die():
root.update_idletasks()
newGeometry='+%d+%d' % (root.winfo_x(), root.winfo_y())

That's one problem: you cannot be assured that winfo_rootx() and winfo_rooty()
will actually return the same coordinates as geometry() does. AFAICT, the only
valid input for geometry() is a former output from geometry(). So I'd do
something like:

newGeometry = root.geometry()
i = newGeometry.find('+')
if i != -1:
newGeometry = newGeometry[i:]
print "out=", newGeometry
if newGeometry != geometryConfig:
...
root.quit() # Better than a sys.exit(0)

print "out=", newGeometry
if (newGeometry!=geometryConfig):
config=open("alarm.config", 'w')
config.write(newGeometry+'\n')
sys.exit(0)

root=Tk()
try:
config=open("alarm.config")
geometryConfig=config.readline()[:-1]
config.close()
print "in=", geometryConfig
print "before=,", root.geometry(newGeometry=None)

Here, you set the geometry before the root window is actually built. It may be a
problem. So I'd pack the button in the window and do an update_idletasks before
reading and setting the geometry. I don't know if it will change anything to the
behavior you get, but it may make your script more portable.
root.geometry(newGeometry=geometryConfig)
root.update()
print "after=", root.geometry(newGeometry=None)
except :
pass

Another (unrelated) problem: if the file alarm.config does not exist,
geometryConfig is never set and the die function will crash... And I won't
repeat here how much a bad habit it is to use "except:" without an exception
type... ;-)
exitb=Button(root, text="Exit", command=die)
exitb.pack(side=LEFT)

root.mainloop()

Your script with all the modifications I've described works as expected on Linux
Mandrake 8 with Python 2.1 and tcl/tk 8.3.4, with the KDE window manager.

HTH
 
Z

Zora Honey

I realized after I posted that the window manager would be important.
I'm on RedHat 7.1, KDE 3.0.

Neither the switch to getting the geometry through the geometry call or
doing an update_idletasks (which I had tried before posting) works on
their own, but together they seem to be working. Apparently I just
didn't hit on the right combination.

Now, if someone can tell me how I can get this to work on a Toplevel
without having the window manager flash the "default" geometry and then
redrawing it with my specified geometry, I would be a very happy camper.

Thanks,
Zora

P.S. To Eric Brunel--thanks for your other fixes. The "real" code does
check for a file and specify an exception--this was just a copy pared
down enough for posting :) I will take the root.quit() under
advisement. Can you explain why it is "better" than just exiting the
process?


Eric said:
Zora said:
I'm trying to get a Tkinter window to open up in the same place on my
screen that I left it the last time I quit the application. To do
this, I simply write the position to a file at "exit" and at startup,
I read the file. Simple enough, but it doesn't work. Oftentimes it's
"close", but over several iterations, the window will wander all over
the screen. In the output below, you can see that the x offset is
"off" by +4 each iteration. Until I move the window. Then x and y
are off for one iteration. Then back to just x.

Anybody know what the heck is going on here?


Window geometry is handled by the window manager you're using, so
knowing your platform and your window manager would help.

Anyway:

[snip script output]
-------Code--------
from Tkinter import *

if __name__=="__main__":
def die():
root.update_idletasks()
newGeometry='+%d+%d' % (root.winfo_x(), root.winfo_y())


That's one problem: you cannot be assured that winfo_rootx() and
winfo_rooty() will actually return the same coordinates as geometry()
does. AFAICT, the only valid input for geometry() is a former output
from geometry(). So I'd do something like:

newGeometry = root.geometry()
i = newGeometry.find('+')
if i != -1:
newGeometry = newGeometry[i:]
print "out=", newGeometry
if newGeometry != geometryConfig:
...
root.quit() # Better than a sys.exit(0)

print "out=", newGeometry
if (newGeometry!=geometryConfig):
config=open("alarm.config", 'w')
config.write(newGeometry+'\n')
sys.exit(0)

root=Tk()
try:
config=open("alarm.config")
geometryConfig=config.readline()[:-1]
config.close()
print "in=", geometryConfig
print "before=,", root.geometry(newGeometry=None)


Here, you set the geometry before the root window is actually built. It
may be a problem. So I'd pack the button in the window and do an
update_idletasks before reading and setting the geometry. I don't know
if it will change anything to the behavior you get, but it may make your
script more portable.
root.geometry(newGeometry=geometryConfig)
root.update()
print "after=", root.geometry(newGeometry=None)
except :
pass


Another (unrelated) problem: if the file alarm.config does not exist,
geometryConfig is never set and the die function will crash... And I
won't repeat here how much a bad habit it is to use "except:" without an
exception type... ;-)
exitb=Button(root, text="Exit", command=die)
exitb.pack(side=LEFT)

root.mainloop()

Your script with all the modifications I've described works as expected
on Linux Mandrake 8 with Python 2.1 and tcl/tk 8.3.4, with the KDE
window manager.

HTH
 
E

Eric Brunel

Zora said:
I realized after I posted that the window manager would be important.
I'm on RedHat 7.1, KDE 3.0.

Neither the switch to getting the geometry through the geometry call or
doing an update_idletasks (which I had tried before posting) works on
their own, but together they seem to be working. Apparently I just
didn't hit on the right combination.

Now, if someone can tell me how I can get this to work on a Toplevel
without having the window manager flash the "default" geometry and then
redrawing it with my specified geometry, I would be a very happy camper.

This will be more trouble... You can try to do a root.withdraw() just after
creating the root window and a root.deiconify() just before running the
mainloop, but it seems it messes up things a bit: if I do that, closing the
window and re-running the script opens the window a bit too low and a bit too
right. So doing many close/run in succession makes the window go slowly towards
the bottom right corner. Apparently, some window decorations from the window
manager are not taken into account by the geometry method when the window is
withdrawn. Too bad... If anybody has a solution for this, I'll be glad to hear
it too.
P.S. To Eric Brunel--thanks for your other fixes. The "real" code does
check for a file and specify an exception--this was just a copy pared
down enough for posting :) I will take the root.quit() under
advisement. Can you explain why it is "better" than just exiting the
process?

First, it certainly leaves things more cleanly on the tcl/tk level than a
"violent" sys.exit. Second, it allows you to put some clean-up code behind your
root.mainloop() call. This code will then always be executed if you do a
root.quit(); it won't if you do a sys.exit(). You can actually achieve the same
goal by putting a try/finally around your main script, but quitting the main
window is the normal way to close a Tkinter application.

HTH
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top