如何在 python tkinter 中使用多个单选按钮?
How do I use multiple Radiobuttons in python tkinter?
我已经在这里挣扎够久了。我需要一些指导。
我正在尝试制作一个字节生成器 GUI。 95% 工作正常,但我无法保留单选按钮 on/off 一旦我点击它们。
我在一个循环中创建了 64 个按钮,为变量赋值,并创建了一个回调函数。
在回调函数中,我单击一个按钮,然后调用 update_array,更新列表和文本字节数组。这些值从 0 到 1 来回切换。工作正常,但按钮不会保留 on/highlighted。我什至不确定我是否应该使用其他按钮类型。
最终结果是按钮数组,字节数组应该显示相同的模式。
我也在尝试获取我单击的按钮的标识。 (Btn_XY) 当我点击 Btn_44 时我知道,但是我如何从 tkinter 中找到它?
运行 python3.8 在 MacBook Pro 版本 10.15.5
GUI 选项卡 1 显示按钮和字节映射。
回调函数为 def btnCall(self)
按钮是在第 280 行到第 293 行创建的。函数 def btnCall 和 def update_array 确实看起来工作正常。即使它们不完整 - 那里的部分仍在工作。我可以稍后将列表保存到全局列表。
在整个展示过程和调试过程中打印语句。
有什么建议吗????提前致谢!
import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext
from tkinter import Menu
from tkinter import messagebox as msg
class CHAR_GEN():
def __init__(self): # Initializer method
# Create instance
self.win = tk.Tk()
# Add a title
self.win.title("Character Generator GUI")
self.create_widgets()
#create the byte array for the byte map
self.create_byte_array()
# Modified Button Click Function
def click_me(self):
self.action.configure(text='Hello ' + self.name.get() + ' ' +
self.number_chosen.get())
# GUI Callback
def checkCallback(self, *ignored_args):
# only enable one checkbutton
if self.chVarUn.get(): self.check3.configure(state='disabled')
else: self.check3.configure(state='normal')
if self.chVarEn.get(): self.check2.configure(state='disabled')
else: self.check2.configure(state='normal')
def create_byte_array(self):
print('Create the array')
self.byte_array = []
for row in range(8):
self.byte_array.append([])
for col in range(8):
self.byte_array[row].append(0)
#############
self.byte_box.insert(tk.END, '\n\n byte_array = { \n')
print(self.byte_array)
for row in range(8):
#self.byte_array[row].append(0)
print(''.join(map(str, self.byte_array[row])))
msg = ''.join(map(str, self.byte_array[row]))
#############
self.byte_box.insert(tk.END, ' ')
self.byte_box.insert(tk.END, msg)
self.byte_box.insert(tk.END, '\n')
self.byte_box.insert(tk.END, ' }\n')
#############
#############
return self.byte_array
########################################################
# The byte_array is just a structure. We will print a
# text representation of it in the text box and
# refresh it every time the update or create fuction is called
########################################################
def update_array(self,row,col):
print('in update array row and col passed == {} {}'.format(row,col))
print('the variable self.byte_array[row][col] == {}'.format(self.byte_array[row][col]))
print('in update_array this is where we toggle the bit in the list')
if self.byte_array[row][col] == 0:
self.byte_array[row][col] = 1
else:
self.byte_array[row][col] = 0
#############
#############
#############
print('ready to print to text box')
print(self.byte_array)
# delete the text in the box
self.byte_box.delete('1.0',tk.END)
#redraw
self.byte_box.insert(tk.END, '\n\n byte_array = { \n')
for row in range(8):
print(''.join(map(str, self.byte_array[row])))
msg = ''.join(map(str, self.byte_array[row]))
#############
self.byte_box.insert(tk.END, ' ')
self.byte_box.insert(tk.END, msg)
self.byte_box.insert(tk.END, '\n')
self.byte_box.insert(tk.END, ' }\n')
#############
#############
#############
#############
#####################################
#####################################
# Build a list for all the radVars
#####################################
# Radiobutton Callback
def btnCall(self):
print('entered btnCall')
print('this is where we clicked the button')
btnVar = self.radVar.get()
print('in btnCall btnVar == {}'.format(btnVar))
###
s = str(btnVar)
#print(s)
if len(s) == 1:
xpos = str(0)
ypos = s
else:
xpos = s[-2]
ypos = s[-1]
print('in btnCall xpos,ypos == {}{}'.format(xpos,ypos))
print('leaving btnCall() and calling self.update_array')
self.update_array(int(xpos),int(ypos))
#####################################
#####################################
#####################################
# reset the pixel map
def reset_map(self):
#delete map
#turn off all the radio buttons
#create map
pass
def invert_map(self):
#delete map
#toggle the bits in the map
#create map
pass
# Exit GUI cleanly
def _quit(self):
self.win.quit()
self.win.destroy()
exit()
#####################################################################################
def create_widgets(self):
tabControl = ttk.Notebook(self.win) # Create Tab Control
tab1 = ttk.Frame(tabControl) # Add a second tab
tabControl.add(tab1, text='Tab 1') # Make second tab visible
tab2 = ttk.Frame(tabControl) # Create a tab
tabControl.add(tab2, text='Tab 2') # Add the tab
tabControl.pack(expand=1, fill="both") # Pack to make visible
# Top of Tab Control 2 -------------------------------------------
# We are creating a container frame to hold all other widgets -- Tab2
self.pixmap = ttk.LabelFrame(tab1, text=' Pixels')
self.pixmap.grid(column=0, row=0, padx=8, pady=4)
self.map_frame = ttk.LabelFrame(self.pixmap, text=' Pixel Map ')
self.map_frame.grid(column=0, row=2, sticky='W', columnspan=2)
## Add a textbox frame to hold the character array
self.byte_frame = ttk.LabelFrame(tab1, text=' Bytes ')
self.byte_frame.grid(column=1, row=0, sticky='W', columnspan=2)
# Creating three checkbuttons
self.chVarDis = tk.IntVar()
self.check1 = tk.Checkbutton(self.pixmap, text="Disabled", variable=self.chVarDis, state='disabled')
self.check1.select()
self.check1.grid(column=0, row=0, sticky=tk.W)
#
self.chVarUn = tk.IntVar()
self.check2 = tk.Checkbutton(self.pixmap, text="Junk", variable=self.chVarUn)
self.check2.deselect()
self.check2.grid(column=1, row=0, sticky=tk.W)
#
self.chVarEn = tk.IntVar()
self.check3 = tk.Checkbutton(self.pixmap, text="Save", variable=self.chVarEn)
self.check3.deselect()
self.check3.grid(column=2, row=0, sticky=tk.W)
# trace the state of the two checkbuttons
self.chVarUn.trace('w', lambda unused0, unused1, unused2 : self.checkCallback())
print('self.chVarUn == {}'.format(self.chVarUn))
self.chVarEn.trace('w', lambda unused0, unused1, unused2 : self.checkCallback())
#print('self.chVarEn == {}'.format(self.chVarEn))
#####################################################################
#
# create a text box to hold the bytes
#
#####################################################################
self. byte_box = tk.Text(self.byte_frame, height=12, width=20)
self.byte_box.grid(column=0, row=0, sticky=tk.E)
#self.byte_box.insert(tk.END, "Just a text Widget\nin two lines\n")
#self.byte_box.insert(tk.END, '\n\n byte_array = { \n')
# First, we change our Radiobutton global variables into a list
# create three Radiobuttons using one variable
self.radVar = tk.IntVar()
# Next we are selecting a non-existing index value for radVar
self.radVar.set(99)
# Now we are creating all three Radiobutton widgets within one loop
# create a temp dictionary to build the radio buttones ????????
##########################
# build a function to create 64 of these radio buttons.
# later !!!
##########################
#####################################################################
#
# create a text box to hold the bytes
#
#####################################################################
self. byte_box = tk.Text(self.byte_frame, height=12, width=20)
self.byte_box.grid(column=0, row=0, sticky=tk.E)
#self.byte_box.insert(tk.END, "Just a text Widget\nin two lines\n")
#self.byte_box.insert(tk.END, '\n\n byte_array = { \n')
# create 64 Radiobuttons using one variable
self.radVar = tk.IntVar()
# Next we are selecting a non-existing index value for radVar
self.radVar.set(99)
# Now we are creating all three Radiobutton widgets within one loop
# create a temp dictionary to build the radio buttones
##########################
# build a function to create 64 of these radio buttons.
# later !!!
##########################
##########################
# here are all the radio buttons
##########################
##########################
##########################
'''
Here we will use a double loop to greate the radio buttons
and later the variables. The numbers in the loop will
be appended to Btn_XY where XY is the row and column.
Also use the numbers for naming radVar for each button
Also use the numbers for naming row and column
'''
##########################
##########################
bname = "Btn_"
for x in range(8):
for y in range(8):
#print(x,y)
#print(bname + str(x) + str(y))
cr_name = bname + str(x) + str(y)
print('in creation loop cr_name == {}'.format(cr_name))
######
# need to create a simple SMALL box above eache of these
# to toggle on and off
self.cr_name = tk.Radiobutton(self.map_frame, variable=self.radVar, val = int(str(x)+str(y)), command=self.btnCall)
self.cr_name.grid(column=y+1, row=x+1, sticky=tk.W)
##########################
# create another frame container
###############################################################
###############################################################
# Create a container to hold misc buttons
misc_buttons_frame = ttk.LabelFrame(self.pixmap, text=' Modify ')
misc_buttons_frame.grid(column=0, row=3, sticky='W', columnspan=2)
# create another frame container
###############################################################
###############################################################
###############################################################
# Add Buttons for reset and invert commands
ttk.Button(misc_buttons_frame, text=" Reset Map", command=self.reset_map).grid(column=0, row=0, sticky='W')
ttk.Button(misc_buttons_frame, text=" Invert Map ", command=self.invert_map).grid(column=1, row=0, sticky='W')
#
for child in misc_buttons_frame.winfo_children():
child.grid_configure(padx=2, pady=2)
#
for child in self.pixmap.winfo_children():
child.grid_configure(padx=8, pady=2)
# Creating a Menu Bar
menu_bar = Menu(self.win)
self.win.config(menu=menu_bar)
# Add menu items
file_menu = Menu(menu_bar, tearoff=0)
file_menu.add_command(label="New")
file_menu.add_separator()
file_menu.add_command(label="Exit", command=self._quit)
menu_bar.add_cascade(label="File", menu=file_menu)
# Display a Message Box
# Add another Menu to the Menu Bar and an item
help_menu = Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="Help", menu=help_menu)
# Change the main windows icon
# self.win.iconbitmap('pyc.ico')
self.check3.focus()
# Start GUI
oop = CHAR_GEN()
oop.win.mainloop(
)
Radiobutton
的目的是在一组中只选择一个。
您应该为您的程序使用 Checkbutton
。
在您的程序中,您从不使用包含 X/Y 的 cr_name
来标识按钮。
如何保存 CheckButton 并在以后访问它们的值的示例:
from tkinter import *
root = Tk()
bits = []
btn = []
for i in range(10): #Populates a list as a replacement for your actual inputs
bits.append("btn"+str(i))
for i in range(len(bits)):
#print text by referencing itself from the list where buttons are stored
btn.append(Checkbutton(root, text=bits[i], command=lambda c=i: print(btn[c].cget("text"))))
btn[i].pack() #pack the buttons
root.mainloop()
我最终为列表中的每个复选按钮创建了变量,就像复选按钮一样。代码太多无法显示,但 Nico 上面提供的建议使我走上了正确的轨道。
感谢所有提供帮助的人。
抱歉,如果下面的缩进失败。我发帖不多。
============================================= =
for i in range(len(blst)):
print(i)
self.vars.append(tk.IntVar())
#print text by referencing itself from the list where buttons are stored
self.btn.append(tk.Checkbutton(self.map_frame,text=blst[i],variable=lambda c=i:self.vars[i],command=lambda c=i: self.press(self.btn[c].cget("text"),self.vars[i])))
self.btn[i].grid(column=int(blst[i][1]), row =int(blst[i][0]),sticky=tk.W)
我已经在这里挣扎够久了。我需要一些指导。
我正在尝试制作一个字节生成器 GUI。 95% 工作正常,但我无法保留单选按钮 on/off 一旦我点击它们。
我在一个循环中创建了 64 个按钮,为变量赋值,并创建了一个回调函数。
在回调函数中,我单击一个按钮,然后调用 update_array,更新列表和文本字节数组。这些值从 0 到 1 来回切换。工作正常,但按钮不会保留 on/highlighted。我什至不确定我是否应该使用其他按钮类型。
最终结果是按钮数组,字节数组应该显示相同的模式。
我也在尝试获取我单击的按钮的标识。 (Btn_XY) 当我点击 Btn_44 时我知道,但是我如何从 tkinter 中找到它?
运行 python3.8 在 MacBook Pro 版本 10.15.5
GUI 选项卡 1 显示按钮和字节映射。
回调函数为 def btnCall(self)
按钮是在第 280 行到第 293 行创建的。函数 def btnCall 和 def update_array 确实看起来工作正常。即使它们不完整 - 那里的部分仍在工作。我可以稍后将列表保存到全局列表。
在整个展示过程和调试过程中打印语句。
有什么建议吗????提前致谢!
import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext
from tkinter import Menu
from tkinter import messagebox as msg
class CHAR_GEN():
def __init__(self): # Initializer method
# Create instance
self.win = tk.Tk()
# Add a title
self.win.title("Character Generator GUI")
self.create_widgets()
#create the byte array for the byte map
self.create_byte_array()
# Modified Button Click Function
def click_me(self):
self.action.configure(text='Hello ' + self.name.get() + ' ' +
self.number_chosen.get())
# GUI Callback
def checkCallback(self, *ignored_args):
# only enable one checkbutton
if self.chVarUn.get(): self.check3.configure(state='disabled')
else: self.check3.configure(state='normal')
if self.chVarEn.get(): self.check2.configure(state='disabled')
else: self.check2.configure(state='normal')
def create_byte_array(self):
print('Create the array')
self.byte_array = []
for row in range(8):
self.byte_array.append([])
for col in range(8):
self.byte_array[row].append(0)
#############
self.byte_box.insert(tk.END, '\n\n byte_array = { \n')
print(self.byte_array)
for row in range(8):
#self.byte_array[row].append(0)
print(''.join(map(str, self.byte_array[row])))
msg = ''.join(map(str, self.byte_array[row]))
#############
self.byte_box.insert(tk.END, ' ')
self.byte_box.insert(tk.END, msg)
self.byte_box.insert(tk.END, '\n')
self.byte_box.insert(tk.END, ' }\n')
#############
#############
return self.byte_array
########################################################
# The byte_array is just a structure. We will print a
# text representation of it in the text box and
# refresh it every time the update or create fuction is called
########################################################
def update_array(self,row,col):
print('in update array row and col passed == {} {}'.format(row,col))
print('the variable self.byte_array[row][col] == {}'.format(self.byte_array[row][col]))
print('in update_array this is where we toggle the bit in the list')
if self.byte_array[row][col] == 0:
self.byte_array[row][col] = 1
else:
self.byte_array[row][col] = 0
#############
#############
#############
print('ready to print to text box')
print(self.byte_array)
# delete the text in the box
self.byte_box.delete('1.0',tk.END)
#redraw
self.byte_box.insert(tk.END, '\n\n byte_array = { \n')
for row in range(8):
print(''.join(map(str, self.byte_array[row])))
msg = ''.join(map(str, self.byte_array[row]))
#############
self.byte_box.insert(tk.END, ' ')
self.byte_box.insert(tk.END, msg)
self.byte_box.insert(tk.END, '\n')
self.byte_box.insert(tk.END, ' }\n')
#############
#############
#############
#############
#####################################
#####################################
# Build a list for all the radVars
#####################################
# Radiobutton Callback
def btnCall(self):
print('entered btnCall')
print('this is where we clicked the button')
btnVar = self.radVar.get()
print('in btnCall btnVar == {}'.format(btnVar))
###
s = str(btnVar)
#print(s)
if len(s) == 1:
xpos = str(0)
ypos = s
else:
xpos = s[-2]
ypos = s[-1]
print('in btnCall xpos,ypos == {}{}'.format(xpos,ypos))
print('leaving btnCall() and calling self.update_array')
self.update_array(int(xpos),int(ypos))
#####################################
#####################################
#####################################
# reset the pixel map
def reset_map(self):
#delete map
#turn off all the radio buttons
#create map
pass
def invert_map(self):
#delete map
#toggle the bits in the map
#create map
pass
# Exit GUI cleanly
def _quit(self):
self.win.quit()
self.win.destroy()
exit()
#####################################################################################
def create_widgets(self):
tabControl = ttk.Notebook(self.win) # Create Tab Control
tab1 = ttk.Frame(tabControl) # Add a second tab
tabControl.add(tab1, text='Tab 1') # Make second tab visible
tab2 = ttk.Frame(tabControl) # Create a tab
tabControl.add(tab2, text='Tab 2') # Add the tab
tabControl.pack(expand=1, fill="both") # Pack to make visible
# Top of Tab Control 2 -------------------------------------------
# We are creating a container frame to hold all other widgets -- Tab2
self.pixmap = ttk.LabelFrame(tab1, text=' Pixels')
self.pixmap.grid(column=0, row=0, padx=8, pady=4)
self.map_frame = ttk.LabelFrame(self.pixmap, text=' Pixel Map ')
self.map_frame.grid(column=0, row=2, sticky='W', columnspan=2)
## Add a textbox frame to hold the character array
self.byte_frame = ttk.LabelFrame(tab1, text=' Bytes ')
self.byte_frame.grid(column=1, row=0, sticky='W', columnspan=2)
# Creating three checkbuttons
self.chVarDis = tk.IntVar()
self.check1 = tk.Checkbutton(self.pixmap, text="Disabled", variable=self.chVarDis, state='disabled')
self.check1.select()
self.check1.grid(column=0, row=0, sticky=tk.W)
#
self.chVarUn = tk.IntVar()
self.check2 = tk.Checkbutton(self.pixmap, text="Junk", variable=self.chVarUn)
self.check2.deselect()
self.check2.grid(column=1, row=0, sticky=tk.W)
#
self.chVarEn = tk.IntVar()
self.check3 = tk.Checkbutton(self.pixmap, text="Save", variable=self.chVarEn)
self.check3.deselect()
self.check3.grid(column=2, row=0, sticky=tk.W)
# trace the state of the two checkbuttons
self.chVarUn.trace('w', lambda unused0, unused1, unused2 : self.checkCallback())
print('self.chVarUn == {}'.format(self.chVarUn))
self.chVarEn.trace('w', lambda unused0, unused1, unused2 : self.checkCallback())
#print('self.chVarEn == {}'.format(self.chVarEn))
#####################################################################
#
# create a text box to hold the bytes
#
#####################################################################
self. byte_box = tk.Text(self.byte_frame, height=12, width=20)
self.byte_box.grid(column=0, row=0, sticky=tk.E)
#self.byte_box.insert(tk.END, "Just a text Widget\nin two lines\n")
#self.byte_box.insert(tk.END, '\n\n byte_array = { \n')
# First, we change our Radiobutton global variables into a list
# create three Radiobuttons using one variable
self.radVar = tk.IntVar()
# Next we are selecting a non-existing index value for radVar
self.radVar.set(99)
# Now we are creating all three Radiobutton widgets within one loop
# create a temp dictionary to build the radio buttones ????????
##########################
# build a function to create 64 of these radio buttons.
# later !!!
##########################
#####################################################################
#
# create a text box to hold the bytes
#
#####################################################################
self. byte_box = tk.Text(self.byte_frame, height=12, width=20)
self.byte_box.grid(column=0, row=0, sticky=tk.E)
#self.byte_box.insert(tk.END, "Just a text Widget\nin two lines\n")
#self.byte_box.insert(tk.END, '\n\n byte_array = { \n')
# create 64 Radiobuttons using one variable
self.radVar = tk.IntVar()
# Next we are selecting a non-existing index value for radVar
self.radVar.set(99)
# Now we are creating all three Radiobutton widgets within one loop
# create a temp dictionary to build the radio buttones
##########################
# build a function to create 64 of these radio buttons.
# later !!!
##########################
##########################
# here are all the radio buttons
##########################
##########################
##########################
'''
Here we will use a double loop to greate the radio buttons
and later the variables. The numbers in the loop will
be appended to Btn_XY where XY is the row and column.
Also use the numbers for naming radVar for each button
Also use the numbers for naming row and column
'''
##########################
##########################
bname = "Btn_"
for x in range(8):
for y in range(8):
#print(x,y)
#print(bname + str(x) + str(y))
cr_name = bname + str(x) + str(y)
print('in creation loop cr_name == {}'.format(cr_name))
######
# need to create a simple SMALL box above eache of these
# to toggle on and off
self.cr_name = tk.Radiobutton(self.map_frame, variable=self.radVar, val = int(str(x)+str(y)), command=self.btnCall)
self.cr_name.grid(column=y+1, row=x+1, sticky=tk.W)
##########################
# create another frame container
###############################################################
###############################################################
# Create a container to hold misc buttons
misc_buttons_frame = ttk.LabelFrame(self.pixmap, text=' Modify ')
misc_buttons_frame.grid(column=0, row=3, sticky='W', columnspan=2)
# create another frame container
###############################################################
###############################################################
###############################################################
# Add Buttons for reset and invert commands
ttk.Button(misc_buttons_frame, text=" Reset Map", command=self.reset_map).grid(column=0, row=0, sticky='W')
ttk.Button(misc_buttons_frame, text=" Invert Map ", command=self.invert_map).grid(column=1, row=0, sticky='W')
#
for child in misc_buttons_frame.winfo_children():
child.grid_configure(padx=2, pady=2)
#
for child in self.pixmap.winfo_children():
child.grid_configure(padx=8, pady=2)
# Creating a Menu Bar
menu_bar = Menu(self.win)
self.win.config(menu=menu_bar)
# Add menu items
file_menu = Menu(menu_bar, tearoff=0)
file_menu.add_command(label="New")
file_menu.add_separator()
file_menu.add_command(label="Exit", command=self._quit)
menu_bar.add_cascade(label="File", menu=file_menu)
# Display a Message Box
# Add another Menu to the Menu Bar and an item
help_menu = Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="Help", menu=help_menu)
# Change the main windows icon
# self.win.iconbitmap('pyc.ico')
self.check3.focus()
# Start GUI
oop = CHAR_GEN()
oop.win.mainloop(
)
Radiobutton
的目的是在一组中只选择一个。
您应该为您的程序使用 Checkbutton
。
在您的程序中,您从不使用包含 X/Y 的 cr_name
来标识按钮。
如何保存 CheckButton 并在以后访问它们的值的示例:
from tkinter import *
root = Tk()
bits = []
btn = []
for i in range(10): #Populates a list as a replacement for your actual inputs
bits.append("btn"+str(i))
for i in range(len(bits)):
#print text by referencing itself from the list where buttons are stored
btn.append(Checkbutton(root, text=bits[i], command=lambda c=i: print(btn[c].cget("text"))))
btn[i].pack() #pack the buttons
root.mainloop()
我最终为列表中的每个复选按钮创建了变量,就像复选按钮一样。代码太多无法显示,但 Nico 上面提供的建议使我走上了正确的轨道。
感谢所有提供帮助的人。
抱歉,如果下面的缩进失败。我发帖不多。
============================================= =
for i in range(len(blst)):
print(i)
self.vars.append(tk.IntVar())
#print text by referencing itself from the list where buttons are stored
self.btn.append(tk.Checkbutton(self.map_frame,text=blst[i],variable=lambda c=i:self.vars[i],command=lambda c=i: self.press(self.btn[c].cget("text"),self.vars[i])))
self.btn[i].grid(column=int(blst[i][1]), row =int(blst[i][0]),sticky=tk.W)