python tkinter.Radiobutton can't get value - python-3.x

I'm writing a python code with tkinter (python3) but I have some problems. I have two classes _MainScreen and _RegisterScreen (this last is nested in _MainScreen). In _RegisterScreen I had implemented a simple question with tkinter.Radiobutton (choose your sex: male, female). The idea is to catch the user selection, but when I run the script, the value assigned to the variable is empty (""). However, if I run the class _RegisterScreen alone, it works. I hope you can show me where is my error. Thanks in advance.
Here is an abstraction (32 lines) of my code (250 lines):
import tkinter
class _MainScreen(tkinter.Frame):
def __init__(self):
self.root = tkinter.Tk()
self.new_account(self.root)
self.root.mainloop()
def new_account(self, frame):
tkinter.Button(frame, text="Create new account",
command=self.create_new_account).pack(anchor="center", pady=(0,15))
def create_new_account(self):
_RegisterScreen()
class _RegisterScreen(tkinter.Frame):
def __init__(self):
self.root = tkinter.Tk()
tkinter.Label(self.root, text="Sex").grid(row=1, padx=(0,10), sticky="w")
self.sex_option = tkinter.StringVar()
tkinter.Radiobutton(self.root, text="Male", variable=self.sex_option,
value="Male", command=self._selected).grid(row=1, column=1)
tkinter.Radiobutton(self.root, text="Female", variable=self.sex_option,
value="Female", command=self._selected).grid(row=1, column=2)
tkinter.Button(self.root, text="Submit",
command=self._login_btn_clickked).grid(row=3, columnspan=4, pady=20)
self.root.mainloop()
def _login_btn_clickked(self):
sex = self._selected()
print(sex)
def _selected(self):
return self.sex_option.get()
_MainScreen()
#_RegisterScreen() # comment the above line and uncomment this line
# to test the _RegisterScreen object alone.

After doing some research on how tkinter's RadioButton widget works, I believe I have a solution to your problem:
Here's your new _RegisterScreen function:
class _RegisterScreen(tkinter.Frame):
def __init__(self):
self.gender = "NA" #Variable to be changed upon user selection
self.root = tkinter.Tk()
tkinter.Label(self.root, text="Sex").grid(row=1, padx=(0,10), sticky="w")
self.sex_option = tkinter.StringVar()
#This Radiobutton runs the setMale function when pressed
tkinter.Radiobutton(self.root, text="Male", variable=self.sex_option,
value="Male", command=self.setMale).grid(row=1, column=1)
#This Radiobutton runs the setFemale function when pressed
tkinter.Radiobutton(self.root, text="Female", variable=self.sex_option,
value="Female", command=self.setFemale).grid(row=1, column=2)
tkinter.Button(self.root, text="Submit",
command=self._login_btn_clickked).grid(row=3, columnspan=4, pady=20)
self.root.mainloop()
def _login_btn_clickked(self):
sex = self.gender #gets the value stored in gender and assigns it to sex
print(sex)
def setMale(self):
self.gender="Male" #sets gender to Male
def setFemale(self):
self.gender="Female" #sets gender to Female
Ultimately, you want to run 2 separate functions for either RadioButton.
When the Male Radiobutton gets clicked, it runs the setMale function.
When the Female Radiobutton gets clicked, it runs the setFemale function.
I believe you were confused about what RadioButton's variable and value attributes actually are (as was I before looking further into this).
I learned more about what those those do in this video: https://www.youtube.com/watch?v=XNF-y0QFNcM
I hope this helps! ~Gunner

Related

Tkinter how update main window combobox values from Toplevel list python3.8

I have 3 modules (small, dont worry).
main_module = it has a combobox and a button. Comobobox list must be update each time a list (in module2) increases in number of names (combo values). Button calls the second window (module2)-->
myapp_second_window.py which has a entry box and another button. We write a name in the entry, push the button...voila..the list increases. In the origina app the list is created automatically when (2) is called.
Now I pass the list to a Pages.variable that is in -->
my_pages_to_connect_modules.
So, when app start I can populate combobox calling (2) to generate a Pages.variable list or populate combobox with json previously written.
The problem? --> how populate combobox while app is running. I mean, we go to (2) create a new name in entry come back to (1) and it is already there.
main_module
import tkinter as tk
from tkinter import*
from tkinter import ttk
import myapp_second_window
from myapp_second_window import SecondClass
root= Tk()
root.geometry("500x500")
root.title('myAPP_Main_Window')
class MainClass:
def __init__(self, parent,myapp_second_window):
self.parent = parent
self.my_widgets1()
def call_second_page (self):
Window2 = tk.Toplevel(root)
Window2.geometry('400x300')
myapp_second_window.SecondClass(Window2)
def my_widgets1(self):
self.field1_value = StringVar()
self.field1 = ttk.Combobox(self.parent, textvariable=self.field1_value)
self.field1['values'] = [1,2] # Pages.variable comes Here
self.field1.grid( row=0, column=0)
self.myButton = tk.Button(self.parent, text = "Call Second module", command = self.call_second_page)
self.myButton.grid(row=2, column=0)
if __name__ == '__main__':
app = MainClass(root, myapp_second_window)
root.mainloop()
myapp_second_window.py
import tkinter as tk
from tkinter import*
from tkinter import ttk
root= Tk()
root.minsize(550,450)
root.maxsize(560,460)
root.title('myAPP_Second_Window')
class SecondClass:
def init(self, parent):
self.parent = parent
self.my_widgets()
self.names = []
def my_widgets(self):
mylabel = Label(self.parent, text='Insert new name in next widget:')
mylabel.grid(column=0, row=0, sticky=W, pady=3)
button1 = tk.Button(self.parent, text="Click to enter Names in list", command=self.addToList)
button1.grid(column=3, row=0, sticky=W, pady=3)
self.name = StringVar()
valueEntry = tk.Entry(self.parent, textvariable= self.name)
valueEntry.grid(row=1, column=0, sticky=W, pady=3)
def addToList(self):
self.names.append(self.name.get())
print('listentries', self.names)
Pages.list_of_names = self.names
my_pages_to_connect_modules.
class Pages():
list_of_names = " "
It`s been challenging to me, every help is welcome. But please dont say just that I must update main window, I need to know how. Thanks to all of you.

tkinter catch value from lambda function

I'm trying to wrap my head around this problem.
Say I have a code like this:
def get_input(data_A, data_B):
all_data = [data_A.get(),dataB.get()]
return(all_data)
def the_gui():
root = Tk()
data_A = Entry(root)
data_B = Entry(root)
button = Button(root, text='Submit', command=lambda: get_input(data_A, data_B))
mainloop()
My goal is to get the value of data_A and data_B once I clicked the submit button.
I tried to use global variable and everything, but I kept failing to catch the value.
The only thing that works is when I put the whole get_input() function inside the_gui() function. However, I don't think that's a good practice to implement.
Any suggestions?
Here is a simple example of how you could write this to get the results you are looking for.
When using global is that all your root window and related fields are in a function. So you would have to define global in both function and this is not what you want to do.
Typically you will want to write the root window in the global namespace and not in a function or write it into a class so you can avoid global's all-together.
button = Button(...) may not be doing what you think it is. This does not return a value from the command once clicked. Tkinter buttons do not care about anything being returned. So you have to record that value elsewhere.
I am not sure how you code is working as you do not use geometry managers and mainloop() should be attached to the root window so I have added those in as well.
Example 1:
import tkinter as tk
def get_input():
global a_and_b
a_and_b = [data_a.get(), data_b.get()]
# If you want to keep a running record of all values submitted
# then you can do this instead:
# a_and_b.append([data_a.get(), data_b.get()])
def print_a_b():
print(a_and_b)
root = tk.Tk()
a_and_b = []
data_a = tk.Entry(root)
data_b = tk.Entry(root)
data_a.pack()
data_b.pack()
tk.Button(root, text='Submit', command=get_input).pack()
tk.Button(root, text='Print A/B List', command=print_a_b).pack()
root.mainloop()
Example 2 using OOP:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.a_and_b = []
self.data_a = tk.Entry(self)
self.data_b = tk.Entry(self)
self.data_a.pack()
self.data_b.pack()
tk.Button(self, text='Submit', command=self.get_input).pack()
tk.Button(self, text='Print A/B List', command=self.print_a_b).pack()
def get_input(self):
self.a_and_b = [self.data_a.get(), self.data_b.get()]
def print_a_b(self):
print(self.a_and_b)
if __name__ == '__main__':
App().mainloop()

Accessing Children in LabelFrames using Tkinter and Python 3

I am working with tkinter and have set up a bare bones application of my project. My objective is to retrieve a value from tk.Entry() which lies within a tk.LabelFrame() (in this code referenced by the groupbox variable). The button finds the groupbox, and the code passes the compiler, too. I guess my question is: How do I access Widgets and their values in a LabelFrame?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.master.title("Application Title")
# Introduce LabelFrame
self.groupbox = tk.LabelFrame(self, text="Parameters")
self.groupbox.grid(row=0, column=1, padx=5, pady=5)
# Test Label & Entry Widget
label = tk.Label(self.groupbox, text="label=")
label.grid(row=0, column=0, sticky="W")
entry = tk.Entry(self.groupbox)
entry.insert(0, default_value)
entry.grid(row = 0, column=1)
# Compile Button
button = tk.Button(self.groupbox, text="Compile", command=self.compile)
button.grid(row=1, column=1)
# Retrieve first Value (second Widget) from LabelFrame
def compile(self):
print(self.groupbox.entry.get(1))
if __name__ == '__main__':
figure = Application()
figure.pack()
figure.mainloop()
I am doing this because I want to perform some calculations based on the tk.Entry() values triggered by a button click which is contained in the same LabelFrame() as suggested by the code snippet above (in the original code there are a lot more widgets but that's essentially the gist of my current problem).
Change entry to self.entry.
class Application(tk.Frame):
def __init__(self, master=None):
....
self.entry = tk.Entry(self.groupbox)
self.entry.insert(0, "default_value")
self.entry.grid(row = 0, column=1)
...
# Retrieve first Value (second Widget) from LabelFrame
def compile(self):
print(self.entry.get())

tkinter: how to write a for loop to destroy a list of labels?

I am trying to remove these elements from the grid. I was able to delete all of them by writing out one by one. I then wrote a for loop to make it expandable, then I run into this error message.
"employee.destroy()
AttributeError: 'str' object has no attribute 'destroy'"
This is part of a bigger program, but as much as I can reduce to the core problem, here is my code:
import tkinter as tk
from tkinter import ttk
labelemployee={}
class Application(ttk.Frame): #inherent from frame.
def __init__(self, parent):
tk.Frame.__init__(self, parent, bg="LightBlue4")
self.parent = parent
self.Employees = ["A", "B", "C", "D"]
self.pack(fill=tk.BOTH, expand=1)
self.GUI()
def GUI(self): #the function that runs all the GUI functions.
self.buttons()
self.create_grid()
self.add_left_names()
def remove(self):
#labelemployee["A"].destroy()
#labelemployee["B"].destroy()
#labelemployee["C"].destroy()
#labelemployee["D"].destroy()
for employee in labelemployee:
employee.destroy()
def create_grid(self):
for i in range (7):
for j in range(7):
self.label = tk.Label(self, relief="ridge", width=12,
height=3)
self.label.grid(row=i, column=j, sticky='nsew')
def buttons(self):
self.button=tk.Button(self, text="Clear", bg="salmon", command
= self.remove)
self.button.grid(row=7, column=6, sticky='e')
def add_left_names(self):
#--------add in name labels on the side--------------
i=2
for employee in self.Employees:
self.label=tk.Label(self, text=employee , fg="red",
bg="snow")
self.label.grid(row=i,column=0)
labelemployee[employee]=self.label
i +=1
def main():
root = tk.Tk()
root.title("class basic window")
root.geometry("1000x500")
root.config(background="LightBlue4")
app = Application(root)
root.mainloop()
if __name__ == '__main__':
main()
Please help me. I think the problem is my for loop is stored a list, and I have a dictionary. So, then I guess i don't know how to destroy labels in a dictionary.
You have already figured out the issue in those comments !
You already know that labelemployee is a dictionary, so iterating over it will give you, by default, the keys of the dictionary. So employee will be strings like A, B... and so on. And destroying a string object will obviously give you an error. You need to destroy the corresponding tkinter widget. So for that, you should replace employee.destroy() with labelemployee[employee].destroy() in the for loop.

Why doesn't the program wait for the function result? [duplicate]

I have a tkinter class:
class DBCreatorWin():
def closeWindow(self):
tkMessageBox.showinfo("Ilmiont SQLite Database Manager", "This window cannot be closed.\nEnter a database name and press Continue.")
def returnName(self):
dbName = self.entry.get()
self.window.destroy()
return dbName
def __init__(self):
self.window = Toplevel()
self.window.transient(tkRoot)
self.window.grab_set()
self.window.resizable(width=False, height=False)
self.window.title("Ilmiont SQLite Database Manager")
self.window.protocol("WM_DELETE_WINDOW", self.closeWindow)
self.label = Label(self.window, text="Enter the name of the database to be created: ")
self.entry = Entry(self.window, width=30)
self.button = Button(self.window, text="Continue", command=self.returnName)
self.label.grid(row=0, column=0)
self.entry.grid(row=0, column=1)
self.button.grid(row=1, column=0, columnspan=2)
I want to create an instance of this class within my main code and wait for the return value. The user types a name into the entry field and presses the Continue button. At that point, the value should be returned to where the class was originally instantiated. How do I go about this? I can't seem to make it work in a normal way and am new to tkinter.
Thanks in advance,
Ilmiont
There are a couple of ways to do this. The basic idea is to use a tkinter method to wait for a specific event before returning. Tkinter provides two methods to do just that: wait_window and wait_variable. The most common method is to open a window and then wait for it to be destroyed. Some good examples can be found on the effbot site, on a page titled Dialog Windows.
Here's a simple illustration. It's not production-ready, but illustrates the general idea. At the very least you'll want to add a grab on the dialog so that you can't interact with the main window while the dialog is open, since you said you want the dialog to be modal.
import Tkinter as tk
class MyDialog(object):
def __init__(self, parent):
self.toplevel = tk.Toplevel(parent)
self.var = tk.StringVar()
label = tk.Label(self.toplevel, text="Pick something:")
om = tk.OptionMenu(self.toplevel, self.var, "one", "two","three")
button = tk.Button(self.toplevel, text="OK", command=self.toplevel.destroy)
label.pack(side="top", fill="x")
om.pack(side="top", fill="x")
button.pack()
def show(self):
self.toplevel.deiconify()
self.toplevel.wait_window()
value = self.var.get()
return value
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.button = tk.Button(self, text="Click me!", command=self.on_click)
self.label = tk.Label(self, width=80)
self.label.pack(side="top", fill="x")
self.button.pack(pady=20)
def on_click(self):
result = MyDialog(self).show()
self.label.configure(text="your result: %s" % result)
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
You can't.
The whole way the tkinter works is with callbacks. The command that you're using is the callback and you'll have to use the value inside the class. Here is an example:
def do_stuf(self):
tkMessageBox.showinfo("Foo", returnName())
....................
self.button = Button(self.window, text="Continue", command=self.do_stuff)

Resources