Reputation: 157
Ubuntu Linux 11.04 / Python 2.7 / Tkinter
I'm a novice at Python GUIs and I'm having trouble making single objects disappear and reappear. pack_forget kind of works for me, but the way I'm doing it makes all the objects blink in and out, when I only want one at a time. In the boiled-down example below, I'm trying to only make object "a" appear and then disappear and then do the same for object "b".
I would be very grateful for any help, plus some better docs on this would be cool too. The stuff I've been able to find has been light on examples.
from Tkinter import *
import time
class Box:
def __init__(self, canvas):
self.canvas = canvas
def type(self, type):
if type == "1":
self.if = self.canvas.create_rectangle(0, 0, 50, 50, fill="red")
elif type == "2":
self.if = self.canvas.create_rectangle(50, 50, 100, 100, fill="blue")
def hide(self):
self.canvas.pack_forget()
self.canvas.update_idletasks()
root.update()
def unhide(self):
self.canvas.pack()
self.canvas.update_idletasks()
root.update()
root = Tk()
frame = Frame(root)
frame.pack()
canvas = Canvas(frame, width=500, height=200)
canvas.pack()
root.update()
a = Box(canvas)
a.type("1")
b = Box(canvas)
b.type("2")
a.unhide()
time.sleep(.5)
a.hide()
time.sleep(1)
b.unhide()
time.sleep(.5)
b.hide()
time.sleep(1)
Upvotes: 0
Views: 1762
Reputation: 385970
There are many things wrong or curious about your code. For one, you should never call sleep
in a program that has an event loop. When you call that, your whole program will freeze. If you want something to happen after a fixed period of time, use the after
method to schedule a function to run in the future.
Second, there is no point in calling root.update
after calling self.canvas.update_idletasks
. For one, assume it is a rule written in stone that you should never call update
. It's OK to call update
if you know the ramifications of that, but since you are just learning and don't know, assume it's unsafe to call it. Plus, update
does the same work as update_idletasks
and more, so if you do choose to call update, calling update_idletasks
is unnecessary.
As to your real problem. You seem to be wanting to create two distinct "Box" objects, and want to hide and show them independently (?). However, both boxes are rectangles that are drawn on the same canvas. When you call pack_forget
, that affects the whole canvas so both of these objects will disappear and then reappear.
It isn't clear what your intention is. If each instance of "Box" is just a rectangle on the canvas, you don't want to use pack_forget
because that works on widgets, not canvas objects.
If you just want the rectangles to appear and disappear you have several choices. You can destroy and recreate them each time, or you can use the canvas move
or coords
method to move the item to a non-visible portion of the canvas. You could also manipulate the stacking order to raise or lower an object above or below any or all other objects.
Here's a quick example that uses the trick of moving the items outside the visible area of the canvas.
from Tkinter import *
import time
class Box:
def __init__(self, canvas, type):
self.canvas = canvas
if type == "1":
self.rect = canvas.create_rectangle(0, 0, 50, 50, fill="red")
elif type == "2":
self.rect = canvas.create_rectangle(50, 50, 100, 100, fill="blue")
self.coords = canvas.coords(canvas, self.rect)
def hide(self):
# remember where this object was
self.coords = canvas.coords(self.rect)
# move it to an invisible part of the canvas
self.canvas.move(self.rect, -1000, -1000)
def unhide(self):
# restore it to where it was
self.canvas.coords(self.rect, *self.coords)
root = Tk()
frame = Frame(root)
frame.pack()
canvas = Canvas(frame, width=500, height=200)
canvas.pack()
a = Box(canvas, type="1")
b = Box(canvas, type="2")
root.after(1000, a.hide)
root.after(2000, a.unhide)
root.after(3000, b.hide)
root.after(4000, b.unhide)
root.mainloop()
Finally, if what you really want is for an object to blink continuously, you can have the hide
method automatically call the unhide
method and visa versa:
def hide(self):
# remember where this object was
self.coords = canvas.coords(self.rect)
# move it to an invisible part of the canvas
self.canvas.move(self.rect, -1000, -1000)
# unhide after a second
self.canvas.after(1000, self.unhide)
def unhide(self):
# restore it to where it was
self.canvas.coords(self.rect, *self.coords)
# re-hide after a second
self.canvas.after(1000, self.hide)
Upvotes: 4