【问题标题】:How to write button callback?如何编写按钮回调?
【发布时间】:2012-10-26 09:27:46
【问题描述】:

下面是我用来用按钮制作棋盘的代码。

from Tkinter import *

for x in xrange(8):
    for y in xrange(8:
        if((x+y)%2 == 0):
            Button(root, bg="white", width=11, height=5).grid(row=y, column=x)
        else:
            Button(root, bg="black", width=11, height=5).grid(row=y, column=x)

我知道如何为单个按钮创建回调函数,但我不确定如何为这 64 个按钮中的每一个实现回调函数,以便在按下时返回它们在网格中的位置.

【问题讨论】:

标签: python user-interface button callback tkinter


【解决方案1】:
def callback(event):
   x,y = event.widget.grid_location()

这个例子应该为你指明正确的方向。

更新: 为了澄清 grid_location 的用法,我做了一个快速的谷歌搜索,发现...SO-post ;-) 通过更直接的way 提供您所需的解决方案,这让我感到羞耻:

grid_info = event.widget.grid_info()
print "row:", grid_info["row"], "column:", grid_info["column"]

所以应该归功于 Bryan Oakley ;-) 这个问题可能被称为重复...

【讨论】:

  • 我不太确定在这种情况下应该是什么事件。抱歉这个看似愚蠢的问题。
  • 您的回调从作为参数传递的调用小部件中获取“事件”!你不需要做任何事情,它就在那里!这就是应该如何使用回调进行事件处理。我应该进一步指出,我的代码不完整 - 网格位置需要 (x,y) 格式的像素位置,这也可以由例如提供。事件或 event.widget 属性
【解决方案2】:

尝试将每个按钮的 x 和 y 值绑定到可以在按下按钮时调用处理函数的 lambda。现在您有了每个按钮按下的 x 和 y 位置。

def handlebuttonpress(x,y):
  print 'Button x-{0} y-{1} pressed'.format(x,y)

width, height = 8, 8
for x in xrange(width):
  for y in xrange(height):
    if((x+y)%2 == 0):
        Button(root, command=lambda x=x, y=y: handlebuttonpress(x,y), bg="white", width=11, height=5).grid(row=y, column=x)
    else:
        Button(root, command=lambda x=x, y=y: handlebuttonpress(x,y), bg="black", width=11, height=5).grid(row=y, column=x)

【讨论】:

  • 应该是lambda x=x, y=y: ...,它会在按钮创建时绑定x和y的值。
  • @BryanOakley - 太棒了,正是我想要的。
【解决方案3】:

编辑:我认为我更喜欢@DonQuestion 的基于事件的方法,因为它不需要为每个按钮提供不同的功能。

下面我已经修改了我的原始代码以使用

    master.bind("<Button-1>", self.onclick)

对鼠标点击做出反应(而不是使用tk.Button(command = ...)


import Tkinter as tk

class ButtonEventBlock(object):
    # http://stackoverflow.com/a/6102759/190597
    def __init__(self, master, names, cols):
        self.names = names
        self.cols = cols
        self.button = []
        for i, name in enumerate(names):
            self.button.append(tk.Button(master, text = name))
            row, col = divmod(i, self.cols)
            self.button[i].grid(sticky = tk.W+tk.E+tk.N+tk.S,
                                row = row, column = col, padx = 1, pady = 1)
        master.bind("<Button-1>", self.onclick)

    def onclick(self, event):
        info = event.widget.grid_info()        
        # print(info)
        # {'rowspan': '1', 'column': '3', 'sticky': 'nesw', 'ipady': '0', 'ipadx':
        # '0', 'columnspan': '1', 'in': <Tkinter.Tk instance at 0xab3d7ec>,
        # 'pady': '1', 'padx': '1', 'row': '0'}
        row, col = [int(info[key]) for key in ['row', 'column']]
        i = self.cols*row + col
        print(row, col, self.names[i])

names = ('One', 'Two', 'Three', 'Four', 'Five',
         'Six', 'Seven', 'Eight', 'Nine', 'Ten')

root = tk.Tk()
ButtonEventBlock(root, names, cols = 5)
root.mainloop()

【讨论】:

  • 使用bind 不如使用内置的command 属性。例如,按钮具有用于键盘遍历的内置行为,它不适用于绑定。此外,command 属性尊重小部件的状态(如果小部件被禁用,则命令不会触发)也许这些功能对于此特定应用程序并不重要,但对于查看此解决方案的其他人可能很重要.
  • @BryanOakley:我预计 OP 最终会希望将按钮更改为 Canvas 上的棋子图像。然后,他希望能够将图像拖动到新的网格位置以移动棋子。所以我认为基于bind 的解决方案将更好地满足他未来的需求。
  • 可能是这样,但是这个特定的问题是关于按钮的,其他人会来这里寻找如何在循环中创建按钮回调的答案。如果您的答案更适合解决画布上的项目,请将其作为答案的一部分。就目前而言,在专门讨论按钮时,绑定是次要的选择。
  • @BryanOakley:我给出了一个我认为对 OP 最有帮助的答案。您对可能访问此问题的其他人的关注是合理的。由于您对 Tkinter 有很多了解,请积极写下答案,以便我们都可以向您学习。
猜你喜欢
  • 2011-04-09
  • 2014-03-28
  • 2018-05-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-12
  • 2011-03-27
  • 2011-01-30
  • 2014-12-20
相关资源
最近更新 更多