I would like to know what does the word instance mean in kivy?
class CustomBtn(Widget):
pressed = ListProperty([0, 0])
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.pressed = touch.pos
# we consumed the touch. return False here to propagate
# the touch further to the children.
return True
return super(CustomBtn, self).on_touch_down(touch)
def on_pressed(self, instance, pos):
print ('pressed at {pos}'.format(pos=pos))
print ('My callback is call from', instance)
'instance' is the name and reference to the object instance of the Class CustomBnt when you press the button. It does not have to be named 'instance'. You may also call it 'obj' or 'btn' or whatever makes sense to you.
You use it to gather information about the pressed Button. instance.text would be the text on the Button e.g.
Use print type(instance) to find out what kind of object 'instance' is.
instance does not have a special meaning. This argument is used to convey to the method which object triggered an event. Consider an event handler attached to an event from another class:
class MyLabel(Label):
def pressed_handler(self, instance, pos):
print ('pressed at {pos}'.format(pos=pos))
print ('My callback is call from', instance)
a = CustomBtn()
b = MyLabel()
a.bind(on_pressed=b.pressed_handler)
then pressed_handler will know which object sent the event, through the instance argument.
Related
The pictures example in /share/kivy-examples/demo/pictures places Image widget in Scatter. I'd like to extend the example and replace Image with <ImageButton#ButtonBehavior+Image>. However, the touch events are not implemented correctly. The ImageButtons are press-able but the drag functionality from the original example is lost.
At first I simply changed Image to <ImageButton#ButtonBehavior+Image> in the pictures.kv file. I see in the documentation that I may need to (re)implement on-press or on_touch_down. To that end, I've added these methods in the Picture class:
class Picture(Scatter):
source = StringProperty(None)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
print('picture touch down')
else:
print('no collide in picture')
super(Picture, self).on_touch_down(touch)
def on_touch_move(self, touch):
if self.collide_point(*touch.pos):
print('touch move')
super(Picture, self).on_touch_move(touch)
I see the print statements in the terminal. But the ImageButtons are still consuming the on_press, and I know this from a print statement in that event handler. I tried to re-implement on_press and just not do anything with pass, and then I had an idea of calling self.parent.on_touch_down, but I don't have a touch object to pass into it.
One idea would be to
class ImageButton(ButtonBehavior, Image):
'''
def on_press(self):
print("button pressed")
print()
return super(ImageButton, self).on_press()
'''
def on_press(self):
pass
So, say I want the ImageButton to only register a double-clicks, and otherwise, for the widgets to behave just like in the example. How would I achieve that? Somewhat related
While there may be a way of distinguishing between a quick touch_down followed immediately by a touch_up, it is easier to show the desired functionality by letting an ImageButton press be activated with a double_tap:
class ImageButton(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(ImageButton, self).__init__(**kwargs)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos) and touch.is_double_tap:
self.on_press(touch)
return True
return False
def on_press(self,touch):
#whatever else you want to happen
return True
I want to go to the next screen after finishing a time consuming calculation. Therefore, I wnat to define at the end of a function the screen that has to be shown. However, when I try the following:
def gotoscreen1(self):
print self.manager (prints None)
self.manager.current = 'screen2'
I have the error = AttributeError: 'NoneType' object has no attribute 'current'
When I try:
def on_enter(self):
print self.manager (prints <__main__.ScreenManagement object at 0x1227C688>)
self.manager.current = 'screen2'
I can jump imediatly to screen 2, but that is not what I want ...
Many thanks in advance for your help!
After a hort night sleep (thank you son) I woke up and knew the solution: I needed to pass the correct arguments when calling the function in the clock schedule
Clock.schedule_interval(partial(self.gotoscreen1, self), 0.5)
for i = 1, groupA:getNumChildren() do
local sprite = groupA:getChildAt(i)
if cute.anim[1]:collidesWith(sprite) then
youLoose()
end
end
local function youLoose()
local font3 = TTFont.new("billo.ttf", 20, " 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,?")
local text7 = TextField.new(font2, "gameover")
text7:setPosition(200, 100)
stage:addChild(text7)
GameLost = Bitmap.new(Texture.new("gameover.jpg"))
Background : removeFromParent()
groupA : removeFromParent()
stage: addChild(GameLost)
alert()
end
It gives an error that says 'attempt to call global youLoose (a nil value), where am I doing it wrong?
Note that collideswith is not the same as collidesWith; if that error you posted is correct, then you posted code that is different from what you are using. It could be that the method really is called collidesWith (it appears to be if it is the one from sprite1), but you used collideswith. Alternatively, if the code posted is what you used, then the error is likely attempt to call collideswith(a nil value), so cute.anim[1] is not a sprite1 object, but it is not nil either otherwise the error would be different.
Once you have fixed this, you'll notice that youLoose is defined after that for loop, when you call youLoose() it is not yet defined. You're going to have to move the local function youLoose() function to before the loop. Because the loop is not itself in a function, but is at module level, it gets executed before any following code, so any functions (local or global) that are used in the loop must be defined before the loop.
Note that "loose" does not mean the same as "lose". Check Grammar-monster to see difference. Probably everywhere you have the word "loose" you should change to "lose".
When I bind a function to a button inside an accordion nothing happens upon clicking it. I have no idea what i'm doing wrong. :( Any thoughts?
def printTest():
print "The button worked!"
accord = Accordion(anim_duration=1.5, orientation='vertical')
specialButton = Button(text="click me", font_size='20sp', text_size=(1100, None), halign="center")
specialButton.bind(on_press=printTest():
item = AccordionItem(title="Hello World")
item.add_widget(specialButton)
accord.add_widget(item)
specialButton.bind(on_press=printTest():
This isn't valid syntax, is the colon a typo?
Either way, the problem is that you are calling printTest, not passing it as an argument.
Instead try
def printTest(*args):
print "The button worked!"
...and...
specialButton.bind(on_press=printTest)
The *args is important because the binding automatically passes some arguments.
I covered this in more detail here.
Basically I want to know when function;
button[n]:onclick() --where n can be any string value
gets called, and send its name (specifically I want to send "n") to another function;
function allbuttons(n) --where n is the n from button[n]:onclick()
which then processes all possible requests.
I want to do this because button[n] is specified, and therefore the button[n]:onclick() gets triggered every time the button is clicked, but it doesn't seem right to write these function every time I want another buttonclick to be processed in the big allbuttons function;
function button['options']:onclick()
allbuttons('options')
end
function button['quit']:onclick()
allbuttons('quit')
end
(...)
function button[n]:onclick()
allbuttons(n)
end
I've tried something like;
debug.sethook(allbuttons, 'c')
function allbuttons()
n = debug.getinfo(2).name
end
but I guess I don't fully understand how to use debug.sethook ..
Set button[n]:onclick to be the function you want (allbuttons), except that here there is one tricky bit, the value n. You likely know already that you could do
button[n].onclick = allbuttons
But if the event dispatcher calls onclick as button[n]:onclick() then allbuttons will always get button as first argument. If what you really want in allbuttons is to know the button[n] instance that was clicked, all you need to do is change the definition of allbuttons(n) to allbuttons(button) and change its code accordingly.
If you need n and it's not available any other way, you can create an anonymous closure with access to n as an upvalue (see http://www.lua.org/pil/6.1.html for details):
function sendClickToCommon(button, n)
button[n].onclick = function (self)
allbuttons(n)
end
end
sendClickToCommon(button, 1)
sendClickToCommon(button, 2)
sendClickToCommon(button, 3)
Or you could do it this way too:
function getAllbuttonsN(n)
return function (self)
allbuttons(n)
end
end
button[1].onclick = getAllbuttonsN(1)
The code is simpler but the index appears twice in the expression, a potential source of error.