Tkinter的Radiobutton在Toplevel窗口中无法正常工作。

huangapple go评论56阅读模式
英文:

Tkinter Radiobuttons not working properly in Toplevel window

问题

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)

        #-----------------------------------------------------------------------
        # The 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 the MenuSettings class.

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?

英文:

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?

答案1

得分: 2

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):
        ...
        # 使用实例变量
        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):
        # 使用实例变量
        self.settings_window = MenuSettings(self, settings)
...

I would suggest that MenuSettings inherits from tk.Toplevel, then you don't need to use an instance variable on settings_window.

英文:

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.

huangapple
  • 本文由 发表于 2023年4月20日 00:46:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76056995.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定