【问题标题】:Python - arrays of tkinter widgets changing with radiobutton clicksPython - tkinter 小部件的数组随着单选按钮的点击而变化
【发布时间】:2015-10-07 06:52:09
【问题描述】:

我正在使用 tkinter 在 Python 中开发 GUI。我正在读取一个文本文件并根据文本文件中的行动态创建 GUI 元素。我的每种元素类型都有一个数组,其中包括标签、单选按钮变量 (StringVars) 和彩色圆圈(使用 create_oval 绘制)。我的目标是,当用户将单选按钮从“未分配”更改为“输入”或“输出”时,该行上的彩色圆圈将从黄色变为绿色。以下是文本文件读入后 GUI 的外观:

第1项:(o)in()out()未分配(G)

第2项:() in () out (o) not assignment (Y)

目前,我在单选按钮 StringVars 上有一个跟踪,以便在更改其中一个按钮时调用一个方法。我的问题是找出更改了哪个单选按钮,以便我可以更改该行上圆圈的颜色...

我目前正在将整个单选按钮 StringVar 数组复制到一个临时全局数组中。当调用跟踪函数时,我将临时数组与当前数组中的内容进行比较,以找出变化的位置。我将数组复制为:temp_radiobutton_vars = list(radiobutton_vars),但我不确定这是否是正确的路线。当我 get() StringVar 时,我的临时列表和当前列表总是显示相同的结果,即使在我更改了按钮之后也是如此。关于如何解决这个问题的任何想法,或者也许有更好的方法来做我想做的事情......

抱歉,解释太长了。如果有人需要更多信息或代码的 sn-ps,请告诉我。谢谢!

【问题讨论】:

    标签: python arrays user-interface tkinter radio-button


    【解决方案1】:

    有很多方法可以解决这个问题。由于您已经在使用变量跟踪,也许最简单的解决方案是将画布项的索引传递给回调。您可以使用 lambdafunctools.partial 执行此任务。您也可以不使用变量跟踪,而是将命令与每个单选按钮相关联。在这两种情况下,您只需要告诉回调要操作哪个索引。

    在以下示例中,回调采用对变量的引用和对画布项的索引。它获取值,在表格中查找颜色,然后配置画布项:

    def on_radiobutton(var, index):
        value = var.get()
        color = {"in": "green", "out": "red", "unassigned": "yellow"}
        self.canvas.itemconfigure(index, fill=color[value])
    

    这是使用 lambda 设置跟踪的方式(注意 name1name2op 由 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))
    

    【讨论】:

      【解决方案2】:

      听起来你对Radiobuttons 有错误的想法。所有“已连接”的Radiobuttons 应该具有相同的variable 值;这样,你就可以调用theVariable.get()并与每个Radiobuttonvalue进行比较;您不需要对每个 Radiobutton 的引用;每个Radiobutton 也不应该有一个StringVar,只有每一行。

      编辑:我已经扩展了我的示例,以展示这如何适用于多行。所有改变的是现在我检查我在回调中传递了哪一行,并使用它知道要更新哪一行(在你的情况下,要为哪一个画布着色)。根据发出回调的行来检查选择了哪个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()
      

      【讨论】:

      • 很好的例子,感谢您的帮助!很高兴有一个完整的程序,我可以运行它来看看一切是如何工作的。
      猜你喜欢
      • 1970-01-01
      • 2018-09-15
      • 2020-01-14
      • 1970-01-01
      • 2022-09-24
      • 1970-01-01
      • 2021-12-05
      • 2011-09-09
      • 1970-01-01
      相关资源
      最近更新 更多