I have been working on this problem for a long time and I cannot figure out a solution. I am making a game of tic tac toe, and I have created a gridlayout of 9 buttons. When a button is pressed, I want it to change from a placeholder image to an image of an x or an o. I have assigned the button image source as a python class attribute, and I can call a function so the attribute updates when the button is pressed. I know it's working because I get an output from the function every time a button is pressed. The problem is that the image does not update. I've looked everywhere for a solution but I can't find one.
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.gridlayout import GridLayout
class Game(GridLayout):
empty = str('C:/Users/codin/Desktop/tictactoe/walpaper.png')
states = ['button1', 'button2', 'button3', 'button4', 'button5',
'button6', 'button7', 'button8', 'button9']
button1 = empty
button2 = empty
button3 = empty
button4 = empty
button5 = empty
button6 = empty
button7 = empty
button8 = empty
button9 = empty
def change_state(self, state):
O = str('C:/Users/codin/Desktop/tictactoe/just_o.png')
X = str('C:/Users/codin/Desktop/tictactoe/just_x.png')
empty = str('C:/Users/codin/Desktop/tictactoe/walpaper.png')
if getattr(self, state) == empty:
setattr(self, state, X)
elif getattr(self, state) == X:
setattr(self, state, O)
elif getattr(self, state) == O:
setattr(self, state, X)
else:
setattr(self, state, empty)
print(self.__dict__[state])
pass
# Create an app class to do the handling
class TicTacToe(App):
def build(self):
return Game()
if __name__ == "__main__":
TicTacToe().run()
.kv file:
<Game>
cols: 3
rows: 4
Button:
on_press: root.change_state(root.states[0])
Image:
id: button1
source: root.button1
center_x: self.parent.center_x
center_y: self.parent.center_y
Button:
on_press: root.change_state(root.states[1])
Image:
id: button2
source: root.button2
center_x: self.parent.center_x
center_y: self.parent.center_y
more buttons below
I am fully aware that I can write a function for every button, and change the image source via self.ids.image_id.source in the python file, but I'm trying to keep it short. Any help is greatly appreciated.
I was able to figure it out using a combination of ApuCoder's answer and information from the kivy.lang module outline here: https://kivy.org/doc/stable/api-kivy.lang.html
My python code is very short, simple variables assigned to str() filepath for images in a game class, and an app class to compile:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.gridlayout import GridLayout
# class for image sources and layout
class Game(GridLayout):
O = str('just_o.png')
X = str('just_x.png')
empty = str('wallpaper.png')
# App class to do the handling
class TicTacToe(App):
def build(self):
return Game()
if __name__ == "__main__":
TicTacToe().run()
In kv, you can write conditional statements. The requirements are that each statement is on its own line. if/elif/else as well as for and while loops are all allowed.
<Game>
cols: 3
rows: 3
Button:
on_press:
if button1.source == root.empty: button1.source = root.X
elif button1.source == root.X: button1.source = root.O
else: button1.source = root.X
Image:
id: button1
source: root.empty
center_x: self.parent.center_x
center_y: self.parent.center_y
This code basically says, "image source assigned at start, on_press if the image is this, change it to that, and vice versa"
This is likely the least amount of code needed to accomplish this task.