基于Tkinter实现类似EasyGUI buttonbox的选择框函数,解决无法返回选中值问题
Hey there! Let's break down why your mychoicebox isn't returning the selected value when you click "Done" and how to fix it.
The Problem with Your Current Code
Your buttonfn callback just returns var.get(), but Tkinter command functions don't pass return values back to the parent function. Plus, your window stays open (since you never destroy it), so choicewin.mainloop() keeps running indefinitely—your function never gets to the point where it can return anything to the reply variable.
The Solution
We need two key changes:
- Store the selected value in a mutable object (like a list) so the callback can modify it and the parent function can access it.
- Close the window when "Done" is clicked, which will exit the mainloop and let the function return the selected value.
Here's the revised code:
from tkinter import * def mychoicebox(choicelist): # Use a list to store the result (mutable objects let us modify values across scopes) selected_value = [None] def on_done_click(): # Save the selected option selected_value[0] = var.get() # Close the window to exit the mainloop choicewin.destroy() choicewin = Tk() choicewin.resizable(False, False) choicewin.title("ChoiceBox") # Add the prompt label Label(choicewin, text="Select an item:").grid(row=0, column=0, sticky="W") # Set up the dropdown menu var = StringVar(choicewin) # Set default to first item if choicelist isn't empty, else "No data" var.set(choicelist[0] if choicelist else 'No data') popupMenu = OptionMenu(choicewin, var, *choicelist) popupMenu.grid(sticky=N+S+E+W, row=1, column=0) # Add the Done button with our updated callback Button(choicewin, text='Done', command=on_done_click).grid(row=2, column=0) # Start the GUI loop choicewin.mainloop() # Return the selected value once the window closes return selected_value[0]
How It Works
- Mutable Storage: We use
selected_value = [None]because lists are mutable. If we used a regular variable, the callback would treat it as a local variable instead of modifying the parent function's variable. - Close the Window:
choicewin.destroy()shuts down the GUI window, which exitsmainloop(). This lets the function proceed to thereturnstatement, passing the selected value back to yourreplyvariable. - Better Default: We updated the default value to use the first item in
choicelist(if it exists) instead of always showing "No data"—this makes the UI more intuitive.
Test It Out
Run your test code again:
reply = mychoicebox(['one','two','three']) print("reply:", reply)
Now when you select an option and click "Done", the window will close, and you'll see your selected value printed in the console.
Bonus Alternative: Using wait_window
If you prefer, you can use wait_window() instead of relying on mainloop() directly. This waits for the window to be destroyed before proceeding, which works similarly:
def mychoicebox(choicelist): selected_value = [None] def on_done_click(): selected_value[0] = var.get() choicewin.destroy() choicewin = Tk() choicewin.resizable(False, False) choicewin.title("ChoiceBox") Label(choicewin, text="Select an item:").grid(row=0, column=0, sticky="W") var = StringVar(choicewin) var.set(choicelist[0] if choicelist else 'No data') popupMenu = OptionMenu(choicewin, var, *choicelist) popupMenu.grid(sticky=N+S+E+W, row=1, column=0) Button(choicewin, text='Done', command=on_done_click).grid(row=2, column=0) # Wait until the window is destroyed before returning choicewin.wait_window(choicewin) return selected_value[0]
内容的提问来源于stack exchange,提问作者rnso

