I'm building a GUI with Tkinter in Python and I'm having trouble with radio buttons. I have two radio buttons in a LabelFrame widget and I'm using a StringVar to track the selected value. However, when I run the program, both radio buttons are initially unselected, but after a few seconds both become selected. Additionally, changes to the selected value are not always reflected in the GUI.
Here is my code:
import tkinter as tk
class MenuSettings:
def __init__(self, parent, settings):
window = tk.Toplevel(parent)
window.title("settings")
database_frame = tk.LabelFrame(
window, text="choose drive: ", font=("Arial", 12))
database_frame.pack(fill=tk.X, padx=10, pady=10)
database_var = tk.StringVar(value=settings.db_path)
database_radio_g = tk.Radiobutton(
database_frame, text="G:", value="PATH_G", variable=database_var,
font=("Arial", 12))
database_radio_g.pack(side="left", padx=10)
database_radio_server = tk.Radiobutton(
database_frame, text="Server", value="PATH_SERVER", variable=database_var,
font=("Arial", 12))
database_radio_server.pack(side="left", padx=10)
#-----------------------------------------------------------------------------
# following code is necessary
#-----------------------------------------------------------------------------
#def on_database_var_changed(*args):
# print('database_var changed:', database_var.get())
#database_var.trace('w', on_database_var_changed)
from wotan.CLS import cls
settings = cls.Settings.getInstance()
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.title("Application")
self.configure(background='black')
self._show_menu_settings()
def _show_menu_settings(self):
settings_window=MenuSettings(self, settings)
def main():
app = Application()
app.mainloop()
if __name__ == '__main__':
main()
settings
is a singleton class to read some variables from a locally stored textfile.
Trace statement incl. function is commented out in class MenuSettings
I've tried several things, such as setting the value option for the radio buttons, removing other parts of my code to isolate the issue, use window.update() and window.update_idletasks(), but nothing seems to work.
The only solution I found is to add a trace with a function to print the StringVar, which is not an ideal solution for an App. Does anyone have any suggestions for how to fix this issue?
You need to use instance variable on database_var
(in MenuSettings
) and settings_window
(in Application
) to avoid garbage collection:
class MenuSettings:
def __init__(self, parent, settings):
...
# use instance variable
self.database_var = tk.StringVar(value=settings.db_path)
database_radio_g = tk.Radiobutton(
database_frame, text="G:", value="PATH_G", variable=self.database_var,
font=("Arial", 12))
database_radio_g.pack(side="left", padx=10)
database_radio_server = tk.Radiobutton(
database_frame, text="Server", value="PATH_SERVER", variable=self.database_var,
font=("Arial", 12))
database_radio_server.pack(side="left", padx=10)
...
class Application(tk.Tk):
...
def _show_menu_settings(self):
# use instance variable
self.settings_window = MenuSettings(self, settings)
...
I would suggest that MenuSettings
inherits form tk.Toplevel
instead, then you don't need to use instance variable on settings_window
.