Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Tkinter - Una pequeña guía para hacer drag & drop
#1
Hola,
como tkinter no trae de "fábrica" esta funcionalidad, pongo aqui un pequeño ejemplo (muy simple) de como hacerlo. El programa en si no hace otra cosa que mover un grafico sobre la pantalla (sin tener en cuenta los limites de los  bordes).
Hay algun código que se puede cosiderar redundante como : .bind("<Button-1>") y .bind("<ButtonPress-1>"). Pero el ejemplo es solo a efectos didácticos. La librería PIL / Pillow se puede omitir, pero es que me siento cómodo con ella.
Código:
from tkinter import *
from PIL import Image, ImageTk


class ArrastraSuelta:
   def __init__(self, raiz, ancho_x, alto_y):
       self.raiz = raiz
       
       # estas medidas serán las mismas que el programa emisor
       # se utilizarán como coordenadas para los clicks, frames, etc.
       self.ancho_x = ancho_x
       self.alto_y = alto_y
       
       # Este diccionario lo usaremos para mantener el rastro de un un drag & drop
       self._drag_data = {"x": 0, "y": 0, "item": None}
       
       self.fm_prin = Frame(self.raiz, height=self.alto_y, width=self.ancho_x)
       #self.fm_prin.pack(expand = True, fill = "none")
       self.fm_prin.pack()
       self.lienzo = Canvas(self.fm_prin, width=self.ancho_x, height=self.alto_y)
       self.lienzo.pack(expand = YES, fill = BOTH)
       
       ancho_lienzo = self.lienzo.winfo_width()
       alto_lienzo = self.lienzo.winfo_height()
       
       #imagen de fondo inicial
       img = Image.open('./iconos/fondo_visor.jpg')
       tkimg = ImageTk.PhotoImage(img)
       self.img_frames = self.lienzo.create_image(ancho_lienzo/2, \
                         alto_lienzo/2, anchor=NW, image = tkimg, tag="nombre1")
       self.lienzo.image = tkimg   # para mantener la referencia
       
       # ahora vinculo los botones y teclas al canvas
       
       # boton izquierdo y derecho
       self.lienzo.bind("<Button-3>", self.onclick_derecho)
       self.lienzo.bind("<Button-1>", self.onclick_izquierdo)
       
       # pasos para el drag & drop con el boton izquierdo
       self.lienzo.tag_bind("nombre1", "<ButtonPress-1>", self.inicia_drag)
       self.lienzo.tag_bind("nombre1", "<Button-1>", self.moviendo_drag)
       self.lienzo.tag_bind("nombre1", "<ButtonRelease-1>", self.suelta_drag)
       
       # la captura de la tecla no se puede hacer sobre un Canvas
       self.raiz.bind("<Key>", self.onTecla_presionada)
       
       
   def onclick_derecho(self, evento):
       #obtenemos las coords. x, y
       x = evento.x
       y = evento.y
       print(46, x, y)
       
       
   def onclick_izquierdo(self, evento):
       #obtenemos las coords. x, y
       x = evento.x
       y = evento.y
       print(53, x, y)
   
   
   def onTecla_presionada(self, evento):
       #capturamos la tecla
       teclaPresionada = evento.char
       print(64, str(teclaPresionada))
       

   def inicia_drag(self, evento):
       #registramos el tema y su localizacion
       self.origen = None
       self._drag_data["item"] = self.lienzo.find_closest(evento.x, evento.y)[0]
       self._drag_data["x"] = evento.x
       self._drag_data["y"] = evento.y
       self.origen = (evento.x, evento.y)
       print(74, evento.x, evento.y)
       
       
   def moviendo_drag(self, evento):
       '''Maneja el arrastre del raton'''
       if self.origen == None:
           # reseteamos la informacion de _drag_data
           self._drag_data["item"] = None
           self._drag_data["x"] = 0
           self._drag_data["y"] = 0
       else:
           # calcula cuanto se ha movido el raton
           distancia_x = evento.x - self._drag_data["x"]
           distancia_y = evento.y - self._drag_data["y"]
           
           # muevo el objeto la distancia apropiada
           self.lienzo.move(self._drag_data["item"], distancia_x, distancia_y)
           
           # retomo la nueva posicion
           self._drag_data["x"] = evento.x
           self._drag_data["y"] = evento.y
       print(93, evento.x, evento.y)
   
   
   def suelta_drag(self, evento):
       '''Final del arrastre de la pieza'''
       # reseteamos la informacion del arrastre
       self._drag_data["item"] = None
       self._drag_data["x"] = 0
       self._drag_data["y"] = 0

       x = evento.x
       y = evento.y
       print(105, x, y)
   
       

def inicia_prueba():
   NOMBRE_PROGRAMA = 'Visor Recibe Escritorio'
   ancho_x = 600
   alto_y = 600
   
   root = Tk()
   root.geometry(str(ancho_x) + 'x' + str(alto_y) +'+500+1')   # la diferencia es el alo del menu
   root.title(NOMBRE_PROGRAMA)

   #img = PhotoImage(file='./iconos/pantalla.png')
   #root.tk.call('wm', 'iconphoto', root._w, img)

   cierra_win = ArrastraSuelta(root, ancho_x, alto_y)

   root.mainloop()


if __name__ == '__main__':
   inicia_prueba()


Espero os sirva.
Saludos
Responder
#2
Muy bueno, gracias por el aporte!
¡No te pierdas nuestro curso oficial en Udemy para aprender Python, bases de datos SQL, orientación a objetos, tkinter y mucho más!

También ofrecemos consultoría profesional de desarrollo en Python para personas y empresas.
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)