Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Josh Keenan
Josh Keenan
19,652 Points

Tkinter Button problem

So what I'm doing is placing 35 buttons in a grid, each using a function called function (inventive right?).

In tkinter to make a button work you can't use parentheses when setting the command, otherwise it runs as soon as the program starts, I need to use them and obviously the code runs instantly.

Anyone know how to stop this?

    def function(self, text):
        print (text)

    def mock_fill(self, row, col, text):
        #temp = tkinter.Label(
         #   self.mainframe,
        #    bg='grey',
         #   text=text,
        #    fg='black',
          #  font=('Helvetica', 10)
        #)

        temp = tkinter.Button(
            self.mainframe,
            text=text,
            command=self.function(text)
        )

        temp.grid(
            row=row, column=col,
            sticky='ew',  # East West
            padx=10, pady=10
        )

Thanks :)

Chris Freeman
Chris Freeman
Treehouse Moderator 68,423 Points

Can I assume mock_fill isn't intended to be indented to be a method of function?

Josh Keenan
Josh Keenan
19,652 Points

Yes that is an indentation error when copying in to treehouse, my bad!

2 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,423 Points

Good. Because I plan to make function a method of mock_fill....

    def mock_fill(self, row, col, text):
        # temp = tkinter.Label(
        #    self.mainframe,
        #    bg='grey',
        #    text=text,
        #    fg='black',
        #    font=('Helvetica', 10)
        # )

        def function(self):  # <-- note drop of param 'text'
            print (text)  # 'text' becomes an encapsulated global for 'function'

        temp = tkinter.Button(
            self.mainframe,
            text=text,
            command=function  # <-- reference local function
        )

        temp.grid(
            row=row, column=col,
            sticky='ew',  # East West
            padx=10, pady=10
        )

To see this in practice:

$ python3
Python 3.4.0 (default, Jun 19 2015, 14:20:21) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class MockItAll():
...     def mock_fill(self, row, col, text):
...         def funct():
...             print(text)
...         setattr(self, "mock_{}_{}".format(row, col), funct)
... 
>>> mock_all = MockItAll()
# Create function as an attribute to call later
>>> mock_all.mock_fill(0, 0, "zero-zero")
>>> mock_all.mock_0_0
<function MockItAll.mock_fill.<locals>.funct at 0x7fa9d63af730>
# Call function
>>> mock_all.mock_0_0()
zero-zero
# Create 2nd function
>>> mock_all.mock_fill(0, 1, "zero-one")
>>> mock_all.mock_0_1
<function MockItAll.mock_fill.<locals>.funct at 0x7fa9d63af840>
# Call second function
>>> mock_all.mock_0_1()
zero-one
Josh Keenan
Josh Keenan
19,652 Points

I swear one day I will be as good as you! Thanks as always Chris! :)

Josh Keenan
Josh Keenan
19,652 Points

Had to drop the self from function in my IDE, weird huh? But it all works, thanks a lot!