Usando y moviendo Widgets / Botones en Kivy

¡Estoy empezando con Kivy y es diferente a lo que estoy acostumbrado, disculpas si estoy cometiendo errores estúpidos!

En este momento estoy tratando de crear una aplicación que haga lo siguiente:

  • Permite la creación de nodos (elipsis por ahora).
  • Permite al usuario posicionar los nodos arrastrando.
  • Permite al usuario conectar los nodos con una línea.

Hasta ahora he conseguido el primero, y el segundo algo.

En este momento mi arrastre no está funcionando muy bien. Si muevo el mouse demasiado rápido, se cancela el método de movimiento (ya que ya no está en contacto). ¿Hay una mejor manera de producir arrastrando o simplemente incremento la frecuencia de actualización (si es así, cómo)?

def on_touch_move(self, touch): if self.collide_point(touch.x, touch.y): self.pos=[touch.x-25, touch.y-25] 

He intentado usar Botones en su lugar, usando el método on_press para seguir mejor el movimiento. Sin embargo, ahora tengo dificultades para actualizar la posición del botón (en su mayoría solo de 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] 

No tengo idea de cómo usar el valor táctil, y sigo recibiendo una serie de errores. (Obviamente el bash actual no funciona, solo pensé que era divertido).

Como probablemente pueda decir, tampoco sé cómo deshacerme de los gráficos de botones, ya que quiero usar la elipse. ¡Como una ventaja adicional si alguien pudiera mostrarme cómo cambiar el color de la elipse al presionar los botones, sería genial!

El archivo kv:

  : size: 50, 50 canvas: Ellipse: pos: self.pos size: self.size on_press: root.moveNode() 

Quiero poder usar la información táctil para actualizar la posición, pero no sé cómo implementarla aquí.

Código de Python de núcleo completo:

  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() 

Si necesita cualquier otra información, o algo no está claro, ¡hágamelo saber!

Edición: Segunda pregunta movida a: Crear una línea dibujada dinámicamente en Kivy .

Primero, deberías leer sobre eventos táctiles en Kivy. De particular interés aquí es la sección sobre agarrar eventos táctiles. Básicamente, puede “agarrar” un toque para asegurarse de que el widget de on_touch_move siempre recibirá más eventos de ese toque; en otras palabras, on_touch_move y on_touch_up luego de ese evento táctil se enviarán a su widget.

Ejemplo básico:

 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 

Pero, incluso mejor! Si quieres poder arrastrar widgets, Kivy ya tiene eso: Scatter .

Simplemente envuelve tu widget en un Scatter y puedes arrastrarlo. También puede usar multitouch para rotar y escalar un Scatter , pero puede deshabilitarlo fácilmente (kv):

 FloatLayout: Scatter: do_scale: False do_rotation: False MyWidget: 

Nota al margen – esto es incorrecto:

 class GraphNode(Button): background_disabled_down=1 background_disabled_normal=1 

background_disabled_down y background_disabled_normal son propiedades de Kivy , debe establecer esos valores en __init__ .

Forzar estos valores:

 class GraphNode(Button): def __init__(self, **kwargs): super(GraphNode, self).__init__(background_disabled_down='', background_disabled_normal='', **kwargs) 

Sugiera estos valores (mejor opción):

 class GraphNode(Button): def __init__(self, **kwargs): kwargs.setdefault('background_disabled_down', '') kwargs.setdefault('background_disabled_normal', '') super(GraphNode, self).__init__(**kwargs) 

Finalmente, tenga en cuenta que estas propiedades son nombres de archivo que apuntan a las imágenes utilizadas para el Button desactivado . Si elimina estos valores y deshabilita su botón, no se dibujará ningún fondo.