I'm using Tkinter with a progress bar.
I've got the code below with the "callback" function that adding 50% to my progress bar.
I would like to limit the function to work only once for each OptionMenu selection.
Currently, I can click twice on the first OptionMenu and get to 100% in the progress bar.
Does anyone know what I should change in the "callback" function in order to make it work only once for each OptionMenu? No matter how many times the user has clicked to change its selected value.
from tkinter import *
from tkinter.ttk import Progressbar
root = Tk()
root.title('Input window V1')
root.geometry('600x400')
root.resizable(False, False)
frame = Frame(root, width=600, height=400)
frame.configure(background="gray28")
frame.pack(fill=BOTH, expand=True)
progress = Progressbar(root, orient=HORIZONTAL, length=300, mode='determinate')
progress.place(x=150, y=15)
Budget = {'Flexible', 'Variable', 'Fixed'}
Commitment = {'High', 'Medium', 'Low'}
def callback(*args):
progress["value"] += 50
bottom_header = Label(root, bg="gray28", fg="white", pady=3,
font=("Helvetica", 20, 'underline'), text='Please fill the following attributes:')
bottom_header.place(x=110, y=100)
lbl1 = Label(root, bg="gray28", text='Budget:', fg="cyan2", font=("Helvetica", 14))
lbl1.place(x=120, y=200)
lbl2 = Label(root, bg="gray28", text='Commitment:', fg="cyan2", font=("Helvetica", 14))
lbl2.place(x=120, y=240)
var1 = StringVar(root)
pl1 = OptionMenu(root, var1, *Budget)
pl1.config(width=20, bg="GREEN", fg="white")
pl1.place(x=250, y=200)
var1.trace("w", callback)
var2 = StringVar(root)
pl2 = OptionMenu(root, var2, *Commitment)
pl2.config(width=20, bg="GREEN", fg="white")
pl2.place(x=250, y=240)
var2.trace("w", callback)
global var_dict
var_dict = dict(Budget=var1,
Commitment=var2)
button1 = Button(root, text="Test")
button1.config(width=25, bg="white")
button1.place(x=220, y=320)
root.mainloop()
Thanks in advance!
Try this out:
from tkinter import *
from tkinter.ttk import Progressbar
def callback(*args):
user_input = (var_1.get(), var_2.get()) # Here you can add even more variables
value = 100 - 100/len(user_input)*(user_input.count("")+user_input.count("Select option"))
progress.config(value=value)
root = Tk()
progress = Progressbar(root, orient="horizontal", length=300)
progress.pack()
var_1 = StringVar(root)
var_1.trace("w", callback)
optionmenu_1 = OptionMenu(root, var_1, "Select option", "Option 1", "Option 2")
optionmenu_1.pack()
var_2 = StringVar(root)
var_2.trace("w", callback)
optionmenu_2 = OptionMenu(root, var_2, "Select option", "Option 1", "Option 2")
optionmenu_2.pack()
# You can remove these if you don't like them:
var_1.set("Select option")
var_2.set("Select option")
root.mainloop()
It counts the number of empty OptionMenus and setts the progress bar to the correct percentage.
Keep track of which of the two you have already accounted for, and update only if there was not yet 50% added for this part.
The callback function is changed (and is understandable) and the passing of the callback is changed to a lambda function (which can be confusing if you never used them).
this works for me:
from tkinter import *
from tkinter.ttk import Progressbar
root = Tk()
root.title('Input window V1')
root.geometry('600x400')
root.resizable(False, False)
frame = Frame(root, width=600, height=400)
frame.configure(background="gray28")
frame.pack(fill=BOTH, expand=True)
progress = Progressbar(root, orient=HORIZONTAL, length=300, mode='determinate')
progress.place(x=150, y=15)
Budget = {'Flexible', 'Variable', 'Fixed'}
Commitment = {'High', 'Medium', 'Low'}
budgetset = False
commitmentset = False
def callback(nb):
global budgetset, commitmentset
if nb == 0 and not budgetset:
budgetset = True
progress["value"] += 50
if nb == 1 and not commitmentset:
commitmentset = True
progress["value"] += 50
bottom_header = Label(root, bg="gray28", fg="white", pady=3,
font=("Helvetica", 20, 'underline'), text='Please fill the following attributes:')
bottom_header.place(x=110, y=100)
lbl1 = Label(root, bg="gray28", text='Budget:', fg="cyan2", font=("Helvetica", 14))
lbl1.place(x=120, y=200)
lbl2 = Label(root, bg="gray28", text='Commitment:', fg="cyan2", font=("Helvetica", 14))
lbl2.place(x=120, y=240)
var1 = StringVar(root)
pl1 = OptionMenu(root, var1, *Budget)
pl1.config(width=20, bg="GREEN", fg="white")
pl1.place(x=250, y=200)
var1.trace("w", lambda *_, x=0: callback(x))
var2 = StringVar(root)
pl2 = OptionMenu(root, var2, *Commitment)
pl2.config(width=20, bg="GREEN", fg="white")
pl2.place(x=250, y=240)
var2.trace("w", lambda *_, x=1: callback(x))
global var_dict
var_dict = dict(Budget=var1,
Commitment=var2)
button1 = Button(root, text="Test")
button1.config(width=25, bg="white")
button1.place(x=220, y=320)
root.mainloop()
Related
I want to update getting results from an entry box in a way that when an integer enters, the equivalent rows of entry boxes appear below that. I have written the below code to make it work using a button. However, I want to make it happen automatically without a button as I entered the number, the rows update. I checked one way of doing that is using the after(). I placed after after() in the function and out of the function but it is not working.
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = IntVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
def update():
for i in range(1, n_para.get()+1):
entryX = Entry(root)
entryX.grid(row=i+1, column=0)
entryY = Entry(root)
entryY.grid(row=i+1, column=1)
entryZ = Entry(root)
entryZ.grid(row=i+1, column=2)
root.after(100, update)
root.after(1, update)
button1 = Button(root, text="update", command=update)
button1.grid(row=1, column=0)
root.mainloop()
You should try using the <KeyRelease> event bind.
import tkinter as tk
def on_focus_out(event):
label.configure(text=inputtxt.get())
root = tk.Tk()
label = tk.Label(root)
label.pack()
inputtxt = tk.Entry()
inputtxt.pack()
root.bind("<KeyRelease>", on_focus_out)
root.mainloop()
This types the text entered in real-time.
Edited Code with OP's requirement:
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = IntVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
def upd(event):
x = entry1.get()
if not x.isnumeric():
x = 0
for i in range(1, int(x)+1):
entryX = Entry(root)
entryX.grid(row=i+1, column=0)
entryY = Entry(root)
entryY.grid(row=i+1, column=1)
entryZ = Entry(root)
entryZ.grid(row=i+1, column=2)
# root.after(100, update)
root.bind("<KeyRelease>", upd)
# button1 = Button(root, text="update", command=update)
# button1.grid(row=1, column=0)
root.mainloop()
When the "view" button is pressed, it should trigger the function solution(i) such that label should be displayed in the new window. The problem is that the window opens and the previous label is packed but the label which gets it's text from "i" does not gets packed, Is there any issue in passing the parameter.
Any help is appreciated.
root = Tk()
root.config(background = "#303939")
root.state('zoomed')
def pre():
with open("DoubtSolution.txt","r+") as f:
dousol = f.read()
dousol_lst = dousol.split("`")
k = 0
window = Tk()
window.config(background = "#303939")
window.state('zoomed')
predoubt = Label(window,
text="Previous Doubts",
fg="Cyan",
bg="#303939",
font="Helvetica 50 bold"
).grid(row=0, column=1)
def solution(text):
print(text)
window1 = Tk()
window1.config(background="#303939")
window1.state('zoomed')
sol = Label(window1,
text=text[:text.find("~")],
font=font.Font(size=20),
bg="#303939",
fg="Cyan")
sol.pack()
window1.mainloop()
for i in dousol_lst:
if i[-5:] == admno:
doubt = Label(window, text=i[i.find("]]")+2:i.find("}}}}")], font=font.Font(size=20), bg="#303939",
fg="Cyan")
doubt.grid(row=2+k, column=1, pady=10)
view = Button(
master=window,
text="View", font=font.Font(size=15, family="Helvetica"),
activebackground="White",
bg="Teal",
bd=0.8,
fg="White",
command = lambda k = k:solution(i)
)
view.grid(row=2+k, column=2, padx=20)
k=k+1
window.mainloop()
previous = Button(
master=root,
text="Previous Doubts", font="Helvetica 22 bold",
activebackground="White",
bg="Teal",
bd=0.8,
fg="White",
command = pre
).grid(row=4, column=3, padx=20)
root.mainloop()
I'm just starting with python and i'm having a problem. I've tried various solutions, but i can't update the field that says '19'. When i click on plus, i want it to be 20, then 21,... and when i click - it has to go back to 20 , 19. Can anybody tell me how to solve this?
from tkinter import *
def fct_tempplus():
while True:
# tekstvak_input_user = tekstvak_input_user +1
return tekstvak_input_user + 1
def fct_tempmin():
print ('ok')
window = Tk()
window.geometry("800x400") # not *
window.title("TEST")
label= Label( window, text = "Temp?")
label.place(x=350,y=175)
tempplus=Button(window, bd=10,width=10, height = 1,text="+",command=fct_tempplus,
font=("Helvetica", 12))
tempplus.place(x=500,y=150)
tempmin=Button(window, bd=10,width=10, height = 1,text="-", font=("Helvetica", 12),command=fct_tempmin)
tempmin.place(x=500,y=200)
tekstvak_input_user = Entry(window, width = 10 )
tekstvak_input_user.insert(0,19.0)
tekstvak_input_user.place(x=350 , y=200)
window.mainloop()`
while True is not needed in this program. And you have to use .get() to get a value inside a function. And then you should store it in a globalized variable, convert it into int or float. Then, simply use delete(0, END) to clear what's inside the Entry widget and then use insert() to insert the new value in the Entry.
Like This:
from tkinter import *
var = 0
def fct_temp_plus():
global var
var = float(tekstvak_input_user.get())
var += 1
tekstvak_input_user.delete(0, END)
tekstvak_input_user.insert(0, var)
def fct_temp_min():
global var
var = float(tekstvak_input_user.get())
var -= 1
tekstvak_input_user.delete(0, END)
tekstvak_input_user.insert(0, var)
window = Tk()
window.geometry("800x400") # not *
window.title("TEST")
label = Label(window, text="Temp?")
label.place(x=350, y=175)
temp_plus = Button(window, bd=10, width=10, height=1, text="+", command=fct_temp_plus, font=("Helvetica", 12))
temp_plus.place(x=500, y=150)
temp_min = Button(window, bd=10, width=10, height=1, text="-", font=("Helvetica", 12), command=fct_temp_min)
temp_min.place(x=500, y=200)
tekstvak_input_user = Entry(window, width=10)
tekstvak_input_user.insert(0, 19.0)
tekstvak_input_user.place(x=350, y=200)
window.mainloop()
Note: You should always import tkinter as tk.
Like This:
import tkinter as tk
var = 0
def fct_temp_plus():
global var
var = float(tekstvak_input_user.get())
var += 1
tekstvak_input_user.delete(0, tk.END)
tekstvak_input_user.insert(0, var)
def fct_temp_min():
global var
var = float(tekstvak_input_user.get())
var -= 1
tekstvak_input_user.delete(0, tk.END)
tekstvak_input_user.insert(0, var)
window = tk.Tk()
window.geometry("800x400")
window.title("TEST")
label = tk.Label(window, text="Temp?")
label.place(x=350, y=175)
temp_plus = tk.Button(window, bd=10, width=10, height=1, text="+", command=fct_temp_plus, font=("Helvetica", 12))
temp_plus.place(x=500, y=150)
temp_min = tk.Button(window, bd=10, width=10, height=1, text="-", font=("Helvetica", 12), command=fct_temp_min)
temp_min.place(x=500, y=200)
tekstvak_input_user = tk.Entry(window, width=10)
tekstvak_input_user.insert(0, 19.0)
tekstvak_input_user.place(x=350, y=200)
window.mainloop()
I'm trying to get the value of the radiobutton selcted and storing this int into a varable. It's my first tkinter project, so I'm sorry for my probably stupid mistakes...
from tkinter import *
from tkinter import ttk
select = "A"
def begin():
grand = Tk()
grand.title("Converter")
window.destroy()
frame = Frame(grand)
option = IntVar()
-> AttributeError: 'NoneType' object has no attribute '_root'
grandlabel = Label(frame, text="Choose the grand").grid(row=0, sticky=N, padx=5)
grand1 = Radiobutton(frame, text="Speed", variable=option, value=1, command=sel).grid(row=1, sticky=W)
grand2 = Radiobutton(frame, text="etc", variable=option, value=2, command=sel).grid(row=2, sticky=W)
submitgrand = Button(frame, text="Ok", command=unit).grid(row=3, sticky=W)
frame.pack()
grand.mainloop()
def sel():
global option
global select
select = option.get()
option = StringVar()
def unit():
unit = Tk()
global select
select = grandchosen
if (grandchosen == "Speed"):
Label(unit, text="Test").pack()
else:
Label(unit, text="Test2").pack()
unit.mainloop()
root = Tk()
frame = Frame(root)
welcome = ttk.Label(frame, text="Welcome!").grid(row=0, sticky=N, padx=10, pady=3)
okbutton = Button(frame, text="Ok", width=15, command=begin).grid(row=1, sticky=S, padx=20, pady=30)
frame.pack()
style = ttk.Style()
style.configure("TLabel", foreground="midnight blue", font="Times 19")
root.mainloop()
Would be great to get some help, thank you!
What I would like to occur is that when I press the other button, the first label is destroyed and only the corresponding label is on the GUI. Is there a way to incorporate If statements into this or should I approach it another way?
from tkinter import *
root = Tk()
root.geometry("250x50")
def func1():
label = Label(root, text = 'Hello', fg="White", bg="Orange" )
label.pack(fill=BOTH, expand=True)
def func2():
label = Label(root, text = 'Goodbye', fg="White", bg="Orange" )
label.pack(fill=BOTH, expand=True)
button1 = Button(root, text = "Button 1", command = func1, fg="White",
bg="Black", width=10, height=5)
button1.pack(side=LEFT)
button2 = Button(root, text = "Button 2", command = func2, fg="White",
bg="Black", width=10, height=5)
button2.pack(side=LEFT)
root.mainloop()
Here is the approach that #jasonsharper proposed: It is indeed easier to have a single Label, created at the start, then to use the two buttons to set its text, and other properties.
import tkinter as tk
if __name__ == '__main__':
root = tk.Tk()
root.geometry("250x50")
def set_label(txt):
label['text'] = txt
label['fg'] = "White"
label['bg'] = "Orange"
button1 = tk.Button(root, text = "Button 1", command = lambda x='hello': set_label(x), fg="White", bg="Black", width=10, height=5)
button1.pack(side=tk.LEFT)
button2 = tk.Button(root, text = "Button 2", command = lambda x='bye': set_label(x), fg="White", bg="Black", width=10, height=5)
button2.pack(side=tk.LEFT)
label = tk.Label(root, text='')
label.pack(fill=tk.BOTH, expand=True)
root.mainloop()
Note:
Please avoid import * --> to keep your namespace clean, use import tkinter as tk