Inagnikai Inagnikai - 2 months ago 18
Python Question

Assigning custom method to on_touch_down etc. in Kivy

I'm writing what is ultimately to be a mobile game app using Kivy. Given the capabilities of the framework - being able to separate form and function - I'm attempting to do most, if not all, of the design of my GUI within a .kv file using the Kivy language. This works great as far as crafting a layout, but getting touch event handlers to work correctly is proving quite challenging. What I'm attempting to do is this:

Python:

from kivy import require
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.boxlayout import BoxLayout

require("1.9.1")

class gameScreen(FloatLayout):

def move_scatter(self, sender):
self.ids.moveArea.x = sender.text

def pc_move(self, touch, *args, **kwargs):
print('Goodbye')
# self.ids.protagonist.pos = (self.x + )

class GameApp(App):

def __init__(self, **kwargs):
super(GameApp, self).__init__(**kwargs)

def build(self):
return gameScreen()

class MoveBox(BoxLayout):
pass

class Pc(Image):
pass


if __name__ == '__main__':
GameApp().run()


Kivy Code:

<gameScreen>:

orientation: 'vertical'
padding: 20

canvas.before:
Rectangle:
size: (root.width, root.height)
source: 'bliss.jpg'

Pc:
id: protagonist

TextInput:
id: debugOut
size_hint: None, None
size: 200, 50
text: 'Hello'

BoxLayout:
id: moveArea
size_hint: None, None
size: 200, 200
on_touch_down: root.pc_move()
canvas:
Color:
rgba: .2, .2, .2, .5
Rectangle:
pos: (self.x + root.width - self.width, self.y)
size: self.size


<Pc>
source:'voolf.png'
pos_hint: {'top': .9}
size_hint: None, None
size: 300, 300


When I try this, I get:

TypeError: pc_move() takes at least 2 arguments (1 given)


This obviously make sense, as I am calling the pc_move() method without passing an argument. I know that the easiest way around this issue is just to create the BoxLayout in my Python code and define the on_touch_down method there, but as stated, I'm trying to keep my GUI and functionality separate.

The question is, how do I get the 'touch' parameter to pass as it would if I were to create the widget in Python code? Alternatively, am I just chasing a white whale? Does the event handling have to be done in a widget created in the Python code?

Answer

I confess I've never used Kivy, but the documentation for on_touch_down indicates it receives a touch parameter.

The docs also mention that args keyword is available in on_ callbacks.

Putting these two together, you should be able to pass your touch parameter to python via:

on_touch_down: root.pc_move(args[1])

[I'm not positive that it will be the #1 element in args[], but some of the examples seem to indicate that]