on_touch_widget kivy all other widgets gets activated - python

on implementing below code every time last widget gets activated
and after that each and every widget gets activated
please solve this
on implementing below code every time last widget gets activated
and after that each and every widget gets activated
please solve this
on implementing below code every time last widget gets activated
and after that each and every widget gets activated
please solve this
on implementing below code every time last widget gets activated
and after that each and every widget gets activated
please solve this
on implementing below code every time last widget gets activated
and after that each and every widget gets activated
please solve this
`
from pieces import matrix
from kivy.app import App
from kivy.graphics import Color,Rectangle
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.clock import Clock
class Sprite(Image):
def __init__(self,size=None,**kwargs):
super(Sprite, self).__init__(**kwargs)
if size==None:
self.size = self.texture_size
else:self.size=size
class Basket(Widget):
def __init__(self,source,pos,name,**kwargs):
super(Basket,self).__init__(**kwargs)
self.speed=4
self.name=name
self.image=Sprite(source=source,pos=pos,size=[100,100])
self.add_widget(self.image)
self.size=self.image.size
print self.size
def update_y(self,a):
final=a*100+50
if self.image.center_y==final:return True
elif self.image.center_y<final:self.image.center_y+=self.speed
else:self.image.center_y-=self.speed
return False
def update_x(self,a):
final=a*100+50
if self.image.center_x==final:return True
elif self.image.center_x<final:self.image.center_x+=self.speed
else:self.image.center_x-=self.speed
return False
def on_touch_down(self,touch):
if touch.grab_current is self:
print self.name
class Game(Widget):
def __init__(self,**kwargs):
super(Game,self).__init__(**kwargs)
self.matrix=matrix()
self.add_widget(Sprite(source='images/gray.jpg'))
for i in range(2):
self.ids[str(i)]=Basket(source='images/basket.jpg',name=str(i),pos=(i*100,i*100))
self.add_widget(self.ids[str(i)])
print i
# Clock.schedule_interval(self.update, 1.0/60.0)
# self.matrix.shuffle()
def update(self,ab):
if self.matrix.up:
if reduce(lambda a,i:self.ids[str(i)].update_y(self.matrix.y[i]) and a ,range(4),True):
self.matrix.shuffle()
else:
if reduce(lambda a,i:self.ids[str(i)].update_x(self.matrix.x[i]) and a,range(4),True):
self.matrix.shuffle()
def on_touch_down(self,touch):
print touch.grab(self)
class GameApp(App):
def build(self):
g=Game(size=(400,400))
Window.size=g.size
return g
GameApp().run()
`

Kivy doesn't perform touch collision by default, so that widgets can interact with touches that do not collide with them (since the widget arrangement is not necessarily the same as the gui touch arrangement).
You can just perform the collision check yourself:
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
do_stuff()

Related

kivy: How to add a callback to a unfocus event on TextIput widgets

I've got a problem tying callback funtions to the on_focus event of a TextInput.
I want it to trigger a validation event when the focus from the input widget is removed. And, in doing so, calling another method (via the on_validate_text method)
Here is the code:
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.app import App
class MyTextInput(TextInput):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.multiline = False
self.unfocus_on_touch = True
def on_focus(self, instance, value):
if not value: # DEFOCUSED
print('Focus is off')
class MainLayout(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 2
#First row
self.top_label = Label(text = 'No text')
self.add_widget(self.top_label)
self.top_input = MyTextInput(on_text_validate=self.change_top_label)
#Here im trying to trigger the validate event when the on_focus gets called
self.top_input.bind(on_focus=self.top_input.on_text_validate)
self.add_widget(self.top_input)
#Second row
self.bottom_label = Label(text='Bottom Label')
self.add_widget(self.bottom_label)
self.bottom_input = MyTextInput(on_text_validate=self.create_popup)
self.bottom_input.bind(on_focus=self.bottom_input.on_text_validate)
self.add_widget(self.bottom_input)
def change_top_label(self, instance):
self.top_label.text = instance.text
instance.text = ''
def create_popup(self, instance):
self.my_popup = Popup(title=instance.text, size_hint=(.5, .5))
self.my_popup.content = Button(text='CLOSE', on_release=self.my_popup.dismiss)
self.my_popup.open()
instance.text = ''
if __name__ == '__main__':
class MainApp(App):
def build(self):
return MainLayout()
MainApp().run()
In this case, when de top input gets defocused, I want it to call the change_top_label method through the validation event.
In the same way, when the bottom input gets defocused, the create_popup method should get called through the validation event.
I need both input to call a callback function when unfocused. But I can not define that function inside the on_focus method, because it needs to be different for every instance of MyTextInput.
I've tried binding on_text_validate to on_focus, and calling on_text_validate inside the on_focus metyhod, but it does not work.
Clearly there is something I'm missing.
If you could help me out here, It'd be great.
First of all, your code seems already doing what you wanted in the following (after the method on_text_validate is being called),
In this case, when de top input gets defocused, I want it to call the change_top_label method through the validation event...
Secondly,
I've tried binding on_text_validate to on_focus...
This seems confusing to me. The method on_text_validate gets called when you hit 'enter' (and if multiline is set to False) and that will also unfocus the TextInput. Also on_focus is kind of a default method that is called whenever the attr. focus changes. So and finally if you want just this,
I need both input to call a callback function when unfocused. But...
You can do that as TextInput_instance.bind(focus = some_method).

want to access the widget's (here OneLineListItem) text and id when it is clicked using on_touch_down method

GOAL:
-call my_callback() function only if the OneLineListItem widget is pressed, other wise do nothing.
EXPLAIN THESE THINGS:
-Please explain how can i call the function my_callback() when any one of the OneLineListItem is pressed, using on_touch_down() function
-Also explain why we are adding super(Touch, self).on_touch_down(touch) in else block
PROBLEMS WITH THE CURRENT CODE:
-Do not give any error, but code does not working as i want.
-The on_touch_down() method is not working (wants to understand how it works, i have just copied it from the documentation of kivy).
from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.list import OneLineListItem
from kivy.uix.widget import Widget
helper_string = """
Screen:
Touch:
ScrollView:
MDList:
id: containers
"""
class MyApp(MDApp):
def build(self):
screen = Builder.load_string(helper_string)
return screen
def on_start(self):
# createing the OneLineListItem
item_1 = OneLineListItem(text='subject_1', id='item1')
item_2 = OneLineListItem(text='subject_2', id='item2')
item_3 = OneLineListItem(text='subject_3', id='item3')
# adding the above OneLineListItem into MDList
self.root.ids.containers.add_widget(item_1)
self.root.ids.containers.add_widget(item_2)
self.root.ids.containers.add_widget(item_3)
class Touch(Widget):
def on_touch_down(self, touch):
app = MDApp.get_running_app()
# gets all the OneLineListItem in subject_wid_list
subject_wid_list = app.root.ids.containers.children
# plz explain this part briefly. have lots of confusion about .collide_point()
# also explain why we are adding super(...).on_touch_down()
# iterating in the list and checking for collision of widget with touched coordinates.
for child in subject_wid_list:
if child.collide_point(*touch.pos):
print('touched one of the OneLineListItem widget')
self.my_callback()
else:
print('touched something else other than OneLineListItem widget')
return super(Touch, self).on_touch_down(touch)
def my_callback(self):
pass
MyApp().run()
You access the widget text and id through the instance:
def mycallback(self,instance):
m=instance.id
x=instnace.text
it determines the row and you can deal with it. You have to add id to the widget when you add it. I have not tried it with on_touch_down but I have with on_press and it worked.
You can call my_callback function when you add_widget as the following:
self.ids.scroll.add_widget(OneLineListItem(text='as you want' ,id=str(i),halign="right",on_press=self.mycallback))

kivy is not detecting touch input

I have installed kivy on my Ubuntu and connected a touch screen, but when I touch the screen kivy doesn't detect that.
To detect mouseclicks is no problem, just touch isn't working.
I already did the changes in config.ini:`
mouse = mouse;
mtdev_%(name)s = probesysfs,provider=mtdev; hid_%(name)s = probesysfs,provider=hidinput
Thats my code:
from kivy.app import App
from kivy.uix.widget import Widget
class TouchInput(Widget):
def on_touch_down(self, touch):
print(touch)
def on_touch_move(self, touch):
print(touch)
def on_touch_up(self, touch):
print("RELEASED!",touch)
class SimpleKivy4(App):
def build(self):
return TouchInput()
if name == "main":
SimpleKivy4().run()
Does anybody have a other idea why kivy doesn't detect my touch input?
Thank you in advance.
While you've defined your on_touch_*(self, touch) function, it's not enough to define it. The Window module has a on_touch_* method, but it is currently bound to None. It is the Window module, not your own classes/widgets, that manages the whole window of your app, that calls the callbacks such as motion and touch. Under the docs for input.motionevent, it has the following on how to listen (use your callback) for a motion/touch event:
def on_touch_down(self, touch):
# Receives a motion event with the [pos] profile
pass
Window.bind(on_touch_down=on_touch_down)
You're missing the Window.bind(window_method=my_function) call.

Using and moving Widgets/Buttons in Kivy

I'm just starting off with Kivy and it's different to what I'm used to, apologies if I'm making stupid mistakes!
Right now I'm trying to create an app that does the following:
Allows creation of Nodes (ellipses for now).
Allows the user to position the nodes by dragging.
Allows the user to connect the nodes with a line.
So far I've achieved the first, and the second somewhat.
Right now my dragging is not working too well. If I move the mouse too quickly it cancels the move method (as it is no longer in contact). Is there a better way to produce dragging or do I just increase the refresh rate (if so how?).
def on_touch_move(self, touch):
if self.collide_point(touch.x, touch.y):
self.pos=[touch.x-25, touch.y-25]
I've tried using Buttons instead, using the on_press method to track the moving better. However now I'm having difficulty updating the position of the button (mostly just syntax).
class GraphNode(Button):
background_disabled_down=1
background_disabled_normal=1
def moveNode(self):
with touch:
self.pos=[touch.x-25, touch.y-25]
I have no idea how to use the touch value, and keep getting an array of errors. (Obviously the current attempt doesn't work, I just thought it was funny).
As you could probably tell, I also don't know how to get rid of the button graphics, as I want to use the ellipse. As an added bonus if someone could show me how to change the colour of the ellipse on button press that would be cool!
The kv file:
<GraphNode>:
size: 50, 50
canvas:
Ellipse:
pos: self.pos
size: self.size
on_press:
root.moveNode()
I want to be able to use the touch information to update the position, but don't know how to implement it here.
Full core python code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.properties import NumericProperty, ReferenceListProperty,\
ObjectProperty
from kivy.graphics import Color, Ellipse, Line
class GraphInterface(Widget):
node = ObjectProperty(None)
class GraphApp(App):
def build(self):
node = GraphNode()
game = GraphInterface()
createNodeButton = Button(text = 'CreateNode', pos=(100,0))
createEdgeButton = Button(text = 'CreateEdge')
game.add_widget(createNodeButton)
game.add_widget(createEdgeButton)
def createNode(instance):
game.add_widget(GraphNode())
print "Node Created"
def createEdge(instance):
game.add_widget(GraphEdge())
print "Edge Created"
createNodeButton.bind(on_press=createNode)
createEdgeButton.bind(on_press=createEdge)
return game
class GraphNode(Button):
def moveNode(self):
with touch:
self.pos=[touch.x-25, touch.y-25]
#def onTouchMove(self, touch):
# if self.collide_point(touch.x, touch.y):
# self.pos=[touch.x-25, touch.y-25]
pass
class GraphEdge(Widget):
def __init__(self, **kwargs):
super(GraphEdge, self).__init__(**kwargs)
with self.canvas:
Line(points=[100, 100, 200, 100, 100, 200], width=1)
pass
if __name__ == '__main__':
GraphApp().run()
If you need any other info, or anything is unclear, please let me know!
Edit: Second question moved to: Creating a dynamically drawn line in Kivy.
First, you should read up on touch events in Kivy. Of particular interest here is the section on grabbing touch events. Basically, you can "grab" a touch to ensure that the grabbing widget will always receive further events from that touch - in other words, the on_touch_move and on_touch_up following that touch event will be sent to your widget.
Basic example:
class MyWidget(Widget):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
touch.grab(self)
# do whatever else here
def on_touch_move(self, touch):
if touch.grab_current is self:
# now we only handle moves which we have grabbed
def on_touch_up(self, touch):
if touch.grab_current is self:
touch.ungrab(self)
# and finish up here
But, even better! If you want to be able to drag widgets around, Kivy already has that: Scatter.
Just wrap your widget in a Scatter and you can drag it around. You can also use multitouch to rotate and scale a Scatter, but you can easily disable that (kv):
FloatLayout:
Scatter:
do_scale: False
do_rotation: False
MyWidget:
Side note - this is incorrect:
class GraphNode(Button):
background_disabled_down=1
background_disabled_normal=1
background_disabled_down and background_disabled_normal are Kivy properties - you should set those values in __init__.
Force these values:
class GraphNode(Button):
def __init__(self, **kwargs):
super(GraphNode, self).__init__(background_disabled_down='',
background_disabled_normal='', **kwargs)
Suggest these values (better option):
class GraphNode(Button):
def __init__(self, **kwargs):
kwargs.setdefault('background_disabled_down', '')
kwargs.setdefault('background_disabled_normal', '')
super(GraphNode, self).__init__(**kwargs)
Finally, note that these properties are filenames pointing to the images used for the disabled Button. If you remove these values, and disable your button, it will draw no background whatsoever.

Kivy tutorial buttons don't print

I'm working through the Kivy tutorial, programming guide, and find the following code is not actually printing the button position anywhere, as far as I can tell---that is, the btn_pressed() method doesn't seem to do anything.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty
class RootWidget(BoxLayout):
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
self.add_widget(Button(text='btn 1'))
cb = CustomBtn()
cb.bind(pressed=self.btn_pressed)
self.add_widget(cb)
self.add_widget(Button(text='btn 2'))
def btn_pressed(self, instance, pos):
print ('pos: printed from root widget: {pos}'.format(pos=pos))
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))
class TestApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
TestApp().run()
Does anyone have any hints or ideas why this isn't working? Is this the intended behavior and I missed something or is there an error in the tutorial?
Specifically, while the instructions above produce buttons that can be clicked and flash---there doesn't seem to be any output corresponding to the method:
def btn_pressed(self, instance, pos):
print ('pos: printed from root widget: {pos}'.format(pos=pos))
Maybe it's printing black on black?
The seemingly blank, unlabeled spot in the middle is the button that accepts location and prints location to the console. I was clicking on the buttons labeled "btn" and didn't notice this place existed.
This part of the tutorial is demonstrating how you can make custom buttons that do stuff precisely like this. It would be more clear if this were labeled, but that should be doable by looking at the API.
Anyway, the code is working as expected.

Categories