Graphical user interface with TK - button position and actions - python

I started using TK in python to build a graphical interface for my program.
I'm not able to fix 2 issues concerning (1) the position of a button in the window and (2) use a value of a radiobutton inside a fucntion.
This is my current code:
root = tk.Tk()
root.title("START")
root.geometry("500x200+500+200")
v = tk.IntVar()
v.set(0) # initializing the choice
my_choise = [
("Basic",1),
("Advanced",2),
('Extreme',3)
]
def ShowChoice():
print(v.get())
tk.Label(root,
text="""Choose your configuration:""",
justify = tk.LEFT,
padx = 20).pack()
val = 0
for val, choise in enumerate(my_choise):
tk.Radiobutton(root,text=choise,padx = 20,variable=v,command=ShowChoice,value=val).pack(anchor=tk.W)
def star_program(value):
os.system("ifconfig")
def open_comments_file():
os.system("gedit /home/user/Desktop/comments.txt")
def open_links_file():
os.system("gedit /home/user/Desktop/links.txt")
frame = tk.Frame(root)
frame.pack()
open_file_c = tk.Button(frame,
text="Comments",
command=open_comments_file)
open_file_f = tk.Button(frame,
text="Links",
command=open_links_file)
button = tk.Button(frame,
text="Start",
command=star_program(v.get()))
button.pack(side=tk.LEFT)
open_file_f.pack(side=tk.LEFT)
open_file_c.pack(side=tk.LEFT)
slogan = tk.Button(frame,
text="Cancel",
command=quit)
slogan.pack(side=tk.LEFT)
root.mainloop()
I would like that the buttons "Links" and "Comments" were positioned below the radiobutton, one below the other. Now, all buttons are in line, but I would like to have "start" and "cancel" at the bottom of my window.
Then I tried to use the value of the radiobutton (choice) inside the star_program function. It does not work. My idea is, based on the choice selected in the radiobutton, perform different actions when I click the button "start":
def star_program(value):
if value == 0:
os.system("ifconfig")
else:
print "Goodbye"
In addition, concerning "start" button, I have a strange behavior. The program runs "ifconfig" command also if I don't click on "start". And If I click "start" it does not perform any action.
Any suggestion?
Thanks!!!

i'm assuming this is more like what you're after:
root = tk.Tk()
root.title("START")
root.geometry("500x200+500+200")
v = tk.IntVar()
v.set(0) # initializing the choice
my_choise = [
("Basic",1),
("Advanced",2),
('Extreme',3)
]
def ShowChoice():
print(v.get())
tk.Label(root,
text="""Choose your configuration:""",
justify = tk.LEFT,
padx = 20).grid(column=1, row=0, sticky="nesw") # use grid instead of pack
root.grid_columnconfigure(1, weight=1)
val = 0
for val, choise in enumerate(my_choise):
tk.Radiobutton(root,text=choise,padx = 20,variable=v,command=ShowChoice,value=val).grid(column=1, row=val+1, sticky="nw")
def star_program(value):
os.system("ifconfig")
def open_comments_file():
os.system("gedit /home/user/Desktop/comments.txt")
def open_links_file():
os.system("gedit /home/user/Desktop/links.txt")
frame = tk.Frame(root)
frame.grid(column=1, row=4, sticky="nesw")
open_file_c = tk.Button(frame,
text="Comments",
command=open_comments_file)
open_file_f = tk.Button(frame,
text="Links",
command=open_links_file)
button = tk.Button(frame,
text="Start",
command=lambda: star_program(v.get()))
# use lambda to create an anonymous function to be called when button pushed,
needed for functions where arguments are required
button.grid(column=2, row=3, sticky="nesw")
open_file_f.grid(column=1, row=1, sticky="nesw")
open_file_c.grid(column=1, row=2, sticky="nesw")
slogan = tk.Button(frame,
text="Cancel",
command=quit)
slogan.grid(column=4, row=3, sticky="nesw")
root.mainloop()

The problem with the "start" button is due to the function definition.
This is the right code that does not trigger any action if you don't click the button:
button = tk.Button(frame,
text="Start",
command=star_program)

Related

tkinter get selected element from combobox without button

I'm trying to find a way to get the tkinter combobox selected element without using a button, or to get the value from command in button, however so far nothing is working for me.
here's an example code (that's not working):
def show_frame(frame, prev_frame):
selected_elem = combobox.get()
if selected_elem == "choose element":
label = Label(frame1, text="please choose an element!")
label.grid(row=4, column=0)
else:
prev_frame.grid_forget()
frame.grid(row=0, column=0, sticky='nsew')
return selected_elem
elem= ""
button = Button(frame1, text="enter", command=lambda: elem==show_frame(frame3, frame1))
button.grid(row=2, column=1, padx=10, pady=10)
Is there a way to get it also outside of this function? this was just an idea that I had but as I mentioned, it's not working...
You need the bind method to watch for a selected element:
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
root.title("Combobox")
selected_elem = tk.StringVar(value='value1')
combobox = ttk.Combobox(root, textvariable=selected_elem)
combobox['values'] = ('value1', 'value2', 'value3')
combobox.pack(fill=tk.X, padx=20, pady=20)
myLabel = tk.Label(root, text=selected_elem.get())
myLabel.pack()
# prevent typing a value
combobox['state'] = 'readonly'
# place the widget
combobox.pack(fill=tk.X, padx=5, pady=5)
# bind the selected value changes
def value_changed(event):
""" handle the value changed event """
myLabel.configure(text=selected_elem.get())
myLabel.pack()
combobox.bind('<<ComboboxSelected>>', value_changed)
root.mainloop()
more info here:
https://www.pythontutorial.net/tkinter/tkinter-combobox/

How to set default value of radio button using TKinter in a class?

I'm trying to set the default value of a radio button using TKinter and Python. It's my first time using it so I'm pretty new. My understanding is that the default value should be set to the second radio button in my example (value=1).
from tkinter import *
from tkinter import ttk
class RadioButtons:
def __init__(self, root):
self.root = root
self.jobNum = IntVar(value=1)
self.create()
def create(self):
content = ttk.Frame(self.root)
radioButtons = ttk.LabelFrame(content, borderwidth=5, relief="ridge", width=400, height=400, text="Radio Buttons")
radioButtonsLbl=ttk.Label(radioButtons, text="Buttons")
# radio buttons
jobType1 = ttk.Radiobutton(radioButtons, text="Button 0", variable= self.jobNum, value=0)
jobType2 = ttk.Radiobutton(radioButtons, text="Button 1", variable= self.jobNum, value=1)
jobType3 = ttk.Radiobutton(radioButtons, text="Button 2", variable= self.jobNum, value=2)
content.grid(column=0, row=0)
# add to grid
radioButtons.grid(column=0, row=0, columnspan=3, rowspan=3)
radioButtonsLbl.grid(column=0, row=5, padx=20, pady=5, sticky=W)
jobType1.grid(column=1, row=5, padx=20, pady=0, sticky=W)
jobType2.grid(column=1, row=6, padx=20, pady=0, sticky=W)
jobType3.grid(column=1, row=7, padx=20, pady=0, sticky=W)
root = Tk()
RadioButtons(root)
root.mainloop()
However no radio button is selected when running the program. (screenshot of program)
The debugger confirms that the value of self.jobNum is set correctly.(screenshot of debugger)
How do I set the default value? I've tried a number of things including self.jobNum.set() before and after creating and adding the radio buttons but to no avail.
What am I missing here? Is this some kind of scope issue?
I suspect this has something to do with python's garbage collector. I can make the problem go away by saving a reference to RadioButtons(root):
root = Tk()
rb = RadioButtons(root)
root.mainloop()

In tkinter, button moves down from its previous position when label text appear on window

When the button "Calculate BMI" is pressed the value appear above button as expected but pushes the button down. I want to fix the button whether pressed or not.
from tkinter import *
window = Tk()
window.title("ASA Downloader")
window.geometry("400x400")
frame1 = LabelFrame(window, padx=100, pady=100)
#Labels
weight_label = Label(frame1, text= "Weight")
height_label = Label(frame1, text= "Height")
weight_label.grid(row=0,column=0, columnspan=3)
height_label.grid(row=1,column=0, columnspan=3)
#Entery of weight
int_type= IntVar
w_entry= Entry(frame1, textvariable= int_type)
w_entry.grid(row=0, column=3, columnspan=2)
#Entery of height
h_entry= Entry(frame1, textvariable= int_type)
h_entry.grid(row=1, column=3, columnspan=2)
def bmi():
result_lable= Label(frame1, text=w_entry.get())
result_lable.grid(row=3, column=3)
result_lable.config(text= w_entry.get())
# Calculate Button
b5 = Button(frame1, text="Calculate BMI", command=bmi)
b5.grid(row=4, column=3, columnspan=3)
frame1.place(relx=.5, rely=.5, anchor="center")
frame1.mainloop()
After pressing button, it pushed a littlie down from previous position
You need to move the Label definition out of the function. Like this instead:
result_lable= Label(frame1)
result_lable.grid(row=3, column=3)
def bmi():
result_lable.config(text= w_entry.get())
I am not exactly sure what you want, but if you want to reserve space for the BMI calculator result the way to do that is by setting a height parameter in the result label.
To do that, you will need to initialize the code at the start of software, so it would look like this:
result_lable = Label(frame1, text=w_entry.get(), height=WHATEVER_YOU_WANT)
result_lable.grid(row=3, column=3)
def bmi():
result_lable.config(text=w_entry.get())
That way there is going to be a set height to the label between the entries and the button, and it will not be pushed back when you calculate.

tkinter (unsure of my error possibly due to .destroy())

from Tkinter import *
import random
menu = Tk()
subpage = Tk()
entry_values = []
population_values = []
startUpPage = Tk()
def main_menu(window):
window.destroy()
global menu
menu = Tk()
frame1 = Frame(menu)
menu.resizable(width=FALSE, height=FALSE)
button0 = Button(menu, text="Set Generation Zero Values", command=sub_menu(menu))
button1 = Button(menu, text="Display Generation Zero Values")
button2 = Button(menu, text="Run Model")
button3 = Button(menu, text="Export Data")
button4 = Button(menu, text="Exit Program", command=menu.destroy)
button0.grid(row=0, column=0, sticky=W)
button1.grid(row=2, column=0, sticky=W)
button2.grid(row=3, column=0, sticky=W)
button3.grid(row=4, column=0, sticky=W)
button4.grid(row=5, column=0, sticky=W)
menu.mainloop()
def sub_menu(window):
global subpage
window.destroy()
subpage = Tk()
subpage.resizable(width=FALSE, height=FALSE)
#defining sub page items
button5 = Button(subpage, text="Save Generation Data",command = main_menu(subpage))
juveniles_label0 = Label(subpage,text="Juveniles")
adults_label1 = Label(subpage,text="Adults")
seniles_label2 = Label(subpage,text="Seniles")
population_label3 = Label(subpage,text="Popultation")
survival_rate_label4 = Label(subpage,text="Survival Rate (Between 0 and 1)")
entry0 = Entry(subpage)
entry1 = Entry(subpage)
entry2 = Entry(subpage)
entry3 = Entry(subpage)
entry4 = Entry(subpage)
entry5 = Entry(subpage)
button4.grid(row=1, column= 6, sticky=E)
juveniles_label0.grid(row=0, column=1)
adults_label1.grid(row=0, column=2)
seniles_label2.grid(row=0, column=3)
population_label3.grid(row=1, column=0)
survival_rate_label4.grid(row=2, column=0)
entry0.grid(row=1, column=1)
entry1.grid(row=1, column=2)
entry2.grid(row=1, column=3)
entry3.grid(row=2, column=1)
entry4.grid(row=2, column=2)
entry5.grid(row=2, column=3)
#add entry 6 7 8
subpage.mainloop()
main_menu(subpage)
main_menu(startUpPage)
I'm very new to coding and stackoverflow. I am trying to create a GUI that has a main page which will be opened first and a sub page which will be opened by clicking a button which will be stored in the main page. my issue is that I have no clue why it isn't opening my main page. my thought is that it is something to do with the .destroy() or something similar. any help would be much appreciated.
As a general rule, you should create exactly one instance of Tk for the life of your program. That is how Tkinter is designed to be used. You can break this rule when you understand the reasoning behind it, though there are very few good reasons to break the rule.
The simplest solution is to implement your main menu and your sub menu as frames, which you've already done. To switch between them you can simply destroy one and (re)create the other, or create them all ahead of time and then remove one and show the other.
For example, the following example shows how you would create them ahead of time and simply swap them out. The key is that each function needs to return the frame, which is saved in a dictionary. The dictionary is used to map symbolic names (eg: "main", "sub", etc) to the actual frames.
def main_menu(root):
menu = Frame(root)
button0 = Button(menu, text="Set Generation Zero Values",
command=lambda: switch_page("sub"))
...
return menu
def sub_menu(root):
subpage = Frame(root)
button5 = Button(subpage, text="Save Generation Data",
command = lambda: switch_page("main"))
...
return subpage
def switch_page(page_name):
slaves = root.pack_slaves()
if slaves:
# this assumes there is only one slave in the master
slaves[0].pack_forget()
pages[page_name].pack(fill="both", expand=True)
root = Tk()
pages = {
"main": main_menu(root),
"sub": sub_menu(root),
...
}
switch_page("main")
root.mainloop()
For a more complex object-oriented approach see Switch between two frames in tkinter
heres some code that does what you want.. make a window, destroy it when button is clicked and then make a new window...
from Tkinter import *
import random
def main_menu():
global root
root = Tk()
b = Button(root,text='our text button',command = next_page)
b.pack()
def next_page():
global root,parent
parent = Tk()
root.destroy()
new_b = Button(parent,text = 'new Button',command=print_something)
new_b.pack()
def print_something():
print('clicked')
main_menu()
root.mainloop()
parent.mainloop()
ps. ive done this in python3 so keep that in mind though it wouldnt be a problem in my opinion

How do I make entry boxes in a second window?

I have been trying to make an entry box for people to enter their names, as part of a "registration" for a mini-program that I am doing, but the result is that an entry box doesn't appear at all.
Here is the section of the code that is troubling me:
def win2(self):
# this is the child window
board = Toplevel()
board.title("Sign up")
board.focus_set()
board.grab_set()
userVar = StringVar()
userVar.set('Username')
square1Label = Label(board,textvariable=userVar)
square1Label.grid(row=0, column=7)
userEnt=Entry(self)
userEnt.grid(row=1, column=7)
s2Var = StringVar()
s2Var.set('First Name')
square2Label = Label(board,textvariable=s2Var)
square2Label.grid(row=1, column=7)
leaveButton = Button(board, text="Quit", command=board.destroy)
leaveButton.grid(row=1, column=1, sticky='nw')
board.wait_window(board)
And here is the coding in full, minus the importing of Tkinter and the mainloop:
class Application(Frame):
"""GUI Application for making Baakibook"""
def __init__(self, parent):
"""Initialize the frame"""
Frame.__init__(self, parent, bg="light blue")
self.win1()
# different windows
def win1(self):
# this is the main/root window
signupButton = Button(root, text="Sign up", command=self.win2)
signupButton.grid(row=9, column=7)
loginButton = Button(root, text="Log in", command=self.win3)
loginButton.grid(row=10, column=7)
leaveButton = Button(root, text="Quit", command=root.destroy)
leaveButton.grid(row=1, column=1, sticky='nw')
b1Var = StringVar()
b2Var = StringVar()
b1Var.set('b1')
b2Var.set('b2')
box1Label = Label(root,textvariable=b1Var,width=12)
box1Label.grid(row=3, column=2)
box2Label = Label(root,textvariable=b2Var,width=12)
box2Label.grid(row=3, column=3)
root.mainloop()
def win2(self):
# this is the child window
board = Toplevel()
board.title("Sign up")
board.focus_set()
board.grab_set()
userVar = StringVar()
userVar.set('Username')
square1Label = Label(board,textvariable=userVar)
square1Label.grid(row=0, column=7)
userEnt=Entry(self)
userEnt.grid(row=1, column=7)
s2Var = StringVar()
s2Var.set('First Name')
square2Label = Label(board,textvariable=s2Var)
square2Label.grid(row=1, column=7)
leaveButton = Button(board, text="Quit", command=board.destroy)
leaveButton.grid(row=1, column=1, sticky='nw')
board.wait_window(board)
def win3(self):
# this is the child window
board = Toplevel()
board.title("Login User")
board.focus_set()
board.grab_set()
s1Var = StringVar()
s2Var = StringVar()
s1Var.set("s1")
s2Var.set("s2")
square1Label = Label(board,textvariable=s1Var)
square1Label.grid(row=0, column=7)
square2Label = Label(board,textvariable=s2Var)
square2Label.grid(row=0, column=6)
leaveButton = Button(board, text="Quit", command=board.destroy)
leaveButton.grid(row=1, column=1, sticky='nw')
board.wait_window(board)
The first argument you use to create the widget is what parent you want it assigned to. So, this line:
userEnt=Entry(self)
userEnt.grid(row=1, column=7)
makes the Entry widget in the Frame that you created in __init__. If you want it to appear in the Toplevel, create it like the other widgets you made in that method, ie:
userEnt=Entry(board)
userEnt.grid(row=1, column=7)
Also, your grid in the Toplevel doesn't make sense right now and a couple of your widgets will appear stacked until you change it.

Categories