Python 3.4 GUI if statement with buttons - python

I'm trying to learn coding with python 3.4. I built this mini GUI and I'm having trouble getting it to work. It prints out 2 every time even though I press the button 1 . All I want to do is to get 1 printed out in the label when I click the button on and 2 with button two with an if statement.
from tkinter import *
root = Tk()
root.geometry("500x500")
root.title("Test")
def button_press():
if one:
x = 1
display.configure(text=x)
if two:
x = 2
display.configure(text=x)
display = LabelFrame(root, bg="red", width="462", height="60")
display.pack()
one = Button(root, text="1", width="15", height="5",command=button_press)
one.pack(side="left")
two = Button(root, text="2", width="15", height="5", command=button_press)
two.pack(side="left")
root.mainloop()

You have two ways:
Or using a different function for each button
Or pass a lambda with one parameter.
bt … command = fct1
bt … command = fct2
Or use a lambda…
from tkinter import *
root = Tk()
root.geometry("500x500")
root.title("Test")
def button_press(var):
display.configure(text=var)
display = LabelFrame(root, bg="red", width="462", height="60")
display.pack()
one = Button(root, text="1", width="15", height="5",command=lambda : button_press(1))
one.pack(side="left")
two = Button(root, text="2", width="15", height="5", command=lambda : button_press(2))
two.pack(side="left")
root.mainloop()

I haven't done any Tkinter to be honest. That said the code snippet below
if one:
x = 1
display.configure(text=x)
if two:
x = 2
display.configure(text=x)
looks like a weird thing to do. Basically you are checking if one and than two are equal or not to None. This doesn't make sense since an if VARIABLE is always True for VARIABLE that is unequal 0, False or None.
Well, they are most certainly not equal to None, False or 0 since both variables represent an instance of a Button. So what you are doing is:
Check if one != None
Set label if 1. is True - this happens and you set the label to "1" but then...
Check if two != None
Set label if 3. is True - this also happens and it also overwrites the previous value of the label set by 2 which was "1" to "2". All this happens instantly so you are unable to see the transition and are left with the impression that only "2" is displayed.
We can go further and rewrite your code in order to expose this error:
def button_press():
if one:
x = 1
display.configure(text=x)
elif two:
x = 2
display.configure(text=x)
or even
def button_press():
if one:
x = 1
display.configure(text=x)
else:
x = 2
display.configure(text=x)
In both of the above cases the first statement will be executed and you will get 1 all the time and never 2. Once you check for the first logical expression in your if-else block and it is True, you go in there and then leave the whole block not touching the elif or else at all.
There are various ways how to fix this. You can assign a name to the button (so that you can distinguish each button based on its name) in case you still want to handle both buttons with a single function and then do a comparison whether the name of the object that called your event handling function is == "one" or == "two". However in most (all?) UI frameworks it is a common practice to have a separate function for each UI component that handles an event that the component supports (multiple functions if the component supports multiple event).
one = Button(root, text="1", width="15", height="5",command=button_press1)
one.pack(side="left")
two = Button(root, text="1", width="15", height="5",command=button_press2)
two.pack(side="left")
This solution is similar to #Clodion's but without the lambdas since I'm not sure if you are familiar with the concept and throwing that in might be a bit confusing.
I would suggest following some basic principles when working with an UI. If your component has support for - let's say - value changes, resized, clicked, pressed down, pressed up etc. (don't know the name of these in Tkinter but I would guess it supports at at least some of them) - you will create a separate function for each event. This not only makes your code more readable but also forces you to learn a way of doing things that is de facto standard no matter if you write your UI with Tkinter, Qt, .NET, Swing, AngularJS and so on.

This is what you want. May be new syntax but its the kinda thing you will get used to seeing. Dont be daunted.
from tkinter import *
root = Tk()
class BuildGui():
def __init__(self, parent):
self.parent = parent
self.parent.geometry("500x500")
self.parent.title("Building a Gui")
self.parent.configure(background="steel blue")
self.parent.resizable(0,0)
self.parent.grid()
self.CreateFrames()
self.AddButtons()
def CreateFrames(self):
"""Create The Frames"""
self.Frm = Frame(self.parent, bg = "steel blue")
self.Frm.grid(row = 0, column = 0)
def AddButtons(self):
self.Btn1 = Button(self.Frm, text = "Button1", height = 2, width = 10, fg = "black", activebackground = "yellow", bg = "light blue", command = self.Button1Pressed)
self.Btn2 = Button(self.Frm, text = "Button2", height = 2, width = 10, fg = "black", activebackground = "yellow", bg = "light blue", command = self.Button2Pressed)
self.Btn1.grid(row = 0, column = 0, padx = 40, pady = 40)
self.Btn2.grid(row = 0, column = 1, padx = 40, pady = 40)
def Button1Pressed(self):
self.Lbl1 = Label(self.Frm, text = "Button1pressed!", font = ("Calibri", 12))
self.Lbl1.grid(row = 1, column = 0, padx = 20, pady = 20)
def Button2Pressed(self):
self.Lbl2 = Label(self.Frm, text = "Button2pressed!", font = ("Calibri", 12))
self.Lbl2.grid(row = 1, column = 1, padx = 20, pady = 20)
buildgui = BuildGui(root)
root.mainloop()

Related

Simple problem in multiple checkbox selection with executable example. Is there automatic way to recognize the plurality multiple selected checkboxes?

Is there an automatic way to recognize the plurality of multiple selected checkboxes? I don't want to manually create multiple selection combinations. I would like to get that:
1/3 checkbox: if I select the first or third box individually, I get the print "ok" in the text box
2/3 checkbox: if I select the first and third at the same time, I get the print "ok" in the text box. But only one "ok" printed, and not two ok as "ok ok" (so two checkboxes correspond to one ok)
I don't want to print the second checkbox in the textbox, because I intentionally wrote an error on it.
The problem is this function. Probably AND (or OR) is not what I need, I guess, I don't know:
def aaa():
if Checkbutton1.get() and Checkbutton2.get() and Checkbutton3.get():
textbox.insert("end", "Ok")
#I also tried to write: if Button1_func() and Button2_func() and Button3_func():
I guess the solution is to create other conditions for each type of multiple selection case, but I think there is a more automatic and better way without creating selection cases with conditions, because I will have to add dozens of other checkboxes and the situation would get complicated.
IMPORTANT: Please do not make sarcasm about True and False, because 5 + 3 = 8 is just a simple example to understand the logic of the checkboxes to which I will have to apply other different code. Leave the return True and False as is, without changing the functions.
Can anyone possibly help me by showing me the correct code? Thank you
import sqlite3
from tkinter import *
from tkinter import ttk
import tkinter as tk
import tkinter.messagebox
from tkinter import messagebox
root = tk.Tk()
root.geometry("600x600")
root.configure(bg='white')
Checkbutton1 = IntVar()
Checkbutton2 = IntVar()
Checkbutton3 = IntVar()
#CHECKBOX'S FUNCTIONS
def Button1_func():
if 5 + 3 == 8:
return True
else:
return False
def Button2_func():
if 5 + 3 == 7:
return True
else:
return False
def Button3_func():
if 5 + 3 == 8:
return True
else:
return False
#CHECKBOX
Button1 = Checkbutton(root, text = "Checkbox 1", variable = Checkbutton1, onvalue = 1, offvalue = 0, height = 1,
bg="white", foreground='black', activebackground="white", command=Button1_func)
Button1.place(x=10, y=36)
Button2 = Checkbutton(root, text = "Checkbox 2", variable = Checkbutton2, onvalue = 1, offvalue = 0, height = 1,
bg="white", foreground='black', activebackground="white", command=Button2_func)
Button2.place(x=10, y=66)
Button3 = Checkbutton(root, text = "Checkbox 3", variable = Checkbutton3, onvalue = 1, offvalue = 0, height = 1,
bg="white", foreground='black', activebackground="white", command=Button3_func)
Button3.place(x=10, y=146)
#BUTTON FUNCTION
def aaa():
if Checkbutton1.get() and Checkbutton2.get() and Checkbutton3.get():
textbox.insert("end", "Ok")
#I also tried to write: if Button1_func () and Button2_func () and Button3_func ():
#TEXTOBOX
textbox = tk.Text(root, width=33, height=10, font=('helvetic', 12))
textbox.place(x=30, y=220)
#BUTTON
button = tk.Button(root, text="Ok", command= lambda: [aaa()])
button.pack()
root.mainloop()
UPDATE
In the code there is also this with which I save and load the checkboxes:
chk_lst = []
chk_lst.extend([Checkbutton1,Checkbutton2, Checkbutton3])
You can use a set to store the function references based on the state of those checkbuttons. Then inside aaa() executes all the functions in the set and determine whether to put OK into the text box or not:
def clicked(flag, func):
if flag:
funclist.add(func)
else:
funclist.remove(func)
funclist = set()
#CHECKBOX
Button1 = tk.Checkbutton(root, text = "Checkbox 1", variable = Checkbutton1, onvalue = 1, offvalue = 0, height = 1,
bg="white", foreground='black', activebackground="white",
command=lambda: clicked(Checkbutton1.get(), Button1_func))
Button1.place(x=10, y=36)
Button2 = tk.Checkbutton(root, text = "Checkbox 2", variable = Checkbutton2, onvalue = 1, offvalue = 0, height = 1,
bg="white", foreground='black', activebackground="white",
command=lambda: clicked(Checkbutton2.get(), Button2_func))
Button2.place(x=10, y=66)
Button3 = tk.Checkbutton(root, text = "Checkbox 3", variable = Checkbutton3, onvalue = 1, offvalue = 0, height = 1,
bg="white", foreground='black', activebackground="white",
command=lambda: clicked(Checkbutton3.get(), Button3_func))
Button3.place(x=10, y=146)
#BUTTON FUNCTION
def aaa():
# if need to clear the text box, uncomment below line
#textbox.delete("1.0", "end")
if funclist and all(func() for func in funclist):
textbox.insert("end", "Ok")
Edited for clarified question
Because each Checkbutton has a unique function associated with it, you will need to define these all manually. For now, I've substituted functions to stand in.
You don't actually need to pass the functions to your checkbuttons, because they are only evaluated when you click your Button. Instead, you can change aaa so that it creates a list of the function results for the ticked Checkbuttons. If any of these return False, don't print "OK". But if they all return True, print "OK"
import tkinter as tk
root = tk.Tk()
root.geometry("600x600")
# How many checkboxes you want
buttons = 5
button_eval = [0 for i in range(buttons)]
# If your functions are unique for each checkbox, you will need to define them here
def foo():
return True
def bar():
return False
my_functions = [foo, bar, foo, bar, foo] # You need to have 5 functions in this case for this to work
# Creating variables, buttons etc
x = [10, 10, 10, 10, 10]
y = [36, 66, 96, 126, 156]
checkbuttons_vars = [tk.IntVar() for _ in range(buttons)]
checkbuttons = [tk.Checkbutton(root, text=f"Checkbox {i+1}", variable=checkbuttons_vars[i], onvalue=1, offvalue=0) for i in range(buttons)]
for i, box in enumerate(checkbuttons):
box.place(x=x[i],y=y[i])
#BUTTON FUNCTION
def aaa():
function_results = [function() for i, function in enumerate(my_functions) if checkbuttons_vars[i].get()]
textbox.delete(1.0, "end")
if False not in function_results:
textbox.insert(1.0, "Ok")
#TEXTOBOX
textbox = tk.Text(root, width=33, height=10, font=('helvetic', 12))
textbox.pack()
#BUTTON
button = tk.Button(root, text="Ok", command=aaa)
button.pack()
root.mainloop()

How to enable a disabled Button after filling Entry widgets?

I have 2 Entrys and one button. I want to make that button's state disabled until the two Entrys are filled in. How can I achieve that?
howManyStocksLabel = Label(root, text = "How many stocks do you want to evaluate?")
howManyStocksLabel.grid(row = 1, column = 0)
howManyStocksEntry = Entry(root, borderwidth = 3)
howManyStocksEntry.grid(row = 1, column = 1)
riskLabel = Label(root, text = "Enter risk %")
riskLabel.grid(row = 2, column = 0, sticky = 'w')
riskEntry = Entry(root, borderwidth = 3)
riskEntry.grid(row = 2, column = 1)
nextButton = Button(root, text = "Next!", width = 20, height = 2,state = DISABLED,
fg = 'green', bg = 'white',
command= lambda: myClick(riskEntry, howManyStocksEntry, var))
nextButton.grid(row = 4, column = 1)
I tried to check whether the entries are filled in or not by:
if(riskEntry.get() != ""):
....................
but it just doesn't work.
You need to check if the value is there after the user inputs it. Also, you can use tk.StringVar() as a text variable and trace it.
Here is an example:
import tkinter as tk
def check_entry(*args):
if r1.get() and r2.get():
b1.config(state='normal')
else:
b1.config(state='disabled')
root = tk.Tk()
r1 = tk.StringVar(master=root)
r2 = tk.StringVar(master=root)
e1 = tk.Entry(root, textvariable=r1)
e1.pack()
e2 = tk.Entry(root, textvariable=r2)
e2.pack()
b1 = tk.Button(root, text='Click Me!', state='disabled')
b1.pack()
r1.trace('w', check_entry)
r2.trace('w', check_entry)
root.mainloop()
You will need to use a binding on your entry widgets to check whether the user has entered anything into the entry or not.
This code will fire the check_entry function every time the user types in one of the entry boxes:
riskEntry.bind('<KeyRelease>', check_entry)
howManyStocksEntry.bind('<KeyRelease>', check_entry)
Then your check_entry function might look like this:
def check_entry(event): #event is required for all functions that use a binding
if riskEntry.get() and howManyStocksEntry.get():
nextButton.config(state=NORMAL)
else:
nextButton.config(state=DISABLED)
One way to do it would be to utilize the ability to "validate" their contents that Entry widgets support — see adding validation to an Entry widget — but make it check the contents of multiple Entry widgets and change the state of a Button accordingly.
Below shows how to do this via a helper class that encapsulates most of the messy details needed to make doing it relatively painless. Any number of Entry widgets can be "watched", so it scales well to handle forms consisting of many more than merely two entries.
from functools import partial
import tkinter as tk
from tkinter.constants import *
class ButtonEnabler:
""" Enable/disable a Button depending on whether all specified Entry widgets
are non-empty (i.e. contain at least one character).
"""
def __init__(self, button, *entries):
self.button = button
self.entries = entries
for entry in self.entries:
func = root.register(partial(self.check_entries, entry))
entry.config(validate="key", validatecommand=(func, '%P'))
def check_entries(self, this_entry, new_value):
other_entries = (entry for entry in self.entries if entry is not this_entry)
all_others_filled = all(entry.get() for entry in other_entries)
combined = bool(new_value) and all_others_filled
self.button.config(state=NORMAL if combined else DISABLED)
return True
root = tk.Tk()
howManyStocksLabel = tk.Label(root, text="How many stocks do you want to evaluate?")
howManyStocksLabel.grid(row=1, column=0)
howManyStocksEntry = tk.Entry(root, borderwidth=3)
howManyStocksEntry.grid(row=1, column=1)
riskLabel = tk.Label(root, text="Enter risk %")
riskLabel.grid(row=2, column=0, sticky='w')
riskEntry = tk.Entry(root, borderwidth=3)
riskEntry.grid(row=2, column=1)
nextButton = tk.Button(root, text="Next!", width=20, height=2, state=DISABLED,
fg='green', bg='white', disabledforeground='light grey',
command=lambda: myClick(riskEntry, howManyStocksEntry, var))
nextButton.grid(row=4, column=1)
enabler = ButtonEnabler(nextButton, howManyStocksEntry, riskEntry)
root.mainloop()

How do I make a tkinter button destroy itself?

I made this program in Tkinter in python where a small window pops up when the code is run and a start button would pop up and make the window full screen and show the content after. I want to make the button destroy itself after I press it so it makes a fullscreen and removes the button. I am still a beginner and would like the answer to be simple. The solution I am looking for is to maybe destroy the button completely(preferred) or move it way out of sight in the fullscreen window. Here is the code:
import Tkinter as w
from Tkinter import *
w = Tk()
w.geometry("150x50+680+350")
def w1():
w.attributes("-fullscreen", True)
l1 = Label(w, text = "Loaded!", height = 6, width = 8).pack()
global b1
b1.place(x = -10000, y = -10000)
b1 = Button(w, text = "Start", height = 3, width = 20, command = w1).place(x = 0, y = 10)
b2 = Button(w, text = "Exit", command = w.destroy).place(x = 1506, y = 0)
w.mainloop()
As you can see I want to make button one destroy itself.
Try this:
import tkinter as tk # Use `import Tkinter as tk` for Python 2
root = tk.Tk()
root.geometry("150x50+680+350")
def function():
global button_start
root.attributes("-fullscreen", True)
label = tk.Label(root, text="Loaded!", height=6, width=8)
label.pack()
button_start.place_forget() # You can also use `button_start.destroy()`
button_start = tk.Button(root, text="Start", height=3, width=20, command=function)
button_start.place(x = 0, y = 10)
button_exit = tk.Button(root, text="Exit", command=root.destroy)
button_exit.place(x=1506, y=0)
root.mainloop()
PS: Please read this.
Try:
b1.place_forget()
This will essentially "forget" about the button and hide it from view.
Edit:
If you are getting the error that b1 is None try:
b1 = Button(w, text = "Start", height = 3, width = 20, command = w1)
b1.place(x = 0, y = 10)
You need to add the b1.place() option at the bottom for this to work

Activate Entry Box from Listbox in Tkinter

I'm trying to create a GUI to collect three inputs from a user, where the first input has two options (based on a Listbox), like the image below (where the option "NACA" is selected):
The problem is with the Listbox. I guess the options are overlapping each other. For example, If I select the NACA option (image above), and then I select the .txt option, some part of the NACA label remains:
And of course, just the labels are appearing, not the entry_boxes to type inside (if I delete the part of the listBox, the entry_boxes of the last two input appers, so I really guess the problem is with the ListBox)
import tkinter as tk
root = tk.Tk()
root.geometry('400x300')
root.resizable(0, 0)
menu_inicial = tk.Canvas(root, width = 400, height = 300)
menu_inicial.pack()
def naca_box():
naca_entry_box = tk.Entry(menu_inicial)
menu_inicial.create_window(200, 30, window=naca_entry_box)
naca_label = tk.Label(root, text="Enter NACA:")
naca_label.pack()
naca_label.place(x=50, y = 50)
def txt_box():
txt_entry_box = tk.Entry(menu_inicial)
menu_inicial.create_window(200, 30, window=txt_entry_box)
txt_label = tk.Label(root, text="Enter .txt:")
txt_label.pack()
txt_label.place(x=50, y = 50)
def aoa_box():
aoa_entry_box = tk.Entry(root)
menu_inicial.create_window(200, 60, window=aoa_entry_box)
aoa_label = tk.Label(root, text="Enter AoA (º):")
aoa_label.pack()
aoa_label.place(x=50, y = 80)
def panel_box():
panel_entry_box = tk.Entry(root)
menu_inicial.create_window(200, 90, window=panel_entry_box)
panel_label = tk.Label(root, text="Enter Nº Panels:")
panel_label.pack()
panel_label.place(x=40, y = 110)
def update_box(*args):
selection = box_list.curselection()
lb_value.set(options[selection[0]] )
if selection[0] == 0:
naca_box()
else:
txt_box()
options = ['NACA', '.txt']
listCon = tk.StringVar(value=options)
box_list = tk.Listbox(menu_inicial, listvariable=listCon, width=10, height=2, selectmode=tk.SINGLE)
box_list.grid(row=0, column=0)
box_list.bind('<<ListboxSelect>>', update_box)
lb_value=tk.StringVar()
aoa_box()
panel_box()
root.mainloop()
How can I proceed with this? Is a problem with the "IF" statement to choose the options ? (I don't know if this is the best what to do this...)
The problem is that while you clicking button each time,
you are creating label each time,
if you want to change the text in the label you created,use 'config()'
change your code like this,
sample_label=tk.Label(root)
sample_label.place(x=50, y = 50)
def naca_box():
naca_entry_box = tk.Entry(menu_inicial)
menu_inicial.create_window(200, 30, window=naca_entry_box)
sample_label.config(text="Enter NACA:")
def txt_box():
txt_entry_box = tk.Entry(menu_inicial)
menu_inicial.create_window(200, 30, window=txt_entry_box)
sample_label.config(text="Enter .txt:")

Button not showing up in Tkinter, even w/ geometry manager

I'm designing an app in tkinter, but there is a button that won't show up. The button is crucial to the program's operation.
import tkinter as tk
global field
root = tk.Tk()
root.resizable(0,0)
root.geometry('368x200')
header = tk.Label(root, text = 'Header Text', pady=20)
header.config(font = ('Tahoma', 24))
header.grid(row = 0, columnspan=2)
enter_here = tk.Label(root, text = 'Question: ')
enter_here.grid(row = 1, column = 0, pady = 50)
field = tk.Entry(root, width = 50)
field.grid(row = 1, column = 1, pady = 50)
answer = tk.Button(root, text = 'Answer', command = answerf, width=10)
answer.grid(row=2, column=2)
root.mainloop()
Title, header text and the letters are all placeholders. I just need to figure out how to use the button. I've looked around and couldn't find any answers; most people had just forgot a geometry manager.
You have to be careful what values you are passing to various parameters of tkinter widgets. In above case, this is the reason why you are not able to see button.
Change
field = tk.Entry(root, width = 50)
field.grid(row = 1, column = 1, pady = 50)
to
field = tk.Entry(root, width = 25)
field.grid(row = 1, column = 1, pady = 30)
And,
answer = tk.Button(root, text = 'Answer', command = answerf, width=10)
answer.grid(row=2, column=2)
to
answer = tk.Button(root, text = 'Answer', command = answerf, width=10)
answer.grid(row=1, column=2)
output:
The problem is simply that you're forcing the window to be a size that is too small for the objects inside it.
A simple fix is to remove this line:
root.geometry('368x200')
If you insist on keeping this line, then you need to adjust the parameters of the other widgets so that they fit in the constrained space. For example, you could reduce the size of the widgets or reduce the padding.

Categories