0

i was creating a python tic tac toe game and I'm currently getting the error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python34\lib\tkinter\__init__.py", line 1482, in __call__
    return self.func(*args)
  File "E:\Workspace\TTT3\src\ttt3.py", line 33, in <lambda>
    self._nwButton = Button(self, image = self.blankPhoto, command = lambda:checker(self._northwest))
  File "E:\Workspace\TTT3\src\ttt3.py", line 13, in checker
     if buttons["image"] == "self.blankPhoto" and xTurn == True:
TypeError: 'method' object is not subscriptable

I'm not sure what it means exactly, but this is the code I have currently:

from tkinter import *
from PIL import Image, ImageTk
'''xTurn determines whos turn it is, game starts out with X's turn'''
xTurn = True

def checker(buttons):
    global xTurn
    if buttons["image"] == "self.blankPhoto" and xTurn == True:
        print("X's turn")
        xTurn = False
    elif buttons["image"] == "self.blankPhoto" and xTurn == False:
        print("O's turn")
        xTurn = True


class tttGUI(Frame):
    def __init__(self):

       '''Setup GUI'''
       Frame.__init__(self)
       self.master.title("Tic-Tac-Toe GUI")
       self.grid()

       self.buttons = StringVar()

       self.blankPhoto = PhotoImage(file = "blank.gif")

       self._nwButton = Button(self, image = self.blankPhoto, command = lambda:checker(self._northwest))
       self._nwButton.grid(row = 0, column = 0)

       self._nButton = Button(self, image = self.blankPhoto, command = lambda:checker(self._north))
       self._nButton.grid(row = 0, column = 1)

       self._neButton = Button(self, image = self.blankPhoto, command = lambda:checker(self._northeast))
       self._neButton.grid(row = 0, column = 2)

       self._wButton = Button(self, image = self.blankPhoto, command = lambda:checker(self._west))
       self._wButton.grid(row = 1, column = 0)

       self._cButton = Button(self, image = self.blankPhoto, command = lambda:checker(self._center))
       self._cButton.grid(row = 1, column = 1)

       self._eButton = Button(self, image = self.blankPhoto, command = lambda:checker(self._east))
       self._eButton.grid(row = 1, column = 2)

       self._swButton = Button(self, image = self.blankPhoto, command = lambda:checker(self._southwest))
       self._swButton.grid(row = 2, column = 0)

       self._sButton = Button(self, image = self.blankPhoto, command = lambda:checker(self._south))
       self._sButton.grid(row = 2, column = 1)

       self._seButton = Button(self, image = self.blankPhoto, command = lambda:checker(self._southeast))
       self._seButton.grid(row = 2, column = 2)

    '''Buttons'''
    def _northwest(self):
        print("North-West")


    def _north(self):
        print("North")

    def _northeast(self):
        print("North-East")

    def _west(self):
        print("West")

    def _center(self):
        print("Center")

   def _east(self):
       print("East")

   def _southwest(self):
       print("South-West")

   def _south(self):
       print("South")

   def _southeast(self):
       print("South-East")

def main():
    tttGUI().mainloop()

main()

I am trying to make a GUI pop up and whenever you click on one of the buttons it will change to an X or an O depending on whose turn it is.

Jacob Ess
  • 13
  • 2

1 Answers1

1

As your python says, you are passing the method self._something to the function checker().

Button( ..., command = lambda: checker(self._northwest))

And the methods self._northwest, self._north, ... are not 'subscriptable' object, which means you can't do

self._northwest[...]

So python fails to evaluate 'if buttons['image'] == ...' and prints that error message.

Besides, according to your code, checker() wants a instance of tkinter.Button as an argument, which is subscriptable. So you may have to pass one of your buttons (self._...Button) to the function.

hunminpark
  • 214
  • 3
  • 10
  • Yes. Try to fix the Button definitions like "self._nwButton = Button( ..., command = lambda: checker(self._nwButton))". If you wrote checker() (and other parts of the program) correctly, the program may work. – hunminpark May 09 '16 at 21:49
  • For further information, see http://stackoverflow.com/questions/216972/in-python-what-does-it-mean-if-an-object-is-subscriptable-or-not . – hunminpark May 09 '16 at 21:54
  • If I am not supposed to do `self._nwButton = Button( ..., command = lambda: checker(self._nwButton))` how else am I supposed to do it. Sorry I am being oblivious, I just don't really understand what you are telling me. – Jacob Ess May 09 '16 at 21:58
  • Ok so I tried doing `self._nwButton = Button( ..., command = lambda: checker(self.buttons))` and it gives me the error `TypeError: 'StringVar' object is not subscriptable` – Jacob Ess May 09 '16 at 22:08
  • Also tried doing `checker(self._..Button)` and no errors but printing anything out. – Jacob Ess May 09 '16 at 22:15
  • @JacobEss It's because two print(...) statements inside checker() are not executed, which means that the conditional statements in 'if ...' and 'elif ...' became False. – hunminpark May 09 '16 at 22:30
  • Now let's analyze the reason. If you put "print(self._nwButton['image'])" after "self._nwButton.grid(row = 0, column = 0)", you'll see the program prints 'blank.gif'. That means (Button instance)['image'] gives the **name** of the image ('blank.gif'), not the attribute name "self.blankPhoto". Try to replace buttons['image'] == 'self.blankPhoto' to buttons['image'] == 'blank,gif' in checker(). I confirmed that it works in my computer. – hunminpark May 09 '16 at 22:30
  • Odd, mine prints out pyimage1 – Jacob Ess May 09 '16 at 22:35
  • @huminpark so that seems to have worked, but now my button images are not updating. – Jacob Ess May 09 '16 at 22:55