about on_touch_down and on_touch_move - python

I want to work with on_touch_down with a left-click but it just with work right-click and on touch move didn't work with anything
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.graphics import Ellipse, Color, Line
Window.clearcolor = (47/255, 72/255, 125/255, 1)
class PaintWindow(Widget):
def on_touch_down(self, touch):
s = 30
self.canvas.add(Color(rgb=(184/255, 154/255, 200/255)))
self.canvas.add(Ellipse(pos=(touch.x - s/2, touch.y - s/2), size=(s, s)))
touch.ud["line"] = Line(points=(touch.x, touch.y))
self.canvas.add(touch.ud)
def on_touch_move(self, touch):
touch.ud["line"].points += Line(points=(touch.x, touch.y))
class PaintApp(App):
def bulid(self):
return PaintWindow()
PaintApp().run()
how can i fix this problem

You are not seeing the results of your on_touch_down() or on_touch_move(). Your PaintApp has a bulid() that probably should be build(). Check your spelling.

Related

Kivy execute function when widget is dragged

I have a little demo here:
From DemoApp.py:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.behaviors import DragBehavior
from kivy.core.window import Window
class DraggableButton(DragBehavior, Button):
def on_drag(self, *args):
...
class DemoLayout(FloatLayout):
def __init__(self, **kwargs):
super(DemoLayout, self).__init__(**kwargs)
self.add_widget(DraggableButton(text='Drag Me'))
class DemoApp(App):
def build(self):
self.button= DraggableButton(text='Drag Me')
Window.bind(mouse_pos=lambda w, p: setattr(self.button, "mouse_pos", p))
return self.button
if __name__ == '__main__':
DemoApp().run()
From demo.kv:
<DraggableButton>:
drag_rectangle: self.x, self.y, self.width, self.height
drag_timeout: 10000000
drag_distance: 0
The problem is, I want to call my on_drag method when the DraggableButton is dragged.
Also, I only want the mouse position while in the function, so I can remove the line
Window.bind(mouse_pos=lambda w, p: setattr(self.button, "mouse_pos", p))
Is there any solution to this?
It uses DragBehavior so I found source code for DragBehavior
and I see it has method on_touch_move(touch).
I replaced this method in DraggableButton() and when button is moved then it gets MouseMotionEvent with pos which seems to be mouse position.
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.behaviors import DragBehavior
from kivy.core.window import Window
class DraggableButton(DragBehavior, Button):
def on_touch_move(self, touch):
super().on_touch_move(touch) # run original `on_touch_move()`
print('[on_drag] touch:', touch)
#print('[on_drag] touch.dpos:', touch.dpos)
#print('[on_drag] touch.spos:', touch.spos)
print('[on_drag] touch.pos:', touch.pos)
print('---')
class DemoApp(App):
def build(self):
self.button = DraggableButton(text='Drag Me')
return self.button
if __name__ == '__main__':
DemoApp().run()
Result:
[on_drag] touch: <MouseMotionEvent spos=(0.36, 0.5766666666666667) pos=(288.0, 346.0)>
[on_drag] touch.pos: (288.0, 346.0)
---
[on_drag] touch: <MouseMotionEvent spos=(0.35875, 0.5783333333333334) pos=(287.0, 347.0)>
[on_drag] touch.pos: (287.0, 347.0)
---
[on_drag] touch: <MouseMotionEvent spos=(0.35875, 0.5783333333333334) pos=(287.0, 347.0)>
[on_drag] touch.pos: (287.0, 347.0)
---

kivy detect clicks on widgets within screen

I have a screen with multiple widgets within it. I need to detect if the user clicked the label - 'home'
Whenever I click the screen the on_touch_down and on_touch_up is triggered. how can I determine the label that I clicked..
class WordScreen(Screen):
def __init__(self, **kwargs):
label_text = kwargs['label_text']
del kwargs['label_text']
super(WordScreen, self).__init__(**kwargs)
main_layout = BoxLayout(id='test', orientation='vertical')
navigation_layout = BoxLayout(orientation='horizontal',
size_hint_y=.1)
navigation_layout.add_widget(Label(text='home'))
navigation_layout.add_widget(Label(text='audio'))
navigation_layout.add_widget(Label(text='favorite'))
text_layout = BoxLayout(orientation='vertical')
text_layout.add_widget(Label(id='sight_text', text=label_text))
main_layout.add_widget(navigation_layout)
main_layout.add_widget(text_layout)
self.add_widget(main_layout)
def on_touch_down(self, touch):
self.initial = touch.x
def on_touch_up(self, touch):
print('on_touch_up - ', touch.x)
print(self.collide_point(*touch.pos))
print(touch.button)
s = None
try:
s = self.manager.get_screen('settings')
except ScreenManagerException:
pass
print('screen - ', s)
if s is not None:
self.manager.clear_widgets([s])
print('screen removed')
if touch.x < self.initial:
self.manager.transition = SlideTransition(direction="right")
self.manager.current = self.manager.next()
elif touch.x > self.initial:
self.manager.transition = SlideTransition(direction="right")
self.manager.current = self.manager.previous()
Based on link from John Anderson comment I created clickable Label.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.behaviors import ButtonBehavior
class MyLabel(ButtonBehavior, Label):
def on_press(self):
print("press:", self.text)
def on_release(self):
print("release:", self.text)
class MyApp(App):
def build(self):
return MyLabel(text="Hello")
MyApp().run()
But problem can be that on_touch_down and on_touch_up may block other events and then even standard Button will not work. You may have to check on_touch_down and on_touch_up only in widget which doesn't need on_press, on_release
Probably it could be resolved using only on_touch_move without on_touch_down, on_touch_up
EDIT:
Minimal working code.
It uses clickable Label and on_touch_move without on_touch_down, on_touch_up to slide screen.
BTW: I use if touch.dx < -3: instead of if touch.dx < 0: to skip very small moves. I tested it only with mouse but for findgers it may need different value.
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from functools import partial
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.uix.behaviors import ButtonBehavior
class MyLabel(ButtonBehavior, Label):
def on_press(self):
print("pressed:", self.text)
def on_release(self):
print("release:", self.text)
class WordScreen(Screen):
def __init__(self, **kwargs):
label_text = kwargs['label_text']
del kwargs['label_text']
super(WordScreen, self).__init__(**kwargs)
main_layout = BoxLayout(id='test', orientation='vertical')
navigation_layout = BoxLayout(orientation='horizontal',
size_hint_y=.1)
navigation_layout.add_widget(MyLabel(text='home'))
navigation_layout.add_widget(MyLabel(text='audio'))
navigation_layout.add_widget(MyLabel(text='favorite'))
text_layout = BoxLayout(orientation='vertical')
#text_layout.add_widget(Label(id='sight_text', text=label_text))
text_layout.add_widget(Label(id='sight_text', text=self.name))
main_layout.add_widget(navigation_layout)
main_layout.add_widget(text_layout)
self.add_widget(main_layout)
def on_touch_move(self, touch):
#print('touch variable:\n', "\n".join(dir(touch)))
print('touch.dx:', touch.dx)
print('touch.dsx:', touch.dsx)
#print('touch.distance:', touch.distance)
#print('touch.move:', touch.move)
if touch.dx < -3: # using `touch.dx < 0` it slides even on very small moves
self.manager.transition = SlideTransition(direction="right")
self.manager.current = self.manager.next()
elif touch.dx > 3: # using `touch.dx > 0` it slides even on very small moves
self.manager.transition = SlideTransition(direction="right")
self.manager.current = self.manager.previous()
sm = ScreenManager()
sm.add_widget(WordScreen(name='menu', label_text="Example"))
sm.add_widget(WordScreen(name='settings', label_text="Example"))
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()
EDIT:
Problem with on_touch_down, on_touch_up which block on_press, on_release can be resolved using super() to execute original code on_touch_down, on_touch_up
def on_touch_down(self, touch):
# ... code ...
return super(WordScreen, self).on_touch_down(touch)
def on_touch_up(self, touch):
# ... code ...
return super(WordScreen, self).on_touch_up(touch)
Based on example in documentation: Events - Dispatching a Property event

Is there a way to stop canva and textinput from overlapping in kivy?

I made a code where you can draw lines with a kivy canva and I wanted to add a Textinput. But the problem is that when I trie clicking on the Textinput, kivy wants to draw a line and it gives me an error :
" File "/myfolders/test.py", line 45, in on_touch_up
touch.ud['line'].points += [touch.x, touch.y]
KeyError: 'line' "
Here is my code :
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse, Line, Rectangle
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.uix.textinput import TextInput
from time import sleep
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.scatter import Scatter
from kivy.uix.boxlayout import BoxLayout
from math import *
isLine=False
length=0
class MyBackground(Widget):
def __init__(self, **kwargs):
super(MyBackground, self).__init__(**kwargs)
with self.canvas:
self.bg = Rectangle(source='chouettes3.jpg', pos=self.pos, size=self.size)
self.bind(pos=self.update_bg)
self.bind(size=self.update_bg)
def update_bg(self, *args):
self.bg.pos = self.pos
self.bg.size = self.size
class MyPaintWidget(Widget):
def on_touch_down(self, touch):
#if self.collide_point(*touch.pos):
with self.canvas:
self.canvas.clear()
d=15
Rectangle(pos=(touch.x-d/2,touch.y-d/2),size=(d,d))
touch.ud['line'] = Line(points=(touch.x, touch.y), width=3)
def on_touch_up(self, touch):
#if self.collide_point(*touch.pos):
touch.ud['line'].points += [touch.x, touch.y]
points=touch.ud['line'].points
length=sqrt(((points[0]-points[2])**2)+((points[1]-points[3])**2))
print (length)
with self.canvas:
d=15
Rectangle(pos=(touch.x-d/2,touch.y-d/2),size=(d,d))
class MyPaintApp(App):
def build(self):
f = FloatLayout()
s = Scatter()
b = BoxLayout(orientation='vertical')
parent = MyBackground()
painter = MyPaintWidget(pos_hint={'x': 100, 'center_y': 100}, size_hint=(None, None))
textinput = TextInput(text='Hello world')
parent.add_widget(painter)
parent.add_widget(textinput)
f.add_widget(parent)
sleep(0.1)
return f
if __name__ == '__main__':
MyPaintApp().run()
I tried the self.collide_point technique, where something only works when you click on the widget in question but that just doesn't draw a line anymore.
Thanks in advance for your answers!
One problem is your use of the Widget class as a container for other Widgets. You should use a Layout class to contain other Widgets, otherwise, things like pos_hint have no effect. So I have modified your code to make MyBackground extend FloatLayout. Also, using collide_point() is a good idea, but usually, when you override a class method, you should also call the overridden method using super(). With that in mind, here is your modified code, that I think will work as you intended:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Line, Rectangle
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from math import *
isLine=False
length=0
class MyBackground(FloatLayout):
def __init__(self, **kwargs):
super(MyBackground, self).__init__(**kwargs)
with self.canvas:
self.bg = Rectangle(source='chouettes3.jpg', pos=self.pos, size=self.size)
self.bind(pos=self.update_bg)
self.bind(size=self.update_bg)
def update_bg(self, *args):
self.bg.pos = self.pos
self.bg.size = self.size
class MyPaintWidget(Widget):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
with self.canvas:
self.canvas.clear()
d=15
Color(1, 0, 0, 1)
Rectangle(pos=(touch.x-d/2,touch.y-d/2),size=(d,d))
touch.ud['line'] = Line(points=(touch.x, touch.y), width=3)
return super(MyPaintWidget, self).on_touch_down(touch)
def on_touch_up(self, touch):
if 'line' not in touch.ud:
return super(MyPaintWidget, self).on_touch_up(touch)
if self.collide_point(*touch.pos):
touch.ud['line'].points += [touch.x, touch.y]
points=touch.ud['line'].points
length=sqrt(((points[0]-points[2])**2)+((points[1]-points[3])**2))
print (length)
with self.canvas:
d=15
Rectangle(pos=(touch.x-d/2,touch.y-d/2),size=(d,d))
return super(MyPaintWidget, self).on_touch_up(touch)
class MyPaintApp(App):
def build(self):
parent = MyBackground()
painter = MyPaintWidget(pos_hint={'x':0., 'center_y':0.5}, size_hint=(1, 1))
self.textinput = TextInput(text='Hello world', pos=(0,0), size_hint=(0.1,0.1))
parent.add_widget(painter)
parent.add_widget(self.textinput)
return parent
if __name__ == '__main__':
MyPaintApp().run()
I have also eliminated some unused code in the build() method.
As the code stands, clicking in the TextInput will not start a new line, but you can end a line behind the TextInput. If you don't want that to happen, you can add a collision test in the on_touch_up() method to handle it as shown below:
def on_touch_up(self, touch):
if 'line' not in touch.ud:
return super(MyPaintWidget, self).on_touch_up(touch)
ti = App.get_running_app().textinput
if self.collide_point(*touch.pos) and not ti.collide_point(*touch.pos):
touch.ud['line'].points += [touch.x, touch.y]
points=touch.ud['line'].points
length=sqrt(((points[0]-points[2])**2)+((points[1]-points[3])**2))
print (length)
with self.canvas:
d=15
Rectangle(pos=(touch.x-d/2,touch.y-d/2),size=(d,d))
else:
self.canvas.clear()
return super(MyPaintWidget, self).on_touch_up(touch)

Kivy canvas.clear() not clearing the canvas

I have followed the widget tutorial for Kivy, but I cannot get the canvas to clear after painting (from their 'a simple paint app' tutorial), unless I resize the window after pressing the clear button. Please help. I am using kivy v1.10.1 and python v3.7.0. on windows 10 64-bit OS. Further, a widget in scatter mode leaves a trace when you drag to a new position, this also clears when resizing the window. See code below:
from random import random
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Ellipse, Line
class MyPaintWidget(Widget):
def on_touch_down(self, touch):
color = (random(), 1, 1)
with self.canvas:
Color(*color, mode='hsv')
d = 30.
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
touch.ud['line'] = Line(points=(touch.x, touch.y))
def on_touch_move(self, touch):
touch.ud['line'].points += [touch.x, touch.y]
class MyPaintApp(App):
def build(self):
parent = Widget()
self.painter = MyPaintWidget()
clearbtn = Button(text='Clear')
clearbtn.bind(on_release=self.clear_canvas)
parent.add_widget(self.painter)
parent.add_widget(clearbtn)
return parent
def clear_canvas(self, obj):
self.painter.canvas.clear()
if __name__ == '__main__':
MyPaintApp().run()

How to pass mouse_pos values to draw ellipse to develop paint app in kivy in python?

I want to develop a paint app which creates ellipse or circle as the mouse is moved on the canvas
There is great examples on how to make drawing apps on kivy's website.
Take a look at it Drawing app in kivy
An example from the site.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse, Line
class MyPaintWidget(Widget):
def on_touch_down(self, touch):
with self.canvas:
Color(1, 1, 0)
d = 30.
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
touch.ud['line'] = Line(points=(touch.x, touch.y))
def on_touch_move(self, touch):
touch.ud['line'].points += [touch.x, touch.y]
class MyPaintApp(App):
def build(self):
return MyPaintWidget()
if __name__ == '__main__':
MyPaintApp().run()

Categories

Resources