Apologies if this is a completely easy fix and I've just missed it. I am learning Python and I am trying to develop a GUI alongside my backend code using Tkinter. This is completely foreign to me and I have recently come across the problem that when I press my buttons there is a very small chance that it will make my window move behind all other open programs.
I am not entirely sure what is causing this but my guess is it stems somehow from one of two functions I have; one meant to minimise the main root window and the second to reveal it. However, these functions are not called in any place in my program that I would not expect them and the windows being minimised are not the root window (which my two functions act on).
I have both functions added below (hopefully, I am pretty new to SO) but if any additional code is needed I will supply it. I have quite a bit of code and everything else functions perfectly so I didn't want to post all my code is all.
There is no particular combination of button presses or buttons in particular which cause it, it appears to be any of them seemingly at random. It sends whatever window I have up to the taskbar.
def revealMenu():
root.update()
root.deiconify()
def hideMenu():
root.withdraw()
I do understand there is way using Threads by emplying Qtimer and yes I do want it to update on a real time basis. I have experienced changing of these object Qlcd and Qlabel upon pushing button how ever i want it to update upon itself. Any help would be appreciated.
Since there was no answer from anyone I went in for digging and figured it out.
You need to add follwing code segment for repeated execution on a timely basis this helps the GUI update itself periodically for the stored variable data and update Qlable and QLCD widgets.
self.timer.timeout.connect(QtCore.SIGNAL(self.READ_DATA))
self.timer.start(51)
This upon trigger yield continus execturion as there is periodic signal generated.
Note: READ_DATA is the def i have declared in my program.
I made a program, which uses tkinter to create a window where stuff happens. It contains images and loops to constantly shift and move the images.
Now, when I close the window, the scripts are still running and it creates error messages that it has nowhere to place the images with new coordinates.
I think that the loops are still running. So my question is, how do I close the program all together after clicking the x on the window. Is there a way to bind the x(close window) to terminate the program, or cat n ibe done inside a code, to see when the tkinter window is closed(to me this way seems to be bad, because it would keep checking for if the window is still existing or not).
Thanks a lot!
I had the same issue caused by a top level window I had created and withdrawn but didn't destroy. Properly destroying it fixed my issue.
I have this following Python Tkinter code which redraw the label every 10 second. My question is , to me it seems like it is drawing the new label over and over again over the old label. So, eventually, after a few hours there will be hundreds of drawing overlapping (at least from what i understand). Will this use more memory or cause problem?
import Tkinter as tk
import threading
def Draw():
frame=tk.Frame(root,width=100,height=100,relief='solid',bd=1)
frame.place(x=10,y=10)
text=tk.Label(frame,text='HELLO')
text.pack()
def Refresher():
print 'refreshing'
Draw()
threading.Timer(10, Refresher).start()
root=tk.Tk()
Refresher()
root.mainloop()
Here in my example, i am just using a single label.I am aware that i can use textvariable to update the text of the label or even text.config. But what am actually doing is to refresh a grid of label(like a table)+buttons and stuffs to match with the latest data available.
From my beginner understanding, if i wrote this Draw() function as class, i can destroy the frame by using frame.destroy whenever i execute Refresher function. But the code i currently have is written in functions without class ( i don't wish to rewrite the whole code into class).
The other option i can think of is to declare frame in the Draw() as global and use frame.destroy() ( which i reluctant to do as this could cause name conflict if i have too many frames (which i do))
If overdrawing over the old drawing doesn't cause any problem (except that i can't see the old drawing), i can live with that.
These are all just my beginner thoughts. Should i destroy the frame before redraw the updated one? if so, in what way should i destroy it if the code structure is just like in my sample code? Or overdrawing the old label is fine?
EDIT
Someone mentioned that python tkinter is not thread safe and my code will likely to fail randomly.
I actually took this link as a reference to use threading as my solution and i didn't find anything about thread safety in that post.
I am wondering what are the general cases that i should not use threading and what are the general cases i could use threading?
The correct way to run a function or update a label in tkinter is to use the after method. This puts an event on the event queue to be executed at some time in the future. If you have a function that does some work, then puts itself back on the event queue, you have created something that will run forever.
Here's a quick example based on your example:
import Tkinter as tk
import time
def Draw():
global text
frame=tk.Frame(root,width=100,height=100,relief='solid',bd=1)
frame.place(x=10,y=10)
text=tk.Label(frame,text='HELLO')
text.pack()
def Refresher():
global text
text.configure(text=time.asctime())
root.after(1000, Refresher) # every second...
root=tk.Tk()
Draw()
Refresher()
root.mainloop()
There are a lot of things I would change about that program from a coding style point of view, but I wanted to keep it as close to your original question as possible. The point is, you can use after to call a function that updates the label without having to create new labels. Plus, that function can arrange for itself to be called again at some interval. In this example I picked one second just so that the effect is easier to see.
You also asked "I am wondering what are the general cases that i should not use threading and what are the general cases i could use threading?"
To put a blunt point on it, you should never use threading if you have to ask a question about when to use threading. Threading is an advanced technique, it is complicated, and it easy to get wrong. It's quite possible for threading to make your program slower rather than faster. It has subtle consequences, such as your programs failing mysteriously if you do things that aren't thread safe.
To be more specific to your situation: you should avoid using threads with tkinter. You can use them, but you can't access widgets from these other threads. If you need to do something with a widget, you must put an instruction in a thread-safe queue, and then in the main thread you need to periodically check that queue to see if there's an instruction to be processed. There are examples of that on this website if you search for them.
If all that sounds complicated, it is. For most of the GUIs you write, you won't need to worry about that. If you can take large processes and break them down into chunks that execute in 100 ms or less, you only need after, and never need threads.
To allow the cleanup with minimal code changes, you could pass previous frames explicitly:
import Tkinter as tk
def Draw(oldframe=None):
frame = tk.Frame(root,width=100,height=100,relief='solid',bd=1)
frame.place(x=10,y=10)
tk.Label(frame, text='HELLO').pack()
frame.pack()
if oldframe is not None:
oldframe.destroy() # cleanup
return frame
def Refresher(frame=None):
print 'refreshing'
frame = Draw(frame)
frame.after(10000, Refresher, frame) # refresh in 10 seconds
root = tk.Tk()
Refresher()
root.mainloop()
I'm playing about with a motion controller, therefore to "click" a button I am finding out which button is closest to the middle at any given point and then using the button.invoke() method.
I am confident the buttons and setup is working, because whenever I click the buttons - they work fine. However, When the button is called via the "button.invoke" method the whole thing just freezes up.
Other information which may be useful:
- The gui is being updated in it's own thread through the .mainloop function.
- Everything works fine when being clicked by a mouse
- The button.invoke() method works fine - when doing a simple print operation. It only freezes when switching frame.
Any help would be great, thanks.
Are you saying that mainloop runs in a separate thread from where you create the widgets? If so, that's your problem. You can only ever call tkinter functions from one thread.