accessing the return value of function that was bo

2019-02-19 00:01发布

Basically, what I've done is bound a click event to a function. For example:

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

What I want now is to access the result of chooseDice() in another function. What is the best way to go about doing that?

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

3条回答
祖国的老花朵
2楼-- · 2019-02-19 00:21

Refactor. Split this into two functions.

One returns the proper result, usable by other objects.

The other is bound to a GUI control, and uses the proper result to activate and deactivate GUI objects.

Indeed, you should always do this. You should always have functions that do normal Python stuff, work correctly without the GUI and can be unit tested without the GUI. Then you connect this working "model" to the GUI.

查看更多
别忘想泡老子
3楼-- · 2019-02-19 00:28

You are already doing what you need to do. Your example code sets self.diceList to some value. Anywhere else in your code you can directly use self.diceList.

By the way -- you're writing code that is going to be hard to maintain over time. For example, what if you change the dice label to "Dice One" or simply "One" rather than "Dice 1"? Or, as your app progresses you might want graphical images instead of text on the buttons. You'll have to modify the code that parses the button name. You are essentially encoding information in a button label which is not a good idea.

A simple solution, that also makes your chooseDice method simpler and easier to understand, is to pass in the dice number in the callback. For example:

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

The above passes two parameters to the chooseDice method: the button instance (so you can disable it) and the button number (so you don't have to parse the button name to get it)

This also allows you to create your dice in a loop rather than hard-coding multiple copies of the same block of code. Here's a complete working example:

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()

Finally, some last bits of advice:

Don't use place, it makes your GUIs harder to create, and they won't react well to changes in window size, changes in font, changes in platform, etc. Use pack and grid instead. Also, don't create fixed-width buttons. Again, this is to better handle changes in fonts. There are times when you want fixed width buttons, but it doesn't look like your code has any reason to use them.

Finally, I don't know what you're actually trying to accomplish, but usually if you're using buttons to track state (is this thing pressed or not?) you want to use checkboxes (pick N of N) or radiobuttons (pick 1 of N). You might want to consider switching to those instead of to buttons.

查看更多
我命由我不由天
4楼-- · 2019-02-19 00:45

just add a self.result attribute to your class and set it at chooseDice()

查看更多
登录 后发表回答