Is using if statements possible with Tkinter Buttons - python

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

Related

How to seperate Tkinter Gui app source code into multiple files

i'm working on downloading manager python gui app using Tkinter and halfway there my code started to look very messy so i decided to seperate functions on different file and then import it:
my main code:
from tkinter import *
from functions import add_download
root = Tk()
root.title("The Pownloader!")
canvas = Canvas(root, width=700, height=500).pack()
# Buttons:
ADD_BUTTON = Button(root, text="ADD", bd=4, height=2, width=5, command=add_download)
SETTINGS_BUTTON = Button(root, text="SETTINGS", bd=4, height=2, width=5)
ABOUT_BUTTON = Button(root, text="ABOUT", bd=4, height=2, width=5)
EXIT_BUTTON = Button(root, text="EXIT", bd=4, height=2, width=5, command=quit)
# Mini-Buttons:
PAUSE_MINI_BUTTON = Button(root, text="PAUSE", font=(None, "8"), height=2, width=3)
RESUME_MINI_BUTTON = Button(root, text="RESUME", font=(None, "8"), height=2, width=3)
REMOVE_MINI_BUTTON = Button(root, text="REMOVE", font=(None, "8"), height=2, width=3)
# Side_Mini_Buttons:
DOWNLOAD_WINDOW = Button(root, text="Downloads", font=(None, "8"), height=3, width=6)
ERRORS_WINDOW = Button(root, text="Failed", font=(None, "8"), height=3, width=6)
COMPLETED_WINDOW = Button(root, text="Completed", font=(None, "8"), height=3, width=6)
# Positionning Buttons:
ADD_BUTTON.place(x=70, y=20)
SETTINGS_BUTTON.place(x=145, y=20)
ABOUT_BUTTON.place(x=220, y=20)
EXIT_BUTTON.place(x=295, y=20)
PAUSE_MINI_BUTTON.place(x=290, y=455)
RESUME_MINI_BUTTON.place(x=340, y=455)
REMOVE_MINI_BUTTON.place(x=390, y=455)
DOWNLOAD_WINDOW.place(x=1, y=100)
ERRORS_WINDOW.place(x=1, y=160)
COMPLETED_WINDOW.place(x=1, y=220)
# Download Frame:
DOWNLOAD_LIST_LABEL = Label(root, text="Download List:")
DOWNLOAD_LIST_LABEL.place(x=70, y=80)
DOWNLOAD_ENTRIES = Listbox(root, width=70, height=19)
DOWNLOAD_ENTRIES.place(x=70, y=100)
# Main Loop:
root.mainloop()
However my functions.py code looks like this:
def add_download():
# Defining The Pop-up frame:
top = Toplevel(root, width = 420, height = 150)
top.title("New Download")
# Putting on widgets:
link = StringVar()
LINK_LABEL = Label(top, text = "Paste Link:")
FIELD_ENTRY = Entry(top, width = 40, textvariable=link)
def on_click():
link_to_verify = (link.get()).strip()
if len(link_to_verify)>15:
if link_to_verify[0:11]=="http://www.":
DOWNLOAD_ENTRIES.insert(0, link_to_verify)
else:
print("Stupid")
else:
print("not a valid link")
BUTTONS_WIDGET = Frame(top)
ADD_BUTTON = Button(BUTTONS_WIDGET, text = "Add", width=10, command=on_click)
CANCEL_BUTTON = Button(BUTTONS_WIDGET, text = "Cancel", width=10, command=top.destroy)
# Positionning everythig:
LINK_LABEL.grid(column=0,row=0)
FIELD_ENTRY.grid(column=1,row=0)
BUTTONS_WIDGET.grid(column=1,row=2)
ADD_BUTTON.grid(column=0,row=0)
CANCEL_BUTTON.grid(column=1,row=0)
basically i wanted the function to call and show a pop-up window, i'm sure this could done in a million times better but i'm just learning, however i receive an error says:
Toplevel is not defined
Every file needs to import tkinter.
In addition, any variables in the main file which are needed by the imported functions need to be passed into the functions. For example, you should define add_download to accept the root window as a parameter.
def add_download(root):
...
Then, in the main program, pass root as that parameter:
ADD_BUTTON = Button(root, ..., command=lambda: add_download(root))
You will need to build a class to manage it.
Inside run.py:
import tkinter as tk
from interface import GUI
root = tk.Tk()
GUI(root)
Then inside your interface.py script you can call in additional modules:
import tkinter as tk
from aux import AuxGUI
from menu import MenuGUI
class GUI:
def __init__(self, master):
self.master = master
self.GUI_list = []
self.AuxGUI = AuxGUI(self.master, self.GUI_list) # Additional module
self.MenuGUI = MenuGUI (self.master, self.GUI_list) # Additional module
Then you can use OOP to access functions or objects to dynamically interact with each other.
self.GUI_list.append(self.AuxGUI)
self.GUI_list.append(self.MenuGUI)
Inside menu.py identify the correct index from the GUI_list:
import tkinter as tk
class MenuGUI:
def __init__(self, master, GUI_list):
self.master = master
self.AuxGUI = GUI_list[0]

Python progress bar selecting limitation

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()

Parameters passed to a function does not works as intended

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()

when I click a button, color string will change dynamically & print on the screen

I have two button for print their color on the screen.
button1 = tk.Button(frame,height = 1, width = 2,bg="Red")
button1.pack()
button2 = tk.Button(frame,height = 1, width = 2,bg="Blue")
button2.pack()
So when i click Button1, my string (colorchange) will include "Red".
when i print that then it will write on the screen as ==>> Red.
Basic Example Code:
import tkinter as tk
win = tk.Tk()
def change_color_label(color):
color_change.set(color)
button1 = tk.Button(win, height=1, width=2, bg="Red",
command=lambda c='Red': change_color_label(c))
button1.pack()
button2 = tk.Button(win, height=1, width=2, bg="Blue",
command=lambda c='Blue': change_color_label(c))
button2.pack()
color_change = tk.StringVar()
mylabel = tk.Label(win, textvariable=color_change)
mylabel.pack()
win.mainloop()
or (with out change_color_label):
import tkinter as tk
win = tk.Tk()
button1 = tk.Button(win, height=1, width=2, bg="Red",
command=lambda: color_change.set('Red'))
button1.pack()
button2 = tk.Button(win, height=1, width=2, bg="Blue",
command=lambda: color_change.set('Blue'))
button2.pack()
color_change = tk.StringVar()
mylabel = tk.Label(win, textvariable=color_change)
mylabel.pack()
win.mainloop()

grid_remove on an Entry widget

Im new to Tkinter and am trying to build a simple GUI using grid manager which upon the push of button1, button2 appears along with an adjacent entry box. If you then press button2 the entry box and button2 dissapear. Below is a slice from the GUI code, the button dissapears but the entry box does not:
import Tkinter
from Tkinter import *
master = Tk()
CreateTestButton = Button(master, text="Create Test", command = CreateTest, fg="red", bg="white", font="Helvetica 10 bold")
CreateTestButton.grid(column=7, row=1)
def CreateTest():
TestEntry = Entry(master, text="", width = 100).grid(row=4,columnspan=6)
Label(self, text="Enter Test Name:").grid(row=3, column=0)
SaveTestButton = Button(master, text="Save to database", command=saveTest, fg="green", bg="white", font="Helvetica 10 bold")
SaveTestButton.grid(row=4, column=5)
def saveTest():
SaveTestButton.grid_remove()
TestEntry.grid_remove() #ERROR
mainloop()
How is one to remove entry boxes using grid manager in Tkinter? And other widgets for that matter I will also be needing to remove a list box, labels and widgets uppon a button click or event.
Regards,
Daniel
grid return nothing; By executing TestEntry = Entry(..).grid(...), TestEntry become None instead of Entry object.
Replace following line:
TestEntry = Entry(self, text="", width = 100).grid(row=4,columnspan=6)
with:
TestEntry = Entry(self, text="", width = 100)
TestEntry.grid(row=4,columnspan=6)
Complete code
from Tkinter import *
def CreateTest():
def saveTest():
SaveTestButton.grid_remove()
TestEntry.grid_remove() #ERROR
TestEntry = Entry(master, text="", width = 100)
TestEntry.grid(row=4,columnspan=6)
Label(master, text="Enter Test Name:").grid(row=3, column=0)
SaveTestButton = Button(master, text="Save to database", command=saveTest, fg="green", bg="white", font="Helvetica 10 bold")
SaveTestButton.grid(row=4, column=5)
master = Tk()
CreateTestButton = Button(master, text="Create Test", command = CreateTest, fg="red", bg="white", font="Helvetica 10 bold")
CreateTestButton.grid(column=7, row=1)
mainloop()

Categories