Saltar al contenido

Girar un objeto en un evento táctil en kivy

Te recomendamos que revises esta resolución en un entorno controlado antes de enviarlo a producción, un saludo.

Solución:

Puede enlazar el ángulo del lienzo a NumericProperty, para cambiarlo desde dentro de su código. Todo lo que necesitas hacer es calcular esos ángulos correctamente. Después de jugar un poco con él, creé el siguiente código:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.properties import NumericProperty

import math 

kv = '''
:
    canvas:
        Rotate:
            angle: root.angle
            origin: self.center
        Color:
            rgb: 1, 0, 0
        Ellipse:    
            size: min(self.size), min(self.size)
            pos: 0.5*self.size[0] - 0.5*min(self.size), 0.5*self.size[1] - 0.5*min(self.size)
        Color:
            rgb: 0, 0, 0
        Ellipse:    
            size: 50, 50
            pos: 0.5*root.size[0]-25, 0.9*root.size[1]-25
'''
Builder.load_string(kv)

class Dial(Widget):
    angle = NumericProperty(0)

    def on_touch_down(self, touch):
        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        self.prev_angle = calc if calc > 0 else 360+calc
        self.tmp = self.angle

    def on_touch_move(self, touch):
        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        new_angle = calc if calc > 0 else 360+calc

        self.angle = self.tmp + (new_angle-self.prev_angle)%360

    def on_touch_up(self, touch):
        Animation(angle=0).start(self)

class DialApp(App):
    def build(self):
        return Dial()

if __name__ == "__main__":
    DialApp().run()

Estoy calculando la diferencia entre el ángulo inicial (después de presionar el mouse) y el ángulo posterior en on_touch_move. Dado que el ángulo es una propiedad, también puedo modificarlo usando kivy.animation para hacer que el dial gire hacia atrás después de soltar el botón del mouse.

EDITAR

on_touch_down evento para círculo infantil:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.properties import NumericProperty

import math 

kv = '''
:
    circle_id: circle_id
    size: root.size
    pos: 0, 0
    canvas:
        Rotate:
            angle: self.angle
            origin: self.center
        Color:
            rgb: 1, 0, 0
        Ellipse:    
            size: min(self.size), min(self.size)
            pos: 0.5*self.size[0] - 0.5*min(self.size), 0.5*self.size[1] - 0.5*min(self.size)
    Circle:
        id: circle_id   
        size_hint: 0, 0
        size: 50, 50
        pos: 0.5*root.size[0]-25, 0.9*root.size[1]-25
        canvas:
            Color:
                rgb: 0, 1, 0
            Ellipse:    
                size: 50, 50
                pos: self.pos              
'''
Builder.load_string(kv)

class Circle(Widget):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            print "small circle clicked"

class Dial(Widget):
    angle = NumericProperty(0)

    def on_touch_down(self, touch):
        if not self.circle_id.collide_point(*touch.pos):
            print "big circle clicked"

        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        self.prev_angle = calc if calc > 0 else 360+calc
        self.tmp = self.angle

        return super(Dial, self).on_touch_down(touch) # dispatch touch event futher

    def on_touch_move(self, touch):
        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        new_angle = calc if calc > 0 else 360+calc

        self.angle = self.tmp + (new_angle-self.prev_angle)%360

    def on_touch_up(self, touch):
        Animation(angle=0).start(self)


class DialApp(App):
    def build(self):
        return Dial()

if __name__ == "__main__":
    DialApp().run()

Puede usar GearTick desde el jardín, que es un control deslizante giratorio. No es exactamente lo que necesita, pero se puede adaptar a sus necesidades. “De forma predeterminada, permite la rotación en el sentido contrario a las agujas del reloj, probablemente lo necesitaría en el sentido de las agujas del reloj” (Actualización: el widget ahora tiene un orientation propiedad que se puede establecer en ‘sentido horario’ o ‘antihorario’).

Debería manejar el resorte hacia atrás y detenerse en el “tope del dedo”.

El ejemplo en los extremos maneja el spring back usando animación, sin embargo, aún necesita administrar / implementar la funcionalidad de detención del dedo.

https://github.com/kivy-garden/garden.geartick

Uso::

Pitón::

from kivy.garden.geartick import GearTick
parent.add_widget(GearTick(range=(0, 100)))

kv ::

BoxLayout:
    orientation: 'vertical'
    GearTick:
        id: gear_tick
        zoom_factor: 1.1
        # uncomment the following to use non default values
        #max: 100
        #background_image: 'background.png'
        #overlay_image: 'gear.png'
        #orientation: 'anti-clockwise'
        on_release:
            Animation.stop_all(self)
            Animation(value=0).start(self)
    Label:
        size_hint: 1, None
        height: '22dp'
        color: 0, 1, 0, 1
        text: ('value: ').format(gear_tick.value)

ingrese la descripción de la imagen aquí

Instalar::

pip install kivy-garden
garden install geartick

Ejemplo de trabajo que puede copiar y pegar:

from kivy.lang import Builder
from kivy.app import runTouchApp
from kivy.garden.geartick import GearTick
runTouchApp(Builder.load_string('''
#:import Animation kivy.animation.Animation
GridLayout:
    cols: 2
    canvas.before:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            size: self.size
            pos: self.pos
    BoxLayout:
        orientation: 'vertical'
        GearTick:
            id: gear_tick
            zoom_factor: 1.1
            # uncomment the following to use non default values
            #max: 100
            #background_image: 'background.png'
            #overlay_image: 'gear.png'
            #orientation: 'anti-clockwise'
            on_release:
                Animation.stop_all(self)
                Animation(value=0).start(self)
        Label:
            size_hint: 1, None
            height: '22dp'
            color: 0, 1, 0, 1
            text: ('value: ').format(gear_tick.value)
'''))

Sección de Reseñas y Valoraciones

Si eres capaz, tienes la habilidad dejar un ensayo acerca de qué te ha parecido este escrito.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *