Hi all,
For the life of me I cannot work out why this is occuring but whenever I try to .destroy() this widget (or its parent) my program hangs - it doesn't crash, it just stops responding so I have to force kill it.
Python 2.6.5, Windows 7 -
def generate_list(self):
-
"""
-
Clears off current list and runs through the entire contact list again,
-
makes a new 'user' object for each
-
"""
-
for each in self.contacts_made:
-
each.clear()
-
#Can't get beyond here
-
-
contacts_made = []
-
global user_count
-
user_count = 1
-
-
for user in client_flags.contacts:
-
process_user = self.create(user)
-
process_user.produce()
-
self.contacts_made.append(process_user)
-
self.update()
-
-
def create(self, user_info):
-
return self.user(self.inner_frame, user_info)
-
-
def update(self):
-
"""
-
For ensuring the the scrollbar knows the correct/current dimensions of
-
the active user list - it will shrink and expand with more and less users
-
online
-
"""
-
self.UListBox.configure(scrollregion=(0, 0, self.inner_frame.winfo_width(), self.inner_frame.winfo_height()))
-
-
class user:
-
def __init__(self, parent, user_info):
-
self.root = parent
-
self.id = user_info[0]
-
self.nick = user_info[1]
-
self.status = user_info[2]
-
-
self.container = Frame(parent, bg='white', bd=1, relief=RAISED)
-
global user_count
-
self.container.grid(row=(user_count + 1), column=0, sticky=(E,W))
-
user_count += 1 #need to go down too
-
-
def clear(self):
-
self.container.destroy() #<-Hangs here
-
#Can't get to here
-
-
def produce(self):
-
global statusGreen, statusRed, verd11
-
self.greenCircle = Label(self.container, image=statusGreen, bg="white")
-
self.redCircle = Label(self.container, image=statusRed, bg="white")
-
lNick = Label(self.container, text=self.nick, font=verd11, bg="white", anchor=W)#, font=fFont_Nick)
-
bConnect = Button(self.container, text="C", font=verd11, command=self.user_connect)#having an image would be cooler than "C"
-
-
if self.status == "AVAILABLE":
-
self.greenCircle.grid(row=0, column=0, pady=5)#, sticky=(N,S,W))
-
else:
-
self.redCircle.grid(row=0, column=0, pady=5)#, sticky=(N,S,W))
-
-
lNick.grid(row=0, column=1, sticky=(N,S,E,W), padx=(5,0), pady=5)
-
bConnect.grid(row=0, column=2, sticky=(N,S,E), pady=3)
-
-
self.container.columnconfigure(0, minsize=18, weight=0)
-
self.container.columnconfigure(1, minsize=150, weight=0)
-
self.container.columnconfigure(2, minsize=18, weight=0)
-
self.container.rowconfigure(0, minsize=34, weight=0)
-
These 'user' classes are being grided under each other as they're created (tracked by user_count). Then I want to 'refresh' the list of users; which involves destroying the old objects and making new ones.
There is something going wrong on what must be a basic level of what I've created or my understanding of widget destruction.
Does anything jump out here?
Cheers
Try calling widget.after() from your main thread to check the value of some variable that you set in the child thread. See my Clock example.
13 14949 bvdet 2,851
Expert Mod 2GB
What does method self.create() return? self.contacts_made should be a list of user instances. destroy() is a universal widget method. It should work. Without having all the code for testing, it's sometimes hard to see a problem.
Ah, my bad. Would make sense to include the create function... :)
I also added in the produce function in case that is making some odd settings.
Thanks
bvdet 2,851
Expert Mod 2GB
jinsue,
I don't see anything that sticks out, but I have no way to test the code.
You should capitalize the name of the class User. This is recommended for naming classes.
Try calling destroy() directly on the widget instead of in an instance method. This can be accomplished by inheriting from Tkinter.Frame. Example: - class User(Frame):
-
def __init__(self, parent, user_info):
-
Frame.__init__(self, parent)
Then you should be able to call destroy() directly on the instance as in: - for each in self.contacts_made:
-
each.destroy()
In my experience with Tkinter, things that you might think would work just don't work.
I'm not big on how inheritance works (never needed it), but I understand what you mean.
In adding in that line to have: -
def __init__(self, parent, user_info):
-
Frame.__init__(parent)
-
self.root = parent
-
self.id = user_info[0]
-
self.nick = user_info[1]
-
self.status = user_info[2]
-
-
self.container = Frame(parent, bg='white', bd=1, relief=RAISED)
-
global user_count
-
self.container.grid(row=(user_count + 1), column=0, sticky=(E,W))
-
user_count += 1 #need to go down too
-
When the call goes through to: -
process_user = self.create(user)
-
process_user.produce()
-
Nothing, visually occurs, so I'm not sure what its altering to cause incorrect grid'ing or some such.
On your train of thought though I tried changing self.clear() to self.container.destroy() but with no success.
In my experience with Tkinter, things that you might think would work just don't work.
I agree entirely with that >.>
bvdet 2,851
Expert Mod 2GB
When done this way: -
class User(Frame):
-
def __init__(self, parent, user_info):
-
Frame.__init__(self, parent)
the instance itself is the Frame object. There is no need in creating another Frame object assigned to self.container.
Here's a simple example of creating a Frame in this way inside a Tk window: - import Tkinter
-
from Tkconstants import *
-
import time
-
-
textFont1 = ("Arial", 16, "bold")
-
-
class Clock(Tkinter.Frame):
-
def __init__(self, master):
-
Tkinter.Frame.__init__(self, master)
-
self.pack(fill=BOTH, expand=1)
-
menubar = Tkinter.Menu()
-
master.config(menu=menubar)
-
optionsMenu = Tkinter.Menu(tearoff=0)
-
menubar.add_cascade(label="Options", menu=optionsMenu)
-
optionsMenu.add_command(label='Print', command=self.print_value)
-
optionsMenu.add_command(label='Quit', command=master.destroy)
-
-
self.clockVar = Tkinter.StringVar()
-
self.clockLabel = Tkinter.Label(self, textvariable=self.clockVar,
-
relief="raised", font=textFont1,
-
bd=3,
-
bg='#ffffff000',
-
fg="#000000fff",
-
activebackground = "#000000fff",
-
activeforeground = "#ffffff000",
-
takefocus=1,
-
padx=3,
-
pady=3)
-
self.clockLabel.pack(fill=BOTH, expand=1)
-
self.run()
-
-
def run(self):
-
timeStr = time.strftime("%A, %b %d, %Y\n%I:%M:%S %p\n%Z")
-
# 24 hour clock
-
#timeStr = time.strftime("%A, %b %d, %Y\n%X\n%Z")
-
if timeStr != self.clockVar.get():
-
self.clockVar.set(timeStr)
-
self.after(200, self.run)
-
-
def print_value(self):
-
print self.clockVar.get()
-
-
if __name__ == "__main__":
-
root = Tkinter.Tk()
-
app = Clock(root)
-
root.mainloop()
Change the command master.destroy to self.destroy and the Tk window will remain when Quit is selected but the clock frame will vanish. The Tk window is still active. There must be a way to make yours work.
Ok, I modified the appropriate sections and everything came out like normal which is good, but upon calling each.destroy() the same problem occurs - the process hangs.
At this point I think more information would be good about the specifics of what is making it choke up.
Speculation on my part is now that Tkinter's grid manager might be unhappy with destroying a frame and then the other frames could be trying to all take its place or something odd. I know when you pack and grid something in Tkinter you often get the 'impossible balance' problem where it will stall forever trying to make both managers happy. It could be something odd like that.
However; how would I go about running a more detailed trace into the .destroy() method as that may render some clues as to why it becomes unhappy.
Thanks for your input thus far bvdet.
Upon further testing I have encountered something interesting.
If in the first run of generate_list(), you build the User objects and then destroy all of anyone of them straight after, it works perfectly. The other frames push together nicely and execution continues happily. When you run it the second time (refreshing the list) and it goes through self.contacts_made to destroy anything in it, it hangs. -
def generate_list(self):
-
if self.contacts_made <> []: #Only destroy if it actually has things in it
-
for each in self.contacts_made:
-
each.destroy() #<-Fails here second time through
-
-
contacts_made = []
-
global user_count
-
user_count = 1
-
-
self.process_user1 = self.create([1, "Jane", "AVAILABLE"])
-
self.process_user1.produce()
-
self.process_user2 = self.create([2, "Bob", "AVAILABLE"])
-
self.process_user2.produce()
-
self.process_user3 = self.create([3, "Alex", "UNAVAILABLE"])
-
self.process_user3.produce()
-
self.process_user4 = self.create([4, "Tim", "AVAILABLE"])
-
self.process_user4.produce()
-
-
self.contacts_made.append(self.process_user1)
-
I think the solution is close now, but I am unsure as to the implications of this data. Please advise.
bvdet 2,851
Expert Mod 2GB
Unrelated to your problem, but this line: - if self.contacts_made <> []:
is unnecessary. When the for loop sees an empty list, it never does anything.
In addition, if you are going to compile a list of contacts, don't create all the extra variables self.process_user1, self.process_user2, and so on. Example: - userList = [[1, "Jane", "AVAILABLE"],
-
[2, "Bob", "AVAILABLE"],
-
[3, "Alex", "UNAVAILABLE"],
-
[4, "Tim", "AVAILABLE"]]
-
for user in userList:
-
new = self.create(user)
-
new.produce()
-
self.contacts_made.append(new)
Try this suggestion. Create your frame object holding the contacts and destroy the frame only. You may need another frame to hold the contacts frame to save it's place if you have other widgets on the master. Using the Clock example again: - import Tkinter
-
from Tkconstants import *
-
import time
-
-
textFont1 = ("Arial", 16, "bold")
-
-
class Clock(Tkinter.Frame):
-
def __init__(self, master):
-
self.master = master
-
menubar = Tkinter.Menu()
-
master.config(menu=menubar)
-
optionsMenu = Tkinter.Menu(tearoff=0)
-
menubar.add_cascade(label="Options", menu=optionsMenu)
-
optionsMenu.add_command(label='Print', command=self.print_value)
-
optionsMenu.add_command(label='Stop', command=self.destroy)
-
optionsMenu.add_command(label='Restart', command=self.start)
-
optionsMenu.add_command(label='Quit', command=master.destroy)
-
self.start()
-
-
def start(self):
-
Tkinter.Frame.__init__(self, self.master)
-
self.pack(fill=BOTH, expand=1)
-
self.clockVar = Tkinter.StringVar(self.master)
-
self.clockLabel = Tkinter.Label(self, textvariable=self.clockVar,
-
relief="raised", font=textFont1,
-
bd=3,
-
bg='#ffffff000',
-
fg="#000000fff",
-
activebackground = "#000000fff",
-
activeforeground = "#ffffff000",
-
takefocus=1,
-
padx=3,
-
pady=3)
-
self.clockLabel.pack(fill=BOTH, expand=1)
-
self.run()
-
-
def run(self):
-
timeStr = time.strftime("%A, %b %d, %Y\n%I:%M:%S %p\n%Z")
-
# 24 hour clock
-
#timeStr = time.strftime("%A, %b %d, %Y\n%X\n%Z")
-
if timeStr != self.clockVar.get():
-
self.clockVar.set(timeStr)
-
self.after(200, self.run)
-
-
def print_value(self):
-
print self.clockVar.get()
-
-
if __name__ == "__main__":
-
root = Tkinter.Tk()
-
app = Clock(root)
-
root.mainloop()
-
Notice the frame is destroyed when "Stop" is selected. Any widgets in that frame will also be destroyed. When "Restart" is selected, the frame and its contents are recreated.
bvdet 2,851
Expert Mod 2GB
As an afterthought, if you can't get destroy() to work, you could always try grid_forget().
Ahah! So close now. Ok I didn't mention in the OP but the secondary (and thus the call that hangs) call is run from a thread which from a quick google search shows that this is a huge no-no /facepalm. At least now I know.
So I'm pretty certain that what I have will work as intended, provided I call it from the mainloop()'s thread.
That makes the million dollar question: how do I get the main (GUI) thread to make the call? It seems a common enough occurrence that this can be done but obviously I'm not in the know.
Similar problem: http://mail.python.org/pipermail/tki...er/002078.html
Third dot point from the bottom, up from 'Resources': http://docs.huihoo.com/tkinter/Tkint...ary.html#Hints
The key point from the last link; "use 'after' from the main loop to poll a 'threading Queue' that your thread writes"
That makes sense but I do not understand where in the main loop I would put this command - if its a specific location I will probably be better off simply doing a condition check for this specific case and not complicating my project with the use of Queues (although they do look quite nice).
Please tell me you know where I should be putting this bvdet or that I'm being an idiot for realising it already :D.
bvdet 2,851
Expert Mod 2GB
Try calling widget.after() from your main thread to check the value of some variable that you set in the child thread. See my Clock example.
It works perfectly now! Thanks so much bvdet for helping with this. I now understand the true significance of your clock example.
I could die happily right now that I have that solved...
To who may care, I ended up making a flag that gets checked like this: -
def --the setup section--
-
self.UListBox.after(5000, self.check_to_update_list)
-
-
def check_to_update_list(self):
-
"""Allows process to be called based on variables from non-Mainloop threads safely"""
-
if client_flags.contacts_update == True:
-
self.generate_list()
-
client_flags.contacts_update = False
-
-
self.UListBox.after(2000, self.check_to_update_list)
-
So it makes the call to self.generate_list() based on the variable set in the child thread and Tkinter is all happy.
bvdet 2,851
Expert Mod 2GB @jinsue
You have made my day. It is gratifying to solve problems such as this. I have learned from your problem also.
Sign in to post your reply or Sign up for a free account.
Similar topics
by: max(01)* |
last post by:
hi people.
when i create a widget, such as a toplevel window, and then i destroy
it, how can i test that it has been destroyed? the problem is that even
after it has been destroyed, the instance...
|
by: phil_nospam_schmidt |
last post by:
I am trying to prevent a user from resizing a frame beyond its
"natural" size as given by winfo_reqwidth and winfo_reqheight, without
any success. Can anyone make any suggestions, based on my code...
|
by: Tuvas |
last post by:
I'm tyring to set the size of the window that is opened when you open a
Tkinter window, without much sucess. I have tried changing the heigth
and width atributes, but it doesn't do anything. I...
|
by: Eric_Dexter |
last post by:
Instead of creating my buttons and waiting for me to press them to
execute they are executing when I create them and won't do my callback
when I press them.. thanks for any help in advance
...
|
by: idsh |
last post by:
I cant make this code work. I am new at Python, and in this program I have made a simple mastermind program.
After creating the widgets, I try to insert text in the textbox in a function but all I...
|
by: Rajendran Appavu |
last post by:
When I am done with a widget that is packed in a Frame, is it safe to
call destroy() method on the widget after calling its pack_forget() or
grid_forget() method?
--
Thanks,
Rajendran.
|
by: joshdw4 |
last post by:
I hate to do this, but I've thoroughly exhausted google search. Yes,
it's that pesky root window and I have tried withdraw to no avail. I'm
assuming this is because of the methods I'm using. I...
|
by: J-Burns |
last post by:
Hello. Im a bit new to using Tkinter and im not a real pro in
programming itself... :P. Need some help here.
Problem 1:
How do I make something appear on 2 separate windows using Tkinter? By...
|
by: Mariostg |
last post by:
I am trying to have a form talk to another one as per exemple below. Basically, a child form alter a widget on a parent form. I cannot find a way to make this to work. What am I doing wrong or...
|
by: taylorcarr |
last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: ryjfgjl |
last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
|
by: emmanuelkatto |
last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud.
Please let me know.
Thanks!
Emmanuel
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
| |