如何在Tkinter开发的SOS游戏中默认选中单选按钮'S'?
问题
我正在用tkinter开发SOS棋盘游戏,通过createBoard(tk.Tk)类处理游戏的GUI界面。其中playerChoice(self,game_window)函数为红、蓝两名玩家分别创建了一组可选'S'或'O'的单选按钮。我希望游戏界面创建完成后,每组单选按钮默认处于选中'S'的状态,但尝试调用.invoke()方法以及对StringVar执行.set('S')操作均未生效。playerChoice函数是在createOptionsDisplay函数中被调用的,相关代码如下:
import tkinter as tk from tkinter import ttk from tkinter.messagebox import showinfo from tkinter import font from typing import NamedTuple from itertools import cycle #game logic class class createBoard(tk.Tk): def __init__(self,game): super().__init__() self.board_win = '' self.cells = {} self.title("SOS Game") self._game = game self.createOptionsDisplay() def playerChoice(self,game_window): #Blue player label and 'S' or 'O' radio buttons. blue_player_frame = tk.Frame(game_window) blue_player_label = ttk.Label(blue_player_frame, text='Blue player') blue_player_label.grid(row = 0, column = 0) blue_var = tk.StringVar() blue_player_s_btn = ttk.Radiobutton(blue_player_frame, text = 'S', variable = blue_var, value = 'S',command=self.setS) blue_player_o_btn = ttk.Radiobutton(blue_player_frame, text = 'O', variable = blue_var, value = 'O',command=self.setO) #does not work: #blue_player_s_btn.invoke() #blue_var.set('S') blue_player_s_btn.grid(row = 1, column = 0) blue_player_o_btn.grid(row = 2, column = 0) blue_player_frame.grid(row=0,column=0) #Red player label and 'S' or 'O' radio buttons. red_player_frame = tk.Frame(game_window) red_player_label = ttk.Label(red_player_frame, text='Red player') red_player_label.grid(row = 0, column = 0) red_var = tk.StringVar() red_player_s_btn = ttk.Radiobutton(red_player_frame, text = 'S', variable = red_var, value = 'S',command=self.setS) red_player_o_btn = ttk.Radiobutton(red_player_frame, text = 'O', variable = red_var, value = 'O', command=self.setO) #does not work: #red_player_s_btn.invoke() #red_var.set('S') red_player_s_btn.grid(row = 1, column = 0) red_player_o_btn.grid(row = 2, column = 0) red_player_frame.grid(row = 0, column = 2)
解决方案
问题出在blue_var和red_var是playerChoice函数的局部变量,函数执行完毕后这两个变量会被Python垃圾回收机制销毁,导致单选按钮与StringVar的绑定关系失效,所以设置选中状态的操作无法生效。
解决方法是将这两个StringVar改为类的实例属性,让它们的生命周期与createBoard实例保持一致,具体修改如下:
- 将
blue_var = tk.StringVar()改为self.blue_var = tk.StringVar() - 将
red_var = tk.StringVar()改为self.red_var = tk.StringVar() - 在创建完单选按钮后,调用
self.blue_var.set('S')和self.red_var.set('S')设置默认选中,或者调用按钮的.invoke()方法
修改后的playerChoice函数代码:
def playerChoice(self,game_window): #Blue player label and 'S' or 'O' radio buttons. blue_player_frame = tk.Frame(game_window) blue_player_label = ttk.Label(blue_player_frame, text='Blue player') blue_player_label.grid(row = 0, column = 0) self.blue_var = tk.StringVar() blue_player_s_btn = ttk.Radiobutton(blue_player_frame, text = 'S', variable = self.blue_var, value = 'S',command=self.setS) blue_player_o_btn = ttk.Radiobutton(blue_player_frame, text = 'O', variable = self.blue_var, value = 'O',command=self.setO) # 现在可正常生效 self.blue_var.set('S') # 也可使用 blue_player_s_btn.invoke() blue_player_s_btn.grid(row = 1, column = 0) blue_player_o_btn.grid(row = 2, column = 0) blue_player_frame.grid(row=0,column=0) #Red player label and 'S' or 'O' radio buttons. red_player_frame = tk.Frame(game_window) red_player_label = ttk.Label(red_player_frame, text='Red player') red_player_label.grid(row = 0, column = 0) self.red_var = tk.StringVar() red_player_s_btn = ttk.Radiobutton(red_player_frame, text = 'S', variable = self.red_var, value = 'S',command=self.setS) red_player_o_btn = ttk.Radiobutton(red_player_frame, text = 'O', variable = self.red_var, value = 'O', command=self.setO) # 现在可正常生效 self.red_var.set('S') # 也可使用 red_player_s_btn.invoke() red_player_s_btn.grid(row = 1, column = 0) red_player_o_btn.grid(row = 2, column = 0) red_player_frame.grid(row = 0, column = 2)
修改后,StringVar会与createBoard实例绑定,不会被提前回收,设置默认选中的操作就能正常生效。
内容的提问来源于stack exchange,提问作者mikedoorhandle
相关产品推荐
相关产品推荐

