How to select one tkinter button at a time - python

I want my tkinter button to raised when selected before content in the entry can be printed but both button can be selected to be raised at the same time.All the behaviour i want my widget to act is performing only that am able to select both button at the same time which i want one to raised at a time.
import tkinter as tk
def output():
global choosed
if choosed:
now = new.get()
print(now)
else:
print("select predict button to proceed")
def raised_button(button_object):
global choosed
choosed = True
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
def stop():
global choosed
choosed = False
lot1.configure(relief=tk.RAISED, state=tk.ACTIVE)
lot2.configure(relief=tk.RAISED, state=tk.ACTIVE)
root = tk.Tk()
root.geometry("400x400")
new = tk.StringVar()
en = tk.Entry(root, textvariable=new).pack()
choosed = False
lot1 = tk.Button(root, text="GOOD")
lot1.configure(command=lambda button_object=lot1:
raised_button(button_object))
lot1.pack(side="left")
lot2 = tk.Button(root, text="BAD")
lot2.configure(command=lambda button_object=lot2:
raised_button(button_object))
lot2.pack()
tk.Button(root, text="print number", command=lambda :[output(),
stop()]).place(x=150, y=300)
root.mainloop()
if button GOOD is selected the sunken is applied to it only then if select button BAD sunken effect is applied to it the button Good sunken effect is disabled.

As I understand only one button can be sunken. If you click second button then first button (which is sunken) have to raise again.
You can use stop() inside raise_button().
def raised_button(button_object):
global choosed
choosed = True
stop()
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
Or you can use choosed to remember suken button and raise it when you click other button.
def raised_button(button_object):
global choosed
if choosed: # previously clicked
choosed.configure(relief=tk.RAISED, state=tk.ACTIVE)
choosed = button_object
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
def stop():
global choosed
choosed = None
lot1.configure(relief=tk.RAISED, state=tk.ACTIVE)
lot2.configure(relief=tk.RAISED, state=tk.ACTIVE)
#----
choosed = None # set at start
EDIT: you can also use Radiobuttons with indicatoron=0 and they will look like normal buttons but still only one Radiobutton can be selected.
import tkinter as tk
root = tk.Tk()
v = tk.IntVar()
tk.Radiobutton(root, text="One", variable=v, value=1, indicatoron=0).pack()
tk.Radiobutton(root, text="Two", variable=v, value=2, indicatoron=0).pack()
tk.Button(root, text='Reset', command=lambda:v.set(0)).pack()
root.mainloop()
See more on effbot.org: Radiobutton

Related

Value from new window, button, and script to main script/window python+tkinter

I have a main script. When you push the button (in tkinter) you open a class with a new window and a new button.
When you click the new button (in the new window and different file) the text in the main window should be updated.
I have the following:
Main script
from tkinter import *
from kandit import Kandit
root=Tk()
def hoop():
s=Kandit()
label.configure(text=s)
button=Button(root, text="ok", command=hoop)
button.grid(row=0,column=0)
label=Label(root, text="nog niet dus")
label.grid(row=1, column=0)
Sub-script
class Kandit:
def __init__(self):
self.Master=Toplevel()
self.Button=Button(self.Master, text="check", command=self.Return())
self.Button.grid(row=0,column=0)
self.Master.mainloop()
def Return(self):
self.Keuze="nothing"
return self.Keuze #, self.Master.destroy()
except from the destroy it works until the moment I press the "check" button.
Than nothing happens.
Try this:
import tkinter as tk
class Kandit:
def __init__(self):
# Set the default value for keuze:
self.keuze = None
self.master = tk.Toplevel()
# If the user presses the "X" in the window toolbar call `_return`
self.master.protocol("WM_DELETE_WINDOW", self.destroy)
# When the button is pressed call `_return`
self.button = tk.Button(self.master, text="check", command=self._return)
self.button.grid(row=0, column=0)
# Start the mainloop. Later we will stop the mainloop
# Note it waits until the button is pressed/window closed
self.master.mainloop()
# Here we can garantee that `_return` was called
# and `self.keuze` has set to the value we need.
def _return(self):
# Set the result in a variable
self.keuze = "nothing"
self.destroy()
def destroy(self):
# Stop the mainloop so that the program can continue
self.master.quit()
# Remove the window from the screen
self.master.destroy()
def hoop():
# Create the window and wait until the button is pressed/window closed
new_window = Kandit()
# Get the result from the class
new_text = new_window.keuze
#if
# Set the label with the result
label.configure(text=new_text)
root = tk.Tk()
button = tk.Button(root, text="ok", command=hoop)
button.grid(row=0, column=0)
label = tk.Label(root, text="nog niet dus")
label.grid(row=1, column=0)
root.mainloop()
The problem in your case is that you can't return values from the __init__ method. This is why you have you save the result to a variable and retrieve it later

Call variables in function by adding to variable number?

I'm Creating a gui in tkinter and have buttons named btn1 btn2 btn3 etc, what i want the button to do on click is disable the button clicked and enable the next button in order. I can write out 6 seperate functions but that seems to defeat the point of a function.
if (btn1['state'] == tk.NORMAL):
btn1.config(state=tk.DISABLED),
btn2.config(state=tk.NORMAL)
else: print ('already clicked')
this is what i have now, but i want it to look more like btn #+1 (state=DISABLED)
You can put the buttons in a list, and then iterate over the list.
Here's a bit of a contrived example:
import tkinter as tk
root = tk.Tk()
def click(button_number):
button = buttons[button_number]
button.configure(state="disabled")
if button == buttons[-1]:
# user clicked the last button
label.configure(text="BOOM!")
else:
next_button = buttons[button_number+1]
next_button.configure(state="normal")
next_button.focus_set()
label = tk.Label(root, text="")
label.pack(side="bottom", fill="x")
buttons = []
for i in range(10):
state = "normal" if i == 0 else "disabled"
button = tk.Button(root, text=i+1, state=state, width=4,
command=lambda button_number=i: click(button_number))
button.pack(side="left")
buttons.append(button)
buttons[0].focus_set()
root.mainloop()

Tkinter GUI program issue. Entry.get() problem

Working on a project in which I use Tkinter in order to create a GUI that gives a list of software in a drop-down and when a particular software is chosen, it takes you to a separate window where a user's name will be entered and they would be added to a database. With the code I have so far, I am able to link a "submit" button on the second window to a function that prints a confirmation message as a test to make sure the button works. My issue now is trying to get the input from the entry field and link the input to the "Submit" button but I can't seem to find a way to do so. I was wondering if I could get some advice on how to go about this. Would classes need to be used in order to make it work? or can I stick with functions and keep the code relatively simple?
I have added the code for my program below.
import tkinter as tk
from tkinter import *
from tkinter import ttk
root = tk.Tk() # Main window
root.title("Software Licences")
root.geometry("300x300")
frame = ttk.Frame(root, padding="50 0 50 50")
frame.pack(fill=tk.BOTH, expand=True)
tkvar = StringVar()
choices = ['Imagenow', # Dropdown menu with software options
'FileMakerPro',
'Acrobat',
'Office',
'Lotus Notes']
tkvar.set('Acrobat') # Shows default dropdown menu option when program is opened
popupMenu = OptionMenu(frame, tkvar, *sorted(choices))
popupLabel = ttk.Label(frame, text="Choose Software")
popupLabel.pack()
popupMenu.pack()
def software_pages(): # In this function is the 2nd window with for each individual software
top = Toplevel()
top.title("Software Licences")
top.geometry("300x300")
myLabel = Label(top, text=tkvar.get()).pack()
employee_entrylbl = Label(top, text="Employee name").pack()
employee_entry = Entry(top, width=25, textvariable=tk.StringVar) # Entry field for adding user's name
employee_entry.pack() # Entry field is displayed
if tkvar.get() == "Acrobat": # for each if statement, button command is link to the functions
# defined below
button = ttk.Button(top, text="Submit", command=add_to_acrobat).pack()
elif tkvar.get() == "Imagenow":
button = ttk.Button(top, text="Submit", command=add_to_imagenow).pack()
elif tkvar.get() == "FileMakerPro":
button = ttk.Button(top, text="Submit", command=add_to_filemakerpro).pack()
elif tkvar.get() == "Office":
button = ttk.Button(top, text="Submit", command=add_to_office).pack()
else:
button = ttk.Button(top, text="Submit", command=add_to_lotusnotes).pack()
exit_button = ttk.Button(top, text="Exit", command=top.destroy).pack() # Exit button for second window
add_emp_button = ttk.Button(frame, text="Next", command=software_pages) # "Next" button in the main window takes the
# user to the second window
add_emp_button.pack()
# Functions below are linked to the button commands of each software in the second window function defined earlier.
# They print out specified messages that confirm the user had been added
def add_to_acrobat():
return print("User added to Acrobat")
def add_to_lotusnotes():
print("User added to IBM")
def add_to_imagenow():
print("User added to imagenow")
def add_to_office():
print("User added to 365")
def add_to_filemakerpro():
print("User added to FMP")
def click_button(): # Function for Exit button for main window
root.destroy()
exit_button = ttk.Button(frame, text="Exit", command=click_button) # Exit button for main window
exit_button.pack()
root.mainloop()
You can pass parameters to the command of tkinter.command using partial from the functools module.
in your case:
button = ttk.Button(top, text="Submit", command=partial(add_to_acrobat, employee_entry)).pack()
in the above line, I send the employee_entry(Which holds your desired text) to the add_to_acrobat function
and the add_acrobat function should look like this:
def add_to_acrobat(e):
print(e.get())
return print("User added to Acrobat")
Hope it helps

Disable / Enable Button in TKinter

I'm trying to make a button like a switch, so if I click the disable button
it will disable the "Button" (that works). And if I press it again, it will enable it again.
I tried things like if, else but didn't get it to work.
Here's an example:
from tkinter import *
fenster = Tk()
fenster.title("Window")
def switch():
b1["state"] = DISABLED
#--Buttons
b1=Button(fenster, text="Button")
b1.config(height = 5, width = 7)
b1.grid(row=0, column=0)
b2 = Button(text="disable", command=switch)
b2.grid(row=0,column=1)
fenster.mainloop()
A Tkinter Button has three states : active, normal, disabled.
You set the state option to disabled to gray out the button and make it unresponsive. It has the value active when the mouse is over it and the default is normal.
Using this you can check for the state of the button and take the required action. Here is the working code.
from tkinter import *
fenster = Tk()
fenster.title("Window")
def switch():
if b1["state"] == "normal":
b1["state"] = "disabled"
b2["text"] = "enable"
else:
b1["state"] = "normal"
b2["text"] = "disable"
#--Buttons
b1 = Button(fenster, text="Button", height=5, width=7)
b1.grid(row=0, column=0)
b2 = Button(text="disable", command=switch)
b2.grid(row=0, column=1)
fenster.mainloop()
The problem is in your switch function.
def switch():
b1["state"] = DISABLED
When you click the button, switch is being called each time. For a toggle behaviour, you need to tell it to switch back to the NORMAL state.
def switch():
if b1["state"] == NORMAL:
b1["state"] = DISABLED
else:
b1["state"] = NORMAL

How to make tkinter button raised before executing command

Am trying to make GUI app which compulsory you have to select one of predict button before the number entered will be printed to the terminal,if none of predictbutton is selected the should print outselect predict button to proceed.
In pseudecode something like:
def check:
now = new.get()
if no lotto_button is selected:
print("select predict button to proceed")
else:
print(now)
But having challenges:
1:when i select one predict button both buttons raised.
2:How to make the predict compulsory to be selected before the content in the entry will be printed.
import tkinter as tk
def terminal():
now = new.get()
print(now)
def start_func():
lotto_button.configure(relief=tk.SUNKEN, state=tk.DISABLED)
lotto_button1.configure(relief=tk.SUNKEN, state=tk.DISABLED)
def stop_func():
lotto_button.configure(relief=tk.RAISED, state=tk.ACTIVE)
lotto_button1.configure(relief=tk.RAISED, state=tk.ACTIVE)
root = tk.Tk()
root.geometry("400x400")
new = tk.StringVar()
en = tk.Entry(root, textvariable=new).pack()
lotto_button = tk.Button(root, text="predict one", command=start_func)
lotto_button.pack(side="left")
lotto_button1 = tk.Button(root, text="predict two", command=start_func)
lotto_button1.pack()
tk.Button(root, text="print number", command=lambda :[stop_func(),
terminal()]).place(x=150, y=300)
root.mainloop()
Thank you and your advice to do is welcome.
As for making it compulsory for picking, you can define a flag in outermost scope (in same level as root = tk.Tk()) so that you can see in your functions if it's set or not like:
isPredicted = False
And as for disabling each button when one is picked, you can define your your start_func such that it takes button object (lotto_button or lotto_button1) as argument:
def start_func(button_object):
global isPredicted
isPredicted = True
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
To be able to use this function, you need to configure your buttons in the following way, so that they pass themselves as the argument:
lotto_button.configure(command=lambda button_object=lotto_button: start_func(button_object))
lotto_button1.configure(command=lambda button_object=lotto_button1: start_func(button_object))
You should have isPredicted flag in your stop_func as well so that it unsets it:
def stop_func():
global isPredicted
isPredicted = False
lotto_button.configure(relief=tk.RAISED, state=tk.ACTIVE)
lotto_button1.configure(relief=tk.RAISED, state=tk.ACTIVE)
As for your terminal function, you'd want to act based on the state of isPredicted so it needs to be defined as:
def terminal():
global isPredicted
if isPredicted:
now = new.get()
print(now)
else:
print("select predict button to proceed")
finally in your "print number" button you need to swap the order of the functions in lambda or isPredicted is always False as far as that button's command is concerned:
tk.Button(root, text="print number", command=lambda :[terminal(),
stop_func()]).place(x=150, y=300)
Your final code should look like:
import tkinter as tk
from tkinter import messagebox
def terminal():
global isPredicted
if isPredicted:
now = new.get()
print(now)
else:
print("select predict button to proceed")
def start_func(button_object):
global isPredicted
isPredicted = True
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
def stop_func():
global isPredicted
isPredicted = False
lotto_button.configure(relief=tk.RAISED, state=tk.ACTIVE)
lotto_button1.configure(relief=tk.RAISED, state=tk.ACTIVE)
root = tk.Tk()
root.geometry("400x400")
new = tk.StringVar()
en = tk.Entry(root, textvariable=new).pack()
isPredicted = False
lotto_button = tk.Button(root, text="predict one")
lotto_button.configure(command=lambda button_object=lotto_button: start_func(button_object))
lotto_button.pack(side="left")
lotto_button1 = tk.Button(root, text="predict two")
lotto_button1.configure(command=lambda button_object=lotto_button1: start_func(button_object))
lotto_button1.pack()
tk.Button(root, text="print number", command=lambda :[terminal(),
stop_func()]).place(x=150, y=300)
root.mainloop()
When you're clicking on one of the button prediction, both are raised because in your function start_func, you're configuring both.
Instead of configuring both of them you can bind an event click and getting the widget in start_func like this:
lotto_button = tk.Button(root, text="predict one")
lotto_button.bind('<1>', start_func)
lotto_button.pack(side="left")
And then in your start_func :
def start_func(event):
w = event.widget
w.configure(relief=tk.SUNKEN, state=tk.DISABLED)
About your second point, I'm not sure to understand what you mean.
Using Radiobutton widgets tends to be better for this sort of multiple choice processing.
Radiobuttons belong to "groups" which means that you can set them up so that one always needs to be selected by default. This means that you don't need to have any kind of error catching or display any sort of instruction to the user, it just intuitively works.
from tkinter import *
root = Tk()
def command(v, entry):
print(v.get(), entry.get())
v = StringVar()
v.set(1)
entry = Entry(root)
rb1 = Radiobutton(root, text="Predict One", variable=v, value=1, indicatoron=0)
rb2 = Radiobutton(root, text="Predict Two", variable=v, value=2, indicatoron=0)
button = Button(root, text="Print Number", command=lambda:command(v, entry))
entry.pack()
rb1.pack()
rb2.pack()
button.pack()
root.mainloop()
So we create a StringVar() which we use to define which Radiobutton widgets should be linked together and then we set it's value to 1 which is the value of the "Predict One" button. If the user presses the other Radiobutton then the value changes to 2 which means the first button "unpresses" and the value of the StringVar() is changed to 2.

Categories