I want to see continuously changing value of label in tkinter window. But I'm not seeing any of it unless I make a keyboard interrupt in MS-CMD while running which shows me the latest assigned value to label. Plz tell me ..What's going on & what's the correct code ??
import random
from Tkinter import *
def server() :
while True:
x= random.random()
print x
asensor.set(x)
app=Tk()
app.title("Server")
app.geometry('400x300+200+100')
b1=Button(app,text="Start Server",width=12,height=2,command=server)
b1.pack()
asensor=StringVar()
l=Label(app,textvariable=asensor,height=3)
l.pack()
app.mainloop()
The function server is called when you click the button, but that function contains an infinite loop. It just keep generating random numbers and sending these to asensor. You are probably not seeing any of it because the server function is run in the same thread as the GUI and it never gives the label a chance to update.
If you remove the while True bit from your code, a new number will be generate each time you click the button. Is that what you wanted to do?
Edit after comment by OP:
I see. In that case your code should be changed as follows:
import random
from Tkinter import Tk, Button, Label, StringVar
def server():
x = random.random()
print x
asensor.set(x)
def slowmotion():
server()
app.after(500, slowmotion)
app = Tk()
app.title("Server")
app.geometry('400x300+200+100')
b1 = Button(app, text="Start Server", width=12, height=2, command=slowmotion)
b1.pack()
asensor = StringVar()
asensor.set('initial value')
l = Label(app, textvariable=asensor, height=3)
l.pack()
app.mainloop()
I also introduced a new function, slowmotion, which does two things: 1) calls server, which updates displays the value, and 2) schedules itself to be executed again in 500ms. slowmotion is first ran when you first click the button.
The problem with your code was that it runs an infinite loop in the main GUI thread. This means once server is running, the GUI will not stop and will not get a chance to display the text you asked it to display.
Related
import tkinter
win=tkinter.Tk()
win.configure(background='grey')
k=False
def g():
k=True
v=tkinter.Button(win, text='click', command=g)
v.pack()
while k==True:
win.configure(background='black')
win.mainloop()
There's no reason why that while loop would run after the button is clicked, since (as you know) your program is run "from top to bottom", and control remains in win.mainloop() until the window is closed. (You can find that out by adding print("bye!") after that call.)
You might want to just directly call .configure(). (I gave the button some padding here so you can see the background change; otherwise the button may take up the entirety of the window and you won't see a change.)
import tkinter
win = tkinter.Tk()
def change_color():
win.configure(background='black')
button = tkinter.Button(win, text='click', command=change_color)
button.pack(padx=10, pady=10)
win.mainloop()
I have a problem where the tkinter Scale widget seems to get stuck whenever I run a seemingly big function.
This is the code:
from tkinter import Tk, Button, Frame, Scale
root = Tk()
slider = Scale(root, orient='horizontal')
slider.pack()
frame = Frame(root)
frame.pack()
num = 0
def buttons():
for widget in frame.winfo_children():
widget.destroy()
for i in range(50):
Button(frame, text='Button' + str(i)).pack()
def basic():
global num
slider.set(num)
num += 1
print(num)
if num <= 100:
slider.after(100, basic)
if __name__ == '__main__':
buttons()
basic()
root.bind('<space>', lambda x: buttons())
root.mainloop()
What I want my program to do is update the slider normally even when I press 'Space' (meaning calling the buttons() function)
If you watch closely each time you press Space the slider will get stuck a little.
Since I'm using the slider for an Mp3 player in order to show time elapsed, this loss of time is extremely important for example for audio files of 10 or so seconds since the slider falls behind a lot making it seem as if it's working wrong \
I'd also like to point out that destroying the buttons and then repacking them is necessary for me.
I suspect that this happens because the program has to go over the buttons() function something that takes time since it's creating 50 buttons. Or am I mistaken?
Can I avoid that lag?
PS: As I mentioned in my comment:
I normally have a button that renames a (button) which is a song and in order for them to alphabetically ordered after renaming i need to recall the function that draws them. If I only configure tha name of the button (and not redraw them), it will stay in place and not move down or up depending on its name, while on the actual directory the order will change leading to inappropriate behavior such as playing the same song
Here are some images for better understanding:
Thanks in advance!
Look at this code:
import tkinter as tk
def config_buttons():
# Get the `text` of the first button
starting_value = int(buttons[0].cget("text")) + 1
# Iterate over all of the buttons
for i, button in enumerate(buttons, start=starting_value):
# Change the button's `text` and `command` atributes
button.config(text=i, command=lambda i=i:print("Clicked %i"%i))
root = tk.Tk()
buttons = []
add_button = tk.Button(root, text="+1 on all buttons", command=config_buttons)
add_button.pack()
for i in range(50):
button = tk.Button(root, text=i, command=lambda i=i:print("Clicked %i"%i))
button.pack()
buttons.append(button)
root.mainloop()
When the add_button buttons is pressed, I iterate over all of the buttons and change their text and command attributes. As I am not creating new buttons, the function runs very fast.
You can implement something similar in your code. Basically, avoid creating new buttons and just update the ones you already have on the screen.
I know there are better ways about this, but I cant figure out what's
wrong about this code, or at least, why it wont function the way I want it. Currently I made a simple test program to try my concept away from my
main code.
from tkinter import *
root = Tk()
test = True
def click():
global test
print("working")
test = False
button = Button(root, text="Hi", command=click)
if test:
button.pack()
root.mainloop()
Everything runs fine but when I press the button all I get is the message "working" without the button going away.
In your code python checks if test is True and as it is, it packs the button and moves on. What you need to use is <tkinter widget>.pack_forget(). It removes the widget from the screen without destroying it. If you later call pack it should put it back in its original place. This is your code with the pack_forget:
from tkinter import *
root = Tk()
def click():
print("working")
button.pack_forget()
button = Button(root, text="Hi", command=click)
button.pack()
root.mainloop()
I'm running pycharm on the mac and noticed that the GUI would not open when it previously has. It bounces in the dock and then says that it is not responding.
So I wrote a very simple program to test the GUI and it still doesn't work.
from tkinter import *
import random
import time
root = Tk()
root.geometry("600x400")
var = 0
one = Label(root, textvariable=var)
one.pack()
while 1 == 1:
var = random.randint(1, 100)
time.sleep(1)
root.mainloop()
I tried reinstalling python but it doesn't help. Also, for my other program, textvariable wasn't able to work and I can't figure out why.
In order for the GUI to run and be responsive, mainloop has to execute. But your mainloop will never execute, because your while 1 == 1: loop will never finish. If you want to do something every second, remove that loop and use root.after instead.
Your textvariable isn't working because var is an integer. It needs to be a StringVar.
I am trying to delete text inside a text box after waiting 5 seconds, but instead the program wont run and does sleep over everything else. Also is there a way for me to just make my textbox sleep so i can run other code while the text is frozen?
from time import time, sleep
from Tkinter import *
def empty_textbox():
textbox.insert(END, 'This is a test')
sleep(5)
textbox.delete("1.0", END)
root = Tk()
frame = Frame(root, width=300, height=100)
textbox = Text(frame)
frame.pack_propagate(0)
frame.pack()
textbox.pack()
empty_textbox()
root.mainloop()
You really should be using something like the Tkinter after method rather than time.sleep(...).
There's an example of using the after method at this other stackoverflow question.
Here's a modified version of your script that uses the after method:
from time import time, sleep
from Tkinter import *
def empty_textbox():
textbox.delete("1.0", END)
root = Tk()
frame = Frame(root, width=300, height=100)
textbox = Text(frame)
frame.pack_propagate(0)
frame.pack()
textbox.pack()
textbox.insert(END, 'This is a test')
textbox.after(5000, empty_textbox)
root.mainloop()
You can emulate time.sleep in tkinter. For this we still need to use the .after method to run our code alongside the mainloop, but we could add readability to our code with a sleep function. To add the desired behavior, tkinter provides another underestimated feature, wait_variable. wait_variable stops the codeblock till the variable is set and thus can be scheduled with after.
def tksleep(t):
'emulating time.sleep(seconds)'
ms = int(t*1000)
root = tk._get_default_root('sleep')
var = tk.IntVar(root)
root.after(ms, var.set, 1)
root.wait_variable(var)
Real world examples:
update a Label to display a clock while-loop
animated writing nested for-loops
Limitation:
tkinter does not quit while tksleep is used.
Make sure there is no pending tksleep by exiting the application.
Using tksleep casually can lead to unintended behavior
UPDATE
TheLizzard worked out something superior to the code above here. Instead of tkwait command he uses the mainloop and this overcomes the bug of not quitting the process as described above, but still can lead to unintended output, depending on what you expect:
import tkinter as tk
def tksleep(self, time:float) -> None:
"""
Emulating `time.sleep(seconds)`
Created by TheLizzard, inspired by Thingamabobs
"""
self.after(int(time*1000), self.quit)
self.mainloop()
tk.Misc.tksleep = tksleep
# Example
root = tk.Tk()
root.tksleep(2)