Changing Variables Within A Function In Tkinter
Solution 1:
The problem here is that the XsorOs
object gets created every time you call the XorO
method. This means XsorOs.turn
is always 1.
One way would be to keep track of turn
from outside and call it with global
but the use
of global is something one should avoid especially it can get quite messy.
I would recommend keeping track of turn
within an own child class of Tk separate "logic" class
I made you an example for the latter:
(please note that this example is super sloppy (particularly the variable naming) and should just show you what I meant)
# stays the same until 'line4 = canvas.create_line(0, 400, 600, 400)'classXsorOs:
def__init__(self):
self.turn = 1defclick(self, row, col):
if self.turn is (1or3or5or7or9):
canvas.create_line(col * third, row * third, (col + 1) * third, (row + 1) * third)
canvas.create_line((col + 1) * third, row * third, col * third, (row + 1) * third)
else:
canvas.create_oval(col * third + 5, row * third + 5, (col + 1) * third - 5, (row + 1) * third - 5)
self.turn += 1defmouse_click(c, event):
col = int(event.x / third)
row = int(event.y / third)
c.click(row, col)
xo = XsorOs()
canvas.pack()
canvas.bind("<Button-1>", lambda event: mouse_click(xo, event))
canvas.mainloop()
EDIT:
lambda
is basically a way to create one line functions. In this case, I used it to pass arguments through the event function. Because somewhere internallytkinter
does something likeif that mouseclick happens do passed_function(event)
so you have no chance to use your own arguments. That's whylambda
is useful here__init__
is maybe not that important here since I saw people putting variables in class bodies before and apparently it works just fine, but I personally prefer it to create all the variables of a class in the constructorself
is likethis
in other languages a reference to the class or the object of that class (you can actually name it the way you want by naming the first constructor argument, butself
is commonly used). It "pulls" the variable in the scope of the class instead of the function. That means the variable exists and can be manipulated as long as the object exists. A function basically loses everything after execution. That was the main problem in your prior code.
Solution 2:
I managed to fix it based off a few tweaks from your code. However, I could I make it that if a X is created, an O and X cannot be created on that same tile? Thanks for your help. This is what I have so far.
from tkinter import *
tk = Tk()
width = 600
third = width / 3
canvas = Canvas(width=width, height=width)
tk.title = "Tic Tac Toe"
line1 = canvas.create_line(200, 0, 200, 600)
line2 = canvas.create_line(400, 0, 400, 600)
line3 = canvas.create_line(0, 200, 600, 200)
line4 = canvas.create_line(0, 400, 600, 400)
classXsorOs:
def__init__(self):
self.turn = 0
self.clicked = []
defclick(self, row, col):
if (row, col) notin self.clicked
if self.turn is0:
canvas.create_line(col * third, row * third, (col + 1) * third, (row + 1) * third)
canvas.create_line((col + 1) * third, row * third, col * third, (row + 1) * third)
self.turn += 1elif self.turn is1:
canvas.create_oval(col * third + 5, row * third + 5, (col + 1) * third - 5, (row + 1) * third - 5)
self.turn -= 1else:
print("Game Over")
self.clicked.append((row, col))
defmouse_click(c, event):
col = int(event.x / third)
row = int(event.y / third)
c.click(row, col)
xo = XsorOs()
canvas.pack()
canvas.bind("<Button-1>", lambda event: mouse_click(xo, event))
canvas.mainloop()
Also, if you have a reason to use the method you used that I was talking about in that comment, I would appreciate it if you would explain why.
Post a Comment for "Changing Variables Within A Function In Tkinter"