Tkinter - 单击默认情况下未设置的按钮后无法获取单选按钮值
Posted
技术标签:
【中文标题】Tkinter - 单击默认情况下未设置的按钮后无法获取单选按钮值【英文标题】:Tkinter - Cannot get radiobutton values after clicking a button which is not set by default 【发布时间】:2022-01-14 11:02:22 【问题描述】:我正在尝试从 CSV 文件中读取内容并创建一个设置窗口,我可以在其中设置单选按钮中的新值并保存它们。为此,我创建了一个循环,该循环从 CSV 中创建 N-1
行,其内容为:
Row0;T
Row1;M
Row2;-
Row3;C
Row4;O
问题是当我尝试通过单击不同的单选按钮来获取新值时,我没有得到该值。我尝试过使用 select、invoke 方法,创建一个打印所选内容的函数,但没有返回正确的值。
我认为问题出在第 44 行和第 88 行之间
import pandas as pd
import os
from tkinter import *
import tkinter as tk
from tkinter import ttk
import platform
class Application(ttk.Frame):
def __init__(self):
root = Tk()
root.geometry("555x490")
root.resizable(0,0)
self.notebook = ttk.Notebook(root)
self.notebook.grid(sticky='news')
self.notebook.pressed_index = None
self.container = Frame(self.notebook)
self.container.grid(sticky='news')
self.notebook.add(self.container)
self.canvas = Canvas(self.container, width=530, height=470)
self.scroll = Scrollbar(self.container, command=self.canvas.yview)
self.canvas.config(yscrollcommand=self.scroll.set, scrollregion=(0,0,100,1000))
self.canvas.grid(row=0, column=0, sticky="news")
self.scroll.grid(row=0, column=1, sticky='ns')
self.frame = Frame(self.canvas, width=555, height=1000)
self.canvas_window = self.canvas.create_window(555, 500, window=self.frame)
self.container.bind("<Configure>", self.onFrameConfigure) #bind an event whenever the size of the container frame changes.
self.canvas.bind("<Configure>", self.onCanvasConfigure) #bind an event whenever the size of the canvas frame changes.
self.container.bind('<Enter>', self.onEnter) # bind wheel events when the cursor enters the control
self.container.bind('<Leave>', self.onLeave) # unbind wheel events when the cursorl leaves the control
self.onFrameConfigure(None) #perform an initial stretch on render, otherwise the self.scroll region has a tiny border until the first resize
archive = pd.read_csv(os.getcwd()+"\\test.csv", sep=';', engine='python')
y=0
self.radioInbound = []
self.radioInbound1 = []
self.radioInbound2 = []
self.radioInbound3 = []
self.radioInbound4 = []
for self.element in range(len(archive.index)):
y+=20
# El nombre de cada fila
self.label = tk.Label(self.frame, text=(str(self.element+1)+' - '+archive.iloc[self.element,0])).grid(column=20, row=y)
# Radio buttons para seleccionar el valor
self.radioInbound.append(tk.IntVar())
#print(self.radioInbound)
if archive.iloc[self.element,1] == 'M':
self.radioInbound[self.element].set(1)
elif archive.iloc[self.element,1] == 'C':
self.radioInbound[self.element].set(2)
elif archive.iloc[self.element,1] == 'O':
self.radioInbound[self.element].set(3)
else:
self.radioInbound[self.element].set(4)
# Pinta los 4 radiobutton por cada self.elemento existente en el inbound
self.radioInbound1.append(tk.Radiobutton(self.frame, text='M', variable=self.radioInbound[self.element], value=1, command=self.selected()))
self.radioInbound1[self.element].grid(column=280,row=y)
self.radioInbound2.append(tk.Radiobutton(self.frame, text='C', variable=self.radioInbound[self.element], value=2, command=self.selected()))
self.radioInbound2[self.element].grid(column=310,row=y)
self.radioInbound3.append(tk.Radiobutton(self.frame, text='O', variable=self.radioInbound[self.element], value=3, command=self.selected()))
self.radioInbound3[self.element].grid(column=340,row=y)
self.radioInbound4.append(tk.Radiobutton(self.frame, text='-', variable=self.radioInbound[self.element], value=4, command=self.selected()))
self.radioInbound4[self.element].grid(column=370,row=y)
#print(self.radioInbound1)
# Mira el valor de cada celda para invocar el radiobutton correspondiente
#if archive.iloc[self.element,1] == 'M':
# self.radioInbound1[self.element].select() ##hay que invocar al que esté en cada momento en el archivo csv
#elif archive.iloc[self.element,1] == 'C':
# self.radioInbound2[self.element].select()
#elif archive.iloc[self.element,1] == 'O':
# self.radioInbound3[self.element].select()
#else:
# self.radioInbound4[self.element].select()
#print(self.radioInbound)
root.mainloop()
def selected(self):
#print(self.radioInbound[self.element].get())
pass
def onFrameConfigure(self, event):
'''Reset the scroll region to encompass the inner frame'''
self.canvas.configure(scrollregion=self.canvas.bbox("all")) #whenever the size of the frame changes, alter the self.scroll region respectively.
def onCanvasConfigure(self, event):
'''Reset the canvas window to encompass inner frame when required'''
canvas_width = event.width
self.canvas.itemconfig(self.canvas_window, width = canvas_width) #whenever the size of the canvas changes alter the window region respectively.
def onMouseWheel(self, event): # cross platform self.scroll wheel event
if platform.system() == 'Windows':
self.canvas.yview_scroll(int(-1* (event.delta/120)), "units")
elif platform.system() == 'Darwin':
self.canvas.yview_scroll(int(-1 * event.delta), "units")
else:
if event.num == 4:
self.canvas.yview_scroll( -1, "units" )
elif event.num == 5:
self.canvas.yview_scroll( 1, "units" )
def onEnter(self, event): # bind wheel events when the cursor enters the control
if platform.system() == 'Linux':
self.canvas.bind_all("<Button-4>", self.onMouseWheel)
self.canvas.bind_all("<Button-5>", self.onMouseWheel)
else:
self.canvas.bind_all("<MouseWheel>", self.onMouseWheel)
def onLeave(self, event): # unbind wheel events when the cursorl leaves the control
if platform.system() == 'Linux':
self.canvas.unbind_all("<Button-4>")
self.canvas.unbind_all("<Button-5>")
else:
self.canvas.unbind_all("<MouseWheel>")
app = Application()
【问题讨论】:
提供minimal reproducible example 【参考方案1】:您在创建这些单选按钮的 for 循环中使用了相同的实例变量 self.element
。所以在for循环之后,self.element
会引用self.radioInbound
的最后一项。
其实实例变量self.element
是不必要的。您需要在创建这些单选按钮时使用分配给command
选项的默认值lambda
将这些单选按钮的相应索引传递给self.selected()
:
### actually don't need to inherited from ttk.Frame ###
#class Application(ttk.Frame):
class Application:
def __init__(self):
...
# just use a local variable instead of instance variable
for idx in range(len(archive.index)):
y+=20
# El nombre de cada fila
self.label = tk.Label(self.frame, text=(str(idx+1)+' - '+archive.iloc[idx,0])).grid(column=20, row=y)
# Radio buttons para seleccionar el valor
self.radioInbound.append(tk.IntVar())
#print(self.radioInbound)
if archive.iloc[idx,1] == 'M':
self.radioInbound[idx].set(1)
elif archive.iloc[idx,1] == 'C':
self.radioInbound[idx].set(2)
elif archive.iloc[idx,1] == 'O':
self.radioInbound[idx].set(3)
else:
self.radioInbound[idx].set(4)
# Pinta los 4 radiobutton por cada idxo existente en el inbound
### used lambda with argument with default value ###
self.radioInbound1.append(tk.Radiobutton(self.frame, text='M', variable=self.radioInbound[idx], value=1, command=lambda i=idx:self.selected(i)))
self.radioInbound1[idx].grid(column=280,row=y)
self.radioInbound2.append(tk.Radiobutton(self.frame, text='C', variable=self.radioInbound[idx], value=2, command=lambda i=idx:self.selected(i)))
self.radioInbound2[idx].grid(column=310,row=y)
self.radioInbound3.append(tk.Radiobutton(self.frame, text='O', variable=self.radioInbound[idx], value=3, command=lambda i=idx:self.selected(i)))
self.radioInbound3[idx].grid(column=340,row=y)
self.radioInbound4.append(tk.Radiobutton(self.frame, text='-', variable=self.radioInbound[idx], value=4, command=lambda i=idx:self.selected(i)))
self.radioInbound4[idx].grid(column=370,row=y)
...
### added argument idx ###
def selected(self, idx):
print(idx, self.radioInbound[idx].get())
...
【讨论】:
以上是关于Tkinter - 单击默认情况下未设置的按钮后无法获取单选按钮值的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有按钮单击python tkinter的情况下进入另一个页面