回调函数未定义

时间:2018-04-01 04:29:55

标签: python user-interface tkinter

我正在尝试学习如何使用Python中的tkinter进行GUI,并且我收到错误,我的回调函数未定义。基本上我想要一个白色方块网格,当你点击方块时它会变成红色。

from tkinter import *

root = Tk()

class Application(Frame):
    def __init__(self, master, *args, **kwargs):
        Frame.__init__(self, master, *args, ** kwargs)
        self.createWidgets()

    def mouse_click(self):
        self.squares.bg = 'red'

    def createWidgets(self):
        for i in range(10):
            for j in range(10):
                self.squares = Button(self, height = 3, width = 7, bg = 'white',
                                      command = lambda: mouse_click())
                self.squares.grid(row = i, column = j)

Application(root).grid()
root.mainloop()

2 个答案:

答案 0 :(得分:2)

您的代码中存在多个问题。

  1. mouse_click是一个实例方法,因此必须引用为self.mouse_click
  2. 你在循环的每次迭代中都覆盖self.squares,所以最后它会引用你创建的最后一个按钮。这没用,可以删除。
  3. 解决此问题的简洁方法是重写mouse_click方法以将按钮作为参数:

    def mouse_click(self, square):
        square['bg'] = 'red'
    

    然后为每个按钮的command函数提供对按钮本身的引用。这可以通过functools.partial

    完成
    def createWidgets(self):
        for i in range(10):
            for j in range(10):
                square = Button(self, height = 3, width = 7, bg = 'white')
                square['command'] = functools.partial(self.mouse_click, square)
                square.grid(row = i, column = j)
    

    这使得按钮的click事件处理程序接收按钮作为参数。通过这两个更改,一切都按预期工作。

答案 1 :(得分:1)

您需要使用ommand = lambda: self.mouse_click()

然而,这并没有解决所有问题。另一个问题是你正在创建一个2D网格按钮,但只存储你班级中的最后一个按钮。

该行

                self.squares = Button(...)

只存储一个按钮。您最终将句柄存储到最后Button。您在之前的步骤中创建的其他Button将丢失给您的班级。

这是我的建议(未经核实):

class Application(Frame):
   def __init__(self, master, *args, **kwargs):
      Frame.__init__(self, master, *args, ** kwargs)
      self.createWidgets()

   def mouse_click(self, i, j):
      self.squares[i][j].bg = 'red'

   def createWidgets(self):

      # Creeate a 2D array that contains None in all the elements.
      self.squares = [[None for x in range(10)] for y in range(10)]

      # Fill up the array.
      for i in range(10):
         for j in range(10):
            # Create a button and display it in the i-th row and j-th
            # column in a grid.
            button = Button(self,
                            height = 3,
                            width = 7,
                            bg = 'white',
                            command = lambda: self.mouse_click(i, j))
            button.grid(row = i, column = j)

            # Store the button for the callback function
            self.squares[i][j] = button