Python - tkinter 小部件数组随着单选按钮的点击而变化
Python - arrays of tkinter widgets changing with radiobutton clicks
我正在使用 tkinter 在 Python 中开发 GUI。我正在读取一个文本文件并根据文本文件中的行动态创建 GUI 元素。我的每种元素类型都有一个数组,其中包括标签、单选按钮变量 (StringVars) 和彩色圆圈(用 create_oval 绘制)。我的目标是,当用户将单选按钮从 "not assigned" 更改为 "in" 或 "out" 时,该行上的彩色圆圈将从黄色变为绿色。以下是读取文本文件后 GUI 的显示方式:
项目 1:(o) in () out () 未分配 (G)
项目 2: () in () out (o) 未分配 (Y)
目前,我在单选按钮 StringVars 上有一个跟踪,这样我就可以在其中一个按钮发生变化时调用一个方法。我的问题是找出更改了哪个单选按钮,以便我可以更改该行上圆圈的颜色...
我目前正在将整个单选按钮 StringVar 数组复制到一个临时全局数组中。当跟踪函数被调用时,我将临时数组与数组中当前的内容进行比较,以确定变化在哪里。我复制数组:temp_radiobutton_vars = list(radiobutton_vars),但我不确定这是否是正确的路线。当我 get() StringVar 时,我的临时列表和当前列表始终显示相同的结果,即使在我更改按钮之后也是如此。关于如何解决这个问题的任何想法,或者也许有更好的方法来做我想做的事情...
抱歉,解释冗长且不够好。如果有人需要更多信息或代码片段,请告诉我。谢谢!
有很多方法可以解决这个问题。由于您已经在使用变量跟踪,也许最简单的解决方案是将 canvas 项目的索引传递给回调。您可以使用 lambda
或 functools.partial
来完成此任务。您也可以不使用变量跟踪,而是将命令与每个单选按钮相关联。在这两种情况下,您只需告诉回调要对哪个索引进行操作。
在以下示例中,回调采用对变量的引用和 canvas 项目的索引。它获取值,在 table 中查找颜色,然后配置 canvas 项:
def on_radiobutton(var, index):
value = var.get()
color = {"in": "green", "out": "red", "unassigned": "yellow"}
self.canvas.itemconfigure(index, fill=color[value])
这是使用 lambda 设置跟踪的方式(请注意,name1
、name2
和 op
由 tkinter 为每个跟踪自动发送):
var = tk.StringVar()
rb0 = tk.Radiobutton(..., variable=var, value="in", text="in")
rb1 = tk.Radiobutton(..., variable=var, value="out", text="out")
rb2 = tk.Radiobutton(..., variable=var, value="unassigned", text="not assigned")
var.trace("w", lambda name1, name2, op, index=i, var=var:
on_radiobutton(var, index))
听起来你对 Radiobuttons
的想法是错误的。所有 "connected" Radiobuttons
应该具有相同的 variable
值;这样,您可以调用 theVariable.get()
并将其与每个 Radiobutton
的 value
进行比较;您不需要引用每个 Radiobutton
;你也不应该为每个 Radiobutton
设置一个 StringVar
,只有每一行。
编辑:我扩展了我的例子来展示它如何适用于多行。所有改变的是现在我检查我在回调中传递了哪一行,并使用它我知道要更新哪一行(在你的情况下,canvas 颜色)。这只是一些二维列表处理,用于根据发出回调的线路检查选择了哪个 Radiobutton
。
from Tkinter import *
root = Tk()
root.geometry("300x200+500+400")
lines = [StringVar(), StringVar()]
strings = [["Hello", "Stack", "Overflow"], ["Whats", "Going", "On"]]
buttons = [[],[]]
l1 = Label(root, text = "Selection: ", justify = LEFT)
l1.grid(column = 0, row = 0, sticky = NW, padx = (0, 250))
l1.grid_propagate(False)
l2 = Label(root, text = "Selection: ", justify = LEFT)
l2.grid(column = 0, row = 4, sticky = NW, padx = (0, 250))
l2.grid_propagate(False)
def process(line):
global l1, l2, strings, lines
if line == lines[0]:
# Since lines[0] was passed in to the callback, we know to update line 0;
# take that line's label (or canvas in your case)
updateLine = 0
updateLabel = l1
else:
# Otherwise take the other line
updateLine = 1
updateLabel = l2
# These operations are performed within if/elif/else to show how you coul
# choose a different process for each Radiobutton: example, coloring a canvas differently
if lines[updateLine].get() == strings[updateLine][0]:
# This means the first button of whatever line was selected
updateLabel.config(text = "Selection: %s" %strings[updateLine][0])
elif lines[updateLine].get() == strings[updateLine][1]:
# This means the second button of whatever line was selected
updateLabel.config(text = "Selection: %s" %strings[updateLine][1])
else:
# You get the idea
updateLabel.config(text = "Selection: Bet you thought I'd say %s" %strings[updateLine][2])
# Must have a seperate row number because with multiple lines, we can't simply use 'i' or 'j'
rowNum = 1
for i in range(len(lines)):
for j in range(len(strings[i])):
buttons[i].append(Radiobutton(root, text = strings[i][j], variable = lines[i], value = strings[i][j], command = lambda line = lines[i]: process(line)))
buttons[i][j].grid(column = 0, row = rowNum, sticky = NW)
rowNum +=1
rowNum += 2
root.mainloop()
我正在使用 tkinter 在 Python 中开发 GUI。我正在读取一个文本文件并根据文本文件中的行动态创建 GUI 元素。我的每种元素类型都有一个数组,其中包括标签、单选按钮变量 (StringVars) 和彩色圆圈(用 create_oval 绘制)。我的目标是,当用户将单选按钮从 "not assigned" 更改为 "in" 或 "out" 时,该行上的彩色圆圈将从黄色变为绿色。以下是读取文本文件后 GUI 的显示方式:
项目 1:(o) in () out () 未分配 (G)
项目 2: () in () out (o) 未分配 (Y)
目前,我在单选按钮 StringVars 上有一个跟踪,这样我就可以在其中一个按钮发生变化时调用一个方法。我的问题是找出更改了哪个单选按钮,以便我可以更改该行上圆圈的颜色...
我目前正在将整个单选按钮 StringVar 数组复制到一个临时全局数组中。当跟踪函数被调用时,我将临时数组与数组中当前的内容进行比较,以确定变化在哪里。我复制数组:temp_radiobutton_vars = list(radiobutton_vars),但我不确定这是否是正确的路线。当我 get() StringVar 时,我的临时列表和当前列表始终显示相同的结果,即使在我更改按钮之后也是如此。关于如何解决这个问题的任何想法,或者也许有更好的方法来做我想做的事情...
抱歉,解释冗长且不够好。如果有人需要更多信息或代码片段,请告诉我。谢谢!
有很多方法可以解决这个问题。由于您已经在使用变量跟踪,也许最简单的解决方案是将 canvas 项目的索引传递给回调。您可以使用 lambda
或 functools.partial
来完成此任务。您也可以不使用变量跟踪,而是将命令与每个单选按钮相关联。在这两种情况下,您只需告诉回调要对哪个索引进行操作。
在以下示例中,回调采用对变量的引用和 canvas 项目的索引。它获取值,在 table 中查找颜色,然后配置 canvas 项:
def on_radiobutton(var, index):
value = var.get()
color = {"in": "green", "out": "red", "unassigned": "yellow"}
self.canvas.itemconfigure(index, fill=color[value])
这是使用 lambda 设置跟踪的方式(请注意,name1
、name2
和 op
由 tkinter 为每个跟踪自动发送):
var = tk.StringVar()
rb0 = tk.Radiobutton(..., variable=var, value="in", text="in")
rb1 = tk.Radiobutton(..., variable=var, value="out", text="out")
rb2 = tk.Radiobutton(..., variable=var, value="unassigned", text="not assigned")
var.trace("w", lambda name1, name2, op, index=i, var=var:
on_radiobutton(var, index))
听起来你对 Radiobuttons
的想法是错误的。所有 "connected" Radiobuttons
应该具有相同的 variable
值;这样,您可以调用 theVariable.get()
并将其与每个 Radiobutton
的 value
进行比较;您不需要引用每个 Radiobutton
;你也不应该为每个 Radiobutton
设置一个 StringVar
,只有每一行。
编辑:我扩展了我的例子来展示它如何适用于多行。所有改变的是现在我检查我在回调中传递了哪一行,并使用它我知道要更新哪一行(在你的情况下,canvas 颜色)。这只是一些二维列表处理,用于根据发出回调的线路检查选择了哪个 Radiobutton
。
from Tkinter import *
root = Tk()
root.geometry("300x200+500+400")
lines = [StringVar(), StringVar()]
strings = [["Hello", "Stack", "Overflow"], ["Whats", "Going", "On"]]
buttons = [[],[]]
l1 = Label(root, text = "Selection: ", justify = LEFT)
l1.grid(column = 0, row = 0, sticky = NW, padx = (0, 250))
l1.grid_propagate(False)
l2 = Label(root, text = "Selection: ", justify = LEFT)
l2.grid(column = 0, row = 4, sticky = NW, padx = (0, 250))
l2.grid_propagate(False)
def process(line):
global l1, l2, strings, lines
if line == lines[0]:
# Since lines[0] was passed in to the callback, we know to update line 0;
# take that line's label (or canvas in your case)
updateLine = 0
updateLabel = l1
else:
# Otherwise take the other line
updateLine = 1
updateLabel = l2
# These operations are performed within if/elif/else to show how you coul
# choose a different process for each Radiobutton: example, coloring a canvas differently
if lines[updateLine].get() == strings[updateLine][0]:
# This means the first button of whatever line was selected
updateLabel.config(text = "Selection: %s" %strings[updateLine][0])
elif lines[updateLine].get() == strings[updateLine][1]:
# This means the second button of whatever line was selected
updateLabel.config(text = "Selection: %s" %strings[updateLine][1])
else:
# You get the idea
updateLabel.config(text = "Selection: Bet you thought I'd say %s" %strings[updateLine][2])
# Must have a seperate row number because with multiple lines, we can't simply use 'i' or 'j'
rowNum = 1
for i in range(len(lines)):
for j in range(len(strings[i])):
buttons[i].append(Radiobutton(root, text = strings[i][j], variable = lines[i], value = strings[i][j], command = lambda line = lines[i]: process(line)))
buttons[i][j].grid(column = 0, row = rowNum, sticky = NW)
rowNum +=1
rowNum += 2
root.mainloop()