I have a problem. I want to simplify and explain the problem.
I have this code:
from tkinter import *
from tkinter.scrolledtext import ScrolledText
def do():
global text
for i in range(0, 10):
time.sleep(0.5)
text.insert(INSERT, i)
root = Tk()
global text
text = ScrolledText(root)
text.grid()
button = Button(root, text = 'insert', command = do)
button.grid(row = 1, column = 0)
root.mainloop()
It does a simple job. it has to open the root window and add a number to it every half second, but it does it all at once and after the loop is done.
If your looking for how to use after(ms,func), this is how your function should look like:
lst = [_ for _ in range(10)] #list of numbers to index through
count = 0 #index number
def do():
global count
text.insert(INSERT,lst[count]) #insert the current element onto the textbox
count += 1 #increase the index number
rep = root.after(500, do) #repeat the function
if count >= len(lst): #if index number greater than length of items in list
root.after_cancel(rep) #stop repeating
and root.after_cancel(id) will cancel the repetition. Using global outside the functions holds no good.
Related
So I'm trying to make a program that has a typing animation,
Here is my reproducible example :
from tkinter import *
root = Tk()
text = "message"
num = 0
message = text[num]
label = Label(root,text=message)
label.pack()
def add() :
global num
num + 1
leng = len(text)
if num == leng :
while True :
num = leng
label.configure(text=message)
root.after(1000, add)
root.mainloop()
It doesn't work and just shows the first letter
First of all, please make descriptive variable names. Calling a variable x will not help others understand what they stand for.
Secondly, the way you used root.after() is not how it works. This piece of code should be in a function, which should have as the second parameter.
Finally, I removed the message variable because we can just increment the index value by 1.
Here is the code:
from tkinter import *
root = Tk()
text = "message"
index = 0
lab = Label(root)
lab.pack()
def add(a):
global index
if index < len(text):
lab.config(text=lab.cget("text") + text[index])
index += 1
root.after(1000, add, root)
add('arg')
root.mainloop()
I'm trying to learn Tkinter module, but I can't undestand why the after method doesn't behave as expected. From what I know, it should wait ms milliseconds and then execute the function, but in my case the function gets executed many more time, not considering the time I write. Here's the code:
from tkinter import *
def doSomething():
x = int(l["text"])
l["text"] = str(x + 1)
root = Tk()
root.geometry("300x300")
l = Label(root, text="0")
l.pack()
while True:
l.after(1000, doSomething)
root.update()
if int(l["text"]) >= 5:
break
root.mainloop()
After the first 2 seconds the label starts displaying humongous numbers
After the first 2 seconds the label starts displaying humongous numbers
Keep in mind, while True, is an infinite loop, you are making infinite calls to root.after() means alot of events are being scheduled to be called after 1 second. Better way to do this is to remove your while and move it all inside your function.
from tkinter import *
root = Tk()
def doSomething():
x = int(l["text"])
l["text"] = x + 1
if int(l["text"]) < 5: # Only repeat this function as long as this condition is met
l.after(1000, doSomething)
root.geometry("300x300")
l = Label(root, text="0")
l.pack()
doSomething()
root.mainloop()
Though the best way to write the function would be to create a variable and increase the value of that variable inside the function and then show it out:
from tkinter import *
root = Tk()
count = 0 # Initial value
def doSomething():
global count # Also can avoid global by using parameters
count += 1 # Increase it by 1
l['text'] = count # Change text
if count < 5:
l.after(1000, doSomething)
root.geometry("300x300")
l = Label(root, text=count)
l.pack()
doSomething() # If you want a delay to call the function initially, then root.after(1000,doSomething)
root.mainloop()
This way you can reduce the complexity of your code too and make use of the variable effectively and avoid nasty type castings ;)
You are using infinite loop when using while True. Correct way is:
from tkinter import *
def doSomething():
x = int(l["text"])
l["text"] = str(x + 1)
if x < 5:
l.after(1000, doSomething)
root = Tk()
root.geometry("300x300")
l = Label(root, text="0")
l.pack()
doSomething()
root.mainloop()
I have written a piece of code code I want to improve it when I enter the elements ,It only allows me to insert data into first index at first,then it enables the second box to insert data into and so. how do I disable the states of other elements of Array?
import tkinter as tk
root=tk.Tk()
root.title("Looping of entry box")
root.geometry("1200x600")
def ApplytoLabel():
xx=size.get()
for i in range(xx):
element = box_list[i].get() # Get value from corresponding Entry
ArrayLabel=tk.Label(ArrayR,text="Array Element: " + element,font="Arial 12 bold",bg="red",fg="white",bd="5")
ArrayLabel.pack()
box_list = [] # Create list of Entrys
def Boxes():
xx=size.get()
for i in range(xx):
box=tk.Entry(ArrayR,font="Arial 10 bold",bd="5",width="5")
box.pack(side="left")
box_list.append(box) # Append current Entry to list
ApplytoLabel1=tk.Button(ArrayR,text="Submit To Array",command=ApplytoLabel)
ApplytoLabel1.pack()
Array = tk.Frame(root)
Array.pack()
text1=tk.Label(Array,text="Enter the Size of Array:",
font="Arial 10 bold",fg="blue")
text1.grid(row=0,column=0,sticky="w")
size=tk.IntVar()
ArraySize=tk.Entry(Array,textvariable=size)
ArraySize.grid(row=0,column=1,sticky="w")
SizeofArray=tk.Button(Array,text="Submit",command=Boxes)
SizeofArray.grid(row=0,column=2,sticky="w")
ArrayR = tk.Frame(root)
ArrayR.pack()
root.mainloop()
This is one way:
import tkinter as tk
root=tk.Tk()
root.title("Looping of entry box")
root.geometry("1200x600")
def ApplytoLabel():
xx=size.get()
for i in range(xx):
if box_list[i].cget('state') == 'normal':
element = box_list[i].get() # Get value from corresponding Entry
ArrayLabel=tk.Label(ArrayR,text="Array Element: " + element,font="Arial 12 bold",bg="red",fg="white",bd="5")
ArrayLabel.pack()
box_list[i].configure(state='disabled')
try:
box_list[i+1].configure(state='normal')
except IndexError: pass
break
box_list = [] # Create list of Entrys
def Boxes():
xx=size.get()
for i in range(xx):
box=tk.Entry(ArrayR,font="Arial 10 bold",bd="5",width="5",state='disabled' if i else 'normal')
box.pack(side="left")
box_list.append(box) # Append current Entry to list
ApplytoLabel1=tk.Button(ArrayR,text="Submit To Array",command=ApplytoLabel)
ApplytoLabel1.pack()
Array = tk.Frame(root)
Array.pack()
text1=tk.Label(Array,text="Enter the Size of Array:",
font="Arial 10 bold",fg="blue")
text1.grid(row=0,column=0,sticky="w")
size=tk.IntVar()
ArraySize=tk.Entry(Array,textvariable=size)
ArraySize.grid(row=0,column=1,sticky="w")
SizeofArray=tk.Button(Array,text="Submit",command=Boxes)
SizeofArray.grid(row=0,column=2,sticky="w")
ArrayR = tk.Frame(root)
ArrayR.pack()
root.mainloop()
In general though, you would probably want each button to have it's on lambda callback with ApplytoLabel receiving a single parameter so you do not have to loop (and break) every time. I would also wrap everything in a class.
import tkinter as tk
panel = tk.Tk()
num = 42
lbl1 = tk.Label(panel, text = str(num))
Let's say I have a function and button like this:
def increase():
lbl1.configure(text = str(num+1))
btn = tk.Button(panel, text = 'Increase', command = increase)
panel.mainloop()
This button will make the number that is the label increase by 1 when pressing the button. However, this only works once before the button does absolutely nothing. How can I make it so that every time I press the button, the number increases by 1?
You never saved the incremented value of num.
def increase():
global num # declare it a global so we can modify it
num += 1 # modify it
lbl1.configure(text = str(num)) # use it
It's because num is always 43
import tkinter as tk
num = 42
def increase():
global num
num += 1
lbl1.configure(text = str(num))
panel = tk.Tk()
lbl1 = tk.Label(panel, text = str(num))
lbl1.pack()
btn = tk.Button(panel, text = 'Increase', command = increase)
btn.pack()
panel.mainloop()
I am using itertools.combinations module to find a large number of combinations. While my program finds all its combinations (a lot of them) it checks for sum of every combination to be some number and then program store that combination in list.
from itertools import *
from math import *
import Tkinter as tk
import ttk
x = int(raw_input('Enter number of combinations: '))
z = int(raw_input('Enter sum number: '))
def combinator():
comb = combinations(range(100), x)
for i in comb:
yield i
my_combinations = []
combination_s = combinator()
for i in combination_s:
print i
c = list(i)
if fsum(c)==z:
my_combinations.append(c)
print my_combinations
root = tk.Tk()
root.title('ttk.Progressbar')
pbar = ttk.Progressbar(root, length=300, mode='determinate', maximum = 100)
pbar.pack(padx=5, pady=5)
root.mainloop()
I want to have ttk.progressbar that shows progress every time program evaluates sum of combinations. How can I do that?
Here is an example that increases the progress bar for every combination. It just waits for a short time, but you can easily change it to do some calculations in the for loop in ProgBarApp.start instead of time.sleep
from Tkinter import *
from itertools import combinations
import ttk
import time
class ProgBarApp:
def __init__(self):
self.vals = range(1, 20)
self.combs = list(combinations(self.vals,3))
self.n = len(self.combs)
self.progressbar = ttk.Progressbar(root, maximum = self.n+1)
self.progressbar.pack()
def start(self):
for c in self.combs:
self.progressbar.step()
time.sleep(0.01)
root.update()
root.destroy()
root = Tk()
p = ProgBarApp()
root.after(0, p.start())
root.mainloop()