【问题标题】:Make tkinter buttons for every item in a list?为列表中的每个项目制作 tkinter 按钮?
【发布时间】:2014-03-11 09:09:28
【问题描述】:

我想制作一些按钮,其中包含从数据库返回的项目列表,它们都调用传入列表项的函数。类似这段代码的东西,但它有效。这段代码的问题是所有按钮都使用'item3' 调用该函数。

#!/usr/bin/env python
from Tkinter import *
root = Tk()
def func(name):
    print name
mylist = ['item1','item2','item3']
for item in mylist:
    button = Button(root,text=item,command=lambda:func(item))
button.pack()

root.mainloop()

【问题讨论】:

  • 您的代码中的缩进是否正确?

标签: python python-2.7 tkinter


【解决方案1】:

这里有两件事:

  1. 您需要将以下行缩进一级:

    button.pack()
    

    目前,您只有在最后一个按钮上调用 pack 方法。进行此更改将导致为每个按钮调用它。

  2. 所有按钮都将'item3' 发送到func,因为这是item 的当前值。重要的是要记住,由 lambda 函数包围的表达式是在 运行时 计算的,而不是在编译时计算的。

    但是,同样重要的是要记住,函数的参数及其默认值(如果有)都是在编译时而不是运行时计算的。

    这意味着您可以通过为 lambda 提供一个默认值设置为 item 的参数来解决此问题。这样做将为 for 循环的每次迭代“捕获”item 的值。

以下是解决这些问题的脚本版本:

from Tkinter import *
root = Tk()
def func(name):
    print name
mylist = ['item1', 'item2', 'item3']
for item in mylist:
    button = Button(root, text=item, command=lambda x=item: func(x))
    button.pack()

root.mainloop()

【讨论】:

    【解决方案2】:

    你应该使用functools.partial:

    import functools
    from Tkinter import *
    
    root = Tk()
    def func(name):
        print name
    mylist = ['item1','item2','item3']
    for item in mylist:
        button = Button(root,text=item,command=functools.partial(func,item))
        button.pack()
    
    root.mainloop()
    

    【讨论】:

      【解决方案3】:

      相同的逻辑,但这是创建计算器的示例。只显示,不计算。这里我使用了 grid() 而不是 pack()。

      import tkinter
      
      main_window = tkinter.Tk()
      main_window.title("Calculator")
      main_window.geometry('500x500+550+200')
      main_window['padx'] = 8
      
      main_window.columnconfigure(0, weight=1)
      main_window.columnconfigure(1, weight=1)
      main_window.columnconfigure(2, weight=1)
      main_window.columnconfigure(3, weight=1)
      main_window.columnconfigure(4, weight=1)
      main_window.columnconfigure(5, weight=1)
      
      main_window.rowconfigure(0, weight=1)
      main_window.rowconfigure(1, weight=1)
      main_window.rowconfigure(2, weight=1)
      main_window.rowconfigure(3, weight=1)
      main_window.rowconfigure(4, weight=1)
      main_window.rowconfigure(5, weight=1)
      main_window.rowconfigure(6, weight=1)
      main_window.rowconfigure(7, weight=1)
      
      title_label = tkinter.Label(main_window, text="Calculator")
      title_label.grid(row=0, columnspan=6)
      
      number_entry = tkinter.Entry(main_window)
      number_entry.grid(row=1, columnspan=4, sticky='nwes')
      
      button_list = [('C', 'E'),
                     ('7', '8', '9', '+'),
                     ('4', '5', '6', '-'),
                     ('1', '2', '3', '*'),
                     ('0', '=', '/')]
      
      for outer_num, outer_val in enumerate(button_list):
      
          for inner_num, inner_val in enumerate(outer_val):
              x = 1
              y = inner_num
              if inner_val == "=":
                  x = 2
              if inner_val == "/":
                  y += 1
              tkinter.Button(main_window, text=inner_val).grid(row=outer_num + 2, column=y, columnspan=x,
                                                               sticky='news')
      
      main_window.mainloop()
      

      【讨论】: