【问题标题】:accessing the return value of function that was bound to an event (tkinter)访问绑定到事件的函数的返回值(tkinter)
【发布时间】:2011-06-02 02:02:09
【问题描述】:

基本上,我所做的是将点击事件绑定到函数。例如:

self.button1.bind("<Button-1>",self.chooseDice)

我现在想要的是在另一个函数中访问chooseDice() 的结果。这样做的最佳方法是什么?

class GraphicsInterface:

    #we want to initialize the game board here, set up the dice and buttons
    def __init__(self):
        self.window = Tk()
        self.window.geometry("720x500")

        #buttons under each die
        self.clicked=[] #empty list to collect all the buttons that were clicked (see chooseDice function)
        self.button1 = Button(self.window, text="Dice 1", width=13) #create the button object
        self.button1.place(x=60, y=160)  
        #bind button click event to a function (chooseDice())
        self.button1.bind("<Button-1>",self.chooseDice)

        self.button2 = Button(self.window, text="Dice 2", width=13)
        self.button2.place(x=185, y=160)
        self.button2.bind("<Button-1>",self.chooseDice)

    #using the event as an argument, append the text to the clicked list
    def chooseDice(self, event):
        self.clicked.append(event.widget.cget('text'))
        self.diceList=[] #create a new empty list
        for i in range(len(self.clicked)):
            self.diceList.append(int(self.clicked[i][5])) #get just the int value of the last character (i.e. the dice number)
        self.deactivate(event.widget)  #deactivate the button
        return self.diceList

【问题讨论】:

    标签: python events tkinter bind


    【解决方案1】:

    你已经在做你需要做的事了。您的示例代码将 self.diceList 设置为某个值。您可以在代码中的任何其他地方直接使用self.diceList

    顺便说一句——您正在编写的代码随着时间的推移将难以维护。例如,如果您将骰子标签更改为“Dice One”或只是“One”而不是“Dice 1”怎么办?或者,随着您的应用程序的进展,您可能需要图形图像而不是按钮上的文本。您必须修改解析按钮名称的代码。您实际上是在按钮标签中编码信息,这不是一个好主意。

    一个简单的解决方案,也使您的chooseDice 方法更简单和更容易理解,是在回调中传递骰子编号。例如:

    self.button1.configure(command=lambda btn=self.button1: self.chooseDice(btn, 1))
    

    上面将两个参数传递给chooseDice方法:按钮实例(这样你可以禁用它)和按钮编号(这样你就不必解析按钮名称来获取它)

    这还允许您在循环中创建骰子,而不是对同一代码块的多个副本进行硬编码。这是一个完整的工作示例:

    from Tkinter import *
    
    class GraphicsInterface:
    
        def __init__(self):
            self.window = Tk()
            self.window.geometry("720x500")
            self.clicked=[] 
            self.buttons = []
    
            for n in range(1, 3):
                btn = Button(text="Button " + str(n))
                btn.configure(command=lambda btn=btn, n=n: self.chooseDice(btn, n))
                btn.pack()
                self.buttons.append(btn)
    
            btn = Button(text="Go!", command=self.go)
            btn.pack()
            self.window.mainloop()
    
    
        def go(self):
            print "buttons:", self.clicked
            self.reset()
    
        def reset(self):
            '''Reset all the buttons'''
            self.clicked = []
            for button in self.buttons:
                button.configure(state="normal")
    
        def chooseDice(self, widget, number):
            self.clicked.append(number)
            widget.configure(state="disabled")
    
    app = GraphicsInterface()
    

    最后,最后一点建议:

    不要使用place,它会让你的GUI更难创建,而且它们对窗口大小的变化、字体的变化、平台的变化等反应不佳。使用packgrid反而。另外,不要创建固定宽度的按钮。同样,这是为了更好地处理字体的变化。有时您需要固定宽度的按钮,但您的代码似乎没有任何理由使用它们。

    最后,我不知道你实际上想要完成什么,但通常如果你使用按钮来跟踪状态(这个东西是否按下?)你想使用复选框(从 N 中选择 N)或单选按钮(从 N 中选择 1 个)。您可能需要考虑切换到那些而不是按钮。

    【讨论】:

    • 非常感谢您的意见!但是,即使采用您的方法,我的问题仍然存在。首先,正如你所说,我不能在我的代码中的其他任何地方使用“self.diceList”。如果我尝试,它只是说 AttributeError:'GraphicsInterface' 对象没有属性 'diceList'。基本上,我需要做的是将单击的按钮名称列表传递给我的实际应用程序类,但我无法弄清楚如何执行此操作,因为我无法使用常规参数调用我的“chooseDice”函数, 对?按钮是否有某种方法可以告诉我是否单击了按钮?
    • @sq1020:你没有理解我的代码是如何工作的。它传入小部件的名称和骰子编号。您可以随心所欲地存储它。我的代码将号码存储在 self.clicked 中。您可以轻松地存储小部件名称、小部件文本或小部件对象本身。不要只是盲目地复制我的代码,从中学习。它向您展示了如何将您想要的任何信息传递给您的方法。您传递什么信息以及如何处理这些信息完全取决于您。
    • @sq1020:这是你需要做的:在构造函数中添加self.diceList = [],在chooseDice方法中添加self.diceList.append(widget.cget("text"))。另外,将self.diceList = [] 放入reset 方法中。就是这么简单。
    • 我理解你的代码,我可以通过self.clicked 列表很好。我遇到的问题是,当我尝试访问另一个类中的列表时,它返回一个空白列表,即它不等待用户单击。它只需要原始的self.clicked=[]。关于如何让我的应用程序类等到列表包含至少三个项目或类似内容的任何提示?再次感谢您的帮助:)
    • @sq1020:很遗憾,我无法提供任何其他建议。没有技术限制,您的代码中只是有错误。没有看到您的代码,就不可能看到问题所在。
    【解决方案2】:

    只需将self.result 属性添加到您的类并将其设置为chooseDice()

    【讨论】:

      【解决方案3】:

      重构。将其拆分为两个函数。

      一个返回正确的结果,可供其他对象使用。

      另一个绑定到一个 GUI 控件,并使用正确的结果来激活和停用 GUI 对象。

      确实,您应该始终这样做。您应该始终拥有执行普通 Python 工作的函数,在没有 GUI 的情况下正常工作,并且可以在没有 GUI 的情况下进行单元测试。然后将这个工作“模型”连接到 GUI。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-24
        • 1970-01-01
        • 2013-08-15
        • 2011-12-19
        • 2017-02-26
        相关资源
        最近更新 更多