Radiobutton in Tkinter calling function - python

I have code for radio buttons in tkinter. I am struggling to write the code that invokes the button command. Basically I want the user to be able to choose a time frame and a person. I have three different files that run three different data analyses, so I want the three files to run but only take data from the time frame and for that person.
from Tkinter import *
class RBDemo:
def __init__(self, win):
self.v = IntVar()
#Put the first group of radio buttons in their own frame.
f1 = Frame(win, borderwidth=3, relief=RAISED)
rb1 = Radiobutton(f1, text="This Week", variable=self.v, value=1)
rb2 = Radiobutton(f1, text="This Month", variable=self.v, value=2)
rb3 = Radiobutton(f1, text="This Year", variable=self.v, value=3)
rb1.pack(anchor=W); rb2.pack(anchor=W); rb3.pack(anchor=W)
f1.pack(side=LEFT)
#Button one will be selected by default
self.v.set(1)
#Make a second group of radiobuttons in their own frame.
#Make first button the default
self.v2 = StringVar()
f2 = Frame(win, borderwidth=2, relief=SOLID)
rb4 = Radiobutton(f2, text="Bob", variable=self.v2, value="Bob")
rb5 = Radiobutton(f2, text="Stacy", variable=self.v2, value="Stacy")
rb6 = Radiobutton(f2, text="Both", variable=self.v2, value="Both")
rb4.pack(anchor=W); rb5.pack(anchor=W); rb6.pack(anchor=W)
f2.pack(side=RIGHT)
self.v2.set("Bob")
#Make a button that prints what each value is when clicked
b = Button(win, text="Let's do this!", command=self.clicked)
b.pack(side=BOTTOM, fill=BOTH, expand=1)
def clicked(self):
print("button clicked!")
print("v is:", self.v.get())
print("v2 is:", self.v2.get() )
mw = Tk()
app = RBDemo(mw)
mw.mainloop()
I tried
def selected(self):
if self.my_var.get()==1:
"do something"
elif self.my_var.get()==2:
"do something"
else:
"do something"
but this doesn't seem to work, nor is it very pythonic considering I have to run three files using the input from the button.

First, When properly indented, an if - elif block is perfectly ok. So you could just use
if whatevervar.get() == 1:
dosomethingfancy()
elif whatevervar.get() == 2:
dosomethingcool()
#and so on
In other languages there is something like a switch - case block: wikipedia There is no such construct in Python, but there is a neat little trick that helps especially when dealing with bigger code blocks:
Options = {
1: dosomething,
2: dosomethingelse
}
#execution
Options[myvar.get()]()
Basically, a dictionary is defined, that maps its key values to functions. Mind the parentheses: You don't want to call the function, when the dictionary is defined.

Related

How can i get input text from an entrybox in Tkinter? [duplicate]

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 2 years ago.
So i am trying to get an text input for my program but tkinter doesn't seem to register it,
and i don't know what i have done wrong
window = self.newWindow(value)
label = tk.Label(window, text="Intfix to Postfix Convert")
label.place(x=0, y=20)
e1 = tk.Entry(window)
text = e1.get()
e1.place(x=0, y=50)
rezultat = tk.Text(window, width=20, height=3)
rezultat.place(x=0, y=80)
button = tk.Button(window, text="Enter")
button.place(x=127, y=46)
button.bind("<Double-Button-1>", self.passValue(rezultat, text))
My code looks something like this. Everything else is working the self.newWindow(value) is just
a function that creates a new window from the main one
so i said text=e1.get() but i ran the debbuger and it says it is an empty string and i want to pass this text through the function passValue()(a function that passes the value to the controller), i used button.bind() to do that. Is that ok?
I tested it by putting a default value at text like text="My name" and it did pass the value so that should be in order but i don't know why doesn't it get it from the entry box like it should.
I even tried to do e1.insert(0,"some random thing") and text= e1.get() and it did get it so i think there's a problem with the input.
Do i need to use some special kind of input function?
The whole code:
class Gui:
def __init__(self, controller):
self.main = tk.Tk()
self.main.title("DSA Quiz Helper")
self.__controller = controller
def IntFixPostExecute(self, event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection[0])
self.IntfixPostfixWindow(value)
def mainWindow(self):
self.main.geometry("800x500")
# to do scrollbar
lb = tk.Listbox(self.main, width=50, height=30)
lb.insert(1, "Intfix and Postfix Calculator")
lb.insert(2, "Something else")
lb.bind("<Double-Button-1>", self.IntFixPostExecute)
lb.pack()
def IntfixPostfixWindow(self, value):
window = self.newWindow(value)
label = tk.Label(window, text="Intfix to Postfix Convert")
label.place(x=0, y=20)
e1 = tk.Entry(window)
text = e1.get()
e1.place(x=0, y=50)
rezultat = tk.Text(window, width=20, height=3)
rezultat.place(x=0, y=80)
button = tk.Button(window, text="Enter")
button.place(x=127, y=46)
button.bind("<Double-Button-1>", self.passValue(rezultat, text))
print(text)
def passValue(self, rezultat, value):
returnValue = self.__controller.InfixToPostC(rezultat, value)
rezultat.insert(tk.INSERT, returnValue)
def newWindow(self, msg):
newwind = tk.Toplevel(self.main)
q1 = tk.Frame(newwind)
q1.pack()
newwind.geometry("500x230")
return newwind
def run(self):
self.mainWindow()
self.main.mainloop()
if i set this manually it works. I don't understand why i doesn't work from entrybox input
text = tk.StringVar()
e1 = tk.Entry(window, textvariable=text)
text.set("x+y*2")
text = e1.get()
e1.place(x=0, y=50)
I think i figured it out (correct me if i am wrong). I think there is a problem
with the button because as soon as a newwindow is open, the button automatically clicks itself, when at first in the entry box there is no text written yet(so it sends to the controller with the initial text(which is empty)). The problem is why the button auto-clicks itself( or anyway auto-runs the function passValue) and why after i input the text and click the button again it does nothing(so as i understand it works only one time and auto-runs itself, at first there is no text in entrybox and the button auto-runs itself,therefore passing an empty string
You should use entryname.get() to get the text that is inside that entry instead of declaring stringVar() and making that much more unreadable and hard to comprehend and to work with. But this is my point of view! – Tiago Oliveira 48 mins ago
I think what is happening is that u use the method right after declaring the entry widget wich means u are going to get a "" empty string because that's nothing that was written there, u need to replace on the command parameter with entryname.get() instead of declaring variable = entryname.get() and passing that as parameter wich will always be empty! Hope this helps!

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

I cannot trigger a random function when a given button is pressed in Tkinter

I am making a button which will display a message in the tkinter module in Python.
At first, the button has text on it. When it is clicked, it will display a messagebox. A messagebox is a "pop-up" or "error message."
The below code will show a sample function that executes the above sentence.
def joke1():
messagebox.showinfo(title = "There are three types of people in this world", message = "Those who can count and those who can't.")
root = Tk()
root.title("Joke Board 1.0 by Jamlandia")
root.iconbitmap(r"C:\Users\VMWZh\Downloads\Icons8-Ios7-Messaging-Lol.ico")
button = Button(text = "There are three types of people in this world", bg = '#42f474', fg = 'black', command = joke1)
test = Button()
button.grid(column = 0, row = 0)
test.grid(column = 1, row = 0)
root.mainloop()
I can not figure out a way to approach coding it so that when you press the button, it will run the function that correlates with the joke that is displayed on the button, then randomly bind to a new function and the text to change to the joke that correlates with that function.
Question: press the button, ... randomly ... change to the joke
tkinter — Python interface to Tcl/Tk
Tk Concepts
Label
Button
The Grid Geometry Manager
The Python Tutorial and Python Module
9. Classes - 9.5. Inheritance
9.3.5. Class and Instance Variables
random.randrange(start, stop[, step])
Show random Joke on Button click, without messagbox.
import tkinter as tk
import random
class App(tk.Tk):
def __init__(self):
super().__init__()
self.joke_index = 0
self.jokes = [("There are three types of people in this world", "Those who can count and those who can't."),
('Grew up with six brothers', 'That’s how I learned to dance–waiting for the bathroom'),
('Always borrow money from a pessimist.', 'He won’t expect it back.')
]
self.label1 = tk.Label(self)
self.label1.grid(row=0, column=0, pady=3)
self.label2 = tk.Label(self)
self.label2.grid(row=1, column=0, pady=3)
button = tk.Button(self,
text='Show next Joke',
command=self.show_random_joke,
bg='#42f474', fg='black'
)
button.grid(row=2, column=0, pady=3)
def show_random_joke(self):
v = -1
while v == self.joke_index:
v = random.randrange(0, len(self.jokes)-1)
self.joke_index = v
self.label1['text'], self.label2['text'] = self.jokes[self.joke_index]
if __name__ == "__main__":
App().mainloop()
Tested with Python: 3.5

Is there a way to define a command for radio buttons to show right or false answer in multiple choice quiz?

I am a beginner trying to create a multiple choice quiz in python with Tkinter. Sorry if I created a messy code. I am using radio buttons for different answers. I would like to show the message "This is the correct answer" when selecting Option 1 and "This is the wrong answer" when selecting any other option. Currently, the message is always "This is the wrong answer" regardless of the Option that is chosen. I understood that the value has nothing to do with it but I did not find the right way to do it. Is there a way to define this kind of command? Thank you so much for any help, recommendations and answers.
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
window = Tk()
window.title("Quiz")
window.geometry("500x150")
score = 0
def inst():
t = Label(window, text="Choose the correct statement to answer the
question")
t.pack()
def start():
start_game()
greet = Label(window, text="Welcome to the Quiz")
greet.pack()
startButton = Button(window, command=start, text="Start")
startButton.pack()
instr = Button(window, text="Instructions", command=inst)
instr.pack()
end = Button(window, text="Exit", command=window.destroy)
end.pack()
def start_game():
top = Toplevel()
top.title("Question 1")
var = StringVar()
def check():
if var.get() is True:
messagebox.showinfo('Congrats', message='This is the correct
answer.Score is {}'.format(score))
else:
messagebox.showinfo('Lose', message='This answer is wrong.')
R1 = Radiobutton(top,
text="Option 1",
indicatoron=0,
width=20,
padx=20,
pady=10,
variable=var,
value=True,
command=check)
R1.pack( anchor = W )
R2 = Radiobutton(top,
text="Option 2",
indicatoron=0,
width=20,
padx=20,
pady=10,
variable=var,
value=False,
command=check)
R2.pack( anchor = W )
R3 = Radiobutton(top,
text="Option 3",
indicatoron=0,
width=20,
padx=20,
pady=10,
variable=var,
value=False,
command=check)
R3.pack( anchor = W)
label = Label(top)
label.pack()
window.mainloop()
Since you're working with boolean values, I thought it made more sense to use a BooleanVar instead.
You can simply pass the buttons to the check function and change their colours if you know which one is correct:
def check(btn1, btn2):
btn1.config(bg='green')
btn2.config(bg='red')
Then modify the radiobuttons as such (just below where you've defined them):
for btn in (R1, R2):
btn.config(command=lambda btn1=R1,btn2=R2:check(btn1,btn2))
Note, I used two buttons as R2 and R3 had the same values so they'd be grouped as one effectively.
Here is an example; it uses a button list to store all radiobuttons that were created and changes the colour of each of them depending on their text whilst also checking if the player got the right answer.
import tkinter as tk
def check_answer():
if question_answer.get() == 2: #get the value of the integer variable
print('you got it right') #if it has been set to 2 by the player, they got it right
for btn in btnlist: #check each of our radiobuttons
if int(btn['text']) == 2: #if the text of that button is equal to the correct answer
btn.config(bg='green') #make it green
else:
btn.config(bg='red') #otherwise make it red
win = tk.Tk()
question = 'What is 1+1?' #put your question here
question_answer = tk.IntVar() #we use an Integer Variable to store the value of the answer
question_answer.set(0) #we set the value of the correct answer to 0
lbl = tk.Label(win, text=question)
lbl.grid(columnspan=4)
column = 0
btnlist = []
for answer in range(4): #create radiobuttons in a for loop
btn = tk.Radiobutton(win, text=str(answer), variable=question_answer,
value=answer) #associate each button with the answer variable
#but give each button its own unique value
btnlist.append(btn)
btn.grid(row=1, column=column)
column += 1
confirm_btn = tk.Button(win, text='Confirm', command=check_answer)
confirm_btn.grid(columnspan=4)
win.mainloop()
In this example I used an IntVar as the answer is an integer, you could also use a BooleanVar or StringVar in the same manner as needed.
EDIT: As per you request in the comments:
import tkinter as tk
win = tk.Tk()
text_to_add_to_btns = ['A', 'B', 'C', 'D', 'E'] #change to whatever text you like
#with however many elements which represent each individual button
btn_list = []
Column = 0
for txt in text_to_add_to_btns:
btn = tk.Button(win, text=txt)
btn.grid(row=0, column=Column, sticky='nesw')
btn_list.append(btn)
Column += 1
win.mainloop()
We create a default list containing text to add to each button as individual list elements. We then loop over that list to create each button for every element and set the text of the button to that element and then append it to our separate button list.

How would one bind two different button click events to the same label, namely "<Button-1>" and "<Double-Button1>" to same label?

So, i know there has got to be a way to do this iv'e literally been trying all day to figure a solution and this is the closest i've come to getting it. The code works but the flaw is that it never reaches the else if statement because whatever button click is first in the statement will always be True hence it will never reach else if. Is their some way to combine the first two statements of my code into one because i believe that would solve it? This is using the tkinter GUI.
self.label1.bind("<Double-Button-1>",self._two_click)
self.label1.bind("<Button-1>", self._two_click)
def _two_click(self,event):
if self.label1.bind("<Button-1>"):
self.label1.configure(self.my_timeBB())
elif self.label1.bind("<Double-Button-1>"):
self.label1.configure(text="Blue")
I use extra argument in function to recognize click.
BTW: you can always bind <Button-1> and <Double-Button1> to one widget but with different functions ?
import Tkinter as tk
def test(event, extra=None):
print extra
master = tk.Tk()
b1 = tk.Button(master, text="QUIT", command=master.destroy, width=20, heigh=5)
b1.pack()
b2 = tk.Label(master, text="OK", width=20, heigh=5)
b2.pack()
b2.bind('<Double-Button-1>', lambda event:test(event,101))
b2.bind('<Button-1>', lambda event:test(event,1))
b2.bind('<Button-2>', lambda event:test(event,2))
b2.bind('<Button-3>', lambda event:test(event,3))
master.mainloop()
But I see one (big) problem - when I try to make double-click with my mouse I always get two text - first for single-click and second for double-click.
The only solution can be measure time between click and decide whether choose single or double click. But probably it will need to use after() too.
EDIT:
run only single or double clik
import Tkinter as tk
#----------------------------------------------------------------------
single = False
def test(event, extra=None):
global single
#print 'event-num:', event.num
#print 'extra:', extra
if extra == 1:
single = True
master.after(200, single_click)
elif extra == 101:
single = False
click('double click')
def single_click():
global single
if single:
single = False
click('single click')
def click(msg):
print 'It was', msg
#----------------------------------------------------------------------
master = tk.Tk()
b1 = tk.Button(master, text="QUIT", command=master.destroy, width=20, heigh=5)
b1.pack()
b2 = tk.Label(master, text="OK", width=20, heigh=5)
b2.pack()
b2.bind('<Double-Button-1>', lambda event:test(event,101))
b2.bind('<Button-1>', lambda event:test(event,1))
master.mainloop()

Categories