[Interfaz Tkinter-Ejercicio 04] Divulgación detallada de la pintura con bloc de bocetos

1. Descripción

        Dominar el lienzo se divide en tres partes: pintar gráficos en el lienzo, mover animaciones y dibujar con el mouse. Este artículo se centrará en la función del dibujo con el mouse. Cuando se trata de la implementación del dibujo con el mouse, implicará una serie de operaciones combinadas a completar, que se explicarán una por una aquí.

        El widget Canvas tiene un montón de funciones y no las cubriremos todas aquí. En su lugar, comenzaremos con un ejemplo simple (la herramienta de dibujo a mano alzada) y gradualmente agregaremos nuevas secciones, cada una mostrando otra funcionalidad del widget de lienzo. 

2. Implementación básica del lienzo.

lienzo = Lienzo ( padre , ancho = 500, alto = 400, fondo = 'gray75')

         Normalmente proporciona el ancho y el alto en píxeles o cualquier otra unidad de distancia estándar. Como siempre, puedes pedirle al Administrador de Geometría que lo expanda para llenar el espacio disponible en la ventana. Puede darle al lienzo un color de fondo predeterminado y especificar el color como aprendió en el capítulo anterior. El widget de lienzo también admite otras opciones de apariencia, como el relieve y el ancho del borde, que usamos antes.

        Primero mire el siguiente código:

import tkinter as Tkinter
top = Tkinter.Tk()
C = Tkinter.Canvas(top, bg="blue", height=250, width=300)
coord = 10, 50, 240, 210
arc = C.create_arc(coord, start=0, extent=150, fill="red")
C.pack()
top.mainloop()

        Los widgets de Canvas administran colecciones 2D de objetos gráficos: líneas, círculos, texto, imágenes, otros widgets, etc. El lienzo de Tk es un widget muy potente y flexible y, de hecho, es uno de los aspectos más destacados de Tk. Es adecuado para una amplia gama de usos, incluidos dibujos o diagramas, herramientas CAD, visualización o monitoreo de equipos reales o simulados y creación de widgets más complejos a partir de widgets más simples.

        Nota: El widget Canvas es parte del widget Tk clásico, no del widget Tk temático.

3. Desplazamiento horizontal

        En muchas aplicaciones, querrás que el lienzo sea más grande de lo que aparece en la pantalla. Puede adjuntar barras de desplazamiento horizontales y verticales al lienzo de la forma habitual mediante los métodos xview e yview.

        Puede especificar qué tan grande desea que aparezca en la pantalla y su tamaño completo (esto requiere desplazarse para verlo). Las opciones de configuración de ancho y alto controlan cuánto espacio solicita el widget de lienzo al administrador de geometría. La opción de configuración de la región de desplazamiento le dice a Tk qué tan grande es la superficie del lienzo especificando sus coordenadas izquierda, superior, derecha e inferior, como 0 0 1000 1000.

        Según lo que ya sabe, debería poder modificar su programa de mesa de trabajo para agregar desplazamiento. darle una oportunidad.

        Una vez que hayas terminado, desplaza el lienzo un poco hacia abajo e intenta dibujar. ¡Verás que la línea que estás dibujando aparece encima de donde apunta el mouse! ¿sorprendido?

        Lo que sucede es que el comando de enlace global no sabe que se ha desplazado el lienzo (no conoce los detalles de ningún widget específico). Entonces, si desplaza el lienzo hacia abajo 50 píxeles y hace clic en la esquina superior izquierda, bind informará que hizo clic en (0,0). Pero sabemos que debido al desplazamiento, la posición debería ser (0,50).

        Los métodos canvasx y canvasy convierten la posición en pantalla (informada por el enlace) en un punto real en el lienzo (teniendo en cuenta el desplazamiento).

from tkinter import    *
from tkinter import ttk
top = Tk()

h = ttk.Scrollbar(top, orient=HORIZONTAL)
v = ttk.Scrollbar(top, orient=VERTICAL)

canvas = Canvas(top, bg="blue", height=250, width=300,scrollregion=(0, 0, 1000, 1000), yscrollcommand=v.set, xscrollcommand=h.set)
h['command'] = canvas.xview
v['command'] = canvas.yview
canvas.grid(column=0, row=0, sticky=(N, W, E, S))
h.grid(column=0, row=1, sticky=(W, E))
v.grid(column=1, row=0, sticky=(N, S))
top.grid_columnconfigure(0, weight=1)
top.grid_rowconfigure(0, weight=1)

coord = 10, 50, 240, 210
arc = canvas.create_arc(coord, start=0, extent=150, fill="red")

top.mainloop()

declaración significado
h = ttk.Scrollbar(arriba, orientar=HORIZONTAL) generar barra de desplazamiento horizontal
v = ttk.Scrollbar(arriba, orientar=VERTICAL) generar barra de desplazamiento vertical
lienzo = Lienzo(arriba, bg="azul", alto=250, ancho=300,scrollregion=(0, 0, 1000, 1000), yscrollcommand=v.set, xscrollcommand=h.set) Establecer el desplazamiento del lienzo.
 h['comando'] = lienzo.xview La barra de desplazamiento corresponde a la posición del lienzo.
v['comando'] = lienzo.yview La barra de desplazamiento corresponde a la posición del lienzo.
lienzo.grid(columna=0, fila=0, pegajoso=(N, W, E, S)) Coloca el lienzo de modo que el borde esté lleno.
h.grid(columna=0, fila=1, fijo=(W, E))
v.grid(columna=1, fila=0, fijo=(N, S))
Coloque barras de desplazamiento alrededor del lienzo.
top.grid_columnconfigure(0, peso=1)
top.grid_rowconfigure(0, peso=1)
Configurar barras de desplazamiento

4. Dibujo manual

4.1 Crear proyecto

        Cuando crea un nuevo widget de lienzo, es esencialmente un rectángulo grande sin contenido; en otras palabras, es efectivamente un lienzo en blanco. Para hacer algo útil con él, debe agregarle proyectos. Puede agregar muchos tipos diferentes de elementos. Aquí agregaremos una línea de pedido simple al lienzo.

        Para crear una línea, debe especificar sus coordenadas inicial y final. Las coordenadas se expresan como el número de píxeles horizontal y verticalmente desde la esquina superior izquierda, es decir, (x,y). El píxel en la esquina superior izquierda (llamado origen) tiene coordenadas (0,0). El valor "x" aumenta a medida que se mueve hacia la derecha y el valor "y" aumenta a medida que se mueve hacia abajo. Una recta está descrita por dos puntos, a los que llamamos (x0,y0) y (x1,y1). Este código crea una línea de (10,5) a (200,50):

        lienzo.create_line(10, 5, 200, 50)

 4.2 Dibujo

        Una mesa de trabajo simple
        Comencemos con nuestro ejemplo de mesa de trabajo simple. Ahora usaremos el mouse para dibujar a mano alzada sobre el lienzo. Creamos un widget de lienzo y le adjuntamos enlaces de eventos para capturar los clics y arrastres del mouse. Cuando se presiona el mouse por primera vez, recordamos esa posición como el "inicio" de la siguiente línea. A medida que movemos el mouse con el botón presionado, creamos un elemento de línea desde esa posición de "inicio" hasta la posición actual del mouse. Esta posición actual se convierte en la posición "inicial" para la siguiente línea de artículo. Cada arrastre del mouse crea una nueva línea de pedido.

from tkinter import *
from tkinter import ttk

def savePosn(event):
    global lastx, lasty
    lastx, lasty = event.x, event.y

def addLine(event):
    canvas.create_line((lastx, lasty, event.x, event.y))
    savePosn(event)

root = Tk()
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)

canvas = Canvas(root)
canvas.grid(column=0, row=0, sticky=(N, W, E, S))
canvas.bind("<Button-1>", savePosn)
canvas.bind("<B1-Motion>", addLine)

root.mainloop()

5. Dibujar atributos de línea

        lienzo.create_line(10, 10, 200, 50, relleno='rojo', ancho=3)

        Cuando crea un elemento, también puede especificar una o más propiedades del elemento que afectan la forma en que se muestra. Por ejemplo, podemos especificar que la línea sea roja y tenga tres píxeles de ancho.

El conjunto exacto de propiedades variará según el tipo de proyecto. Algunos de uso común son:

fill: el color del objeto dibujado

width: El grosor de línea del elemento (o su contorno)

outline: Para formas rellenas como rectángulos, el color del contorno del elemento dibujado

dash: Dibuja una línea discontinua en lugar de una línea sólida, por ejemplo, 2 4 6 4 alternando líneas discontinuas cortas (2 píxeles) y largas (6 píxeles) con 4 píxeles entre ellas.

stipple:Utilice un patrón en lugar de un color de relleno sólido, normalmente gris75, gris50, gris25 o gris12; el punteado no se admite actualmente en macOS

state: Asigna el estado normal (predeterminado), deshabilitado (se ignoran los enlaces de eventos de elementos) u oculto (eliminado de la pantalla). Relleno
deshabilitado, ancho deshabilitado, ...:

disabledfill, disabledwidth, ...:Si el estado de un elemento está establecido en Desactivado, el elemento se mostrará utilizando estas variaciones de las propiedades comunes.

activefill, activewidth, ...:Cuando el puntero del mouse esté sobre el elemento, se mostrará usando estas variaciones de propiedades comunes.

id = canvas.create_line(0, 0, 10, 10, fill='red')
...
canvas.itemconfigure(id, fill='blue', width=2)

6. tipo de artículo

        Los widgets de Canvas admiten múltiples tipos de elementos.

6.1 línea

        Nuestra mesa de trabajo crea elementos de línea simples, cada uno de los cuales es un segmento de línea con un punto inicial y final. Las líneas de pedido también pueden estar compuestas por varios segmentos.

        lienzo.create_line(10, 10, 200, 50, 90, 150, 50, 80)

Las líneas tienen varias propiedades adicionales interesantes que permiten dibujar curvas, flechas, etc.

Flecha: coloca una flecha al inicio (primero), al final (último) o en ambos extremos (ambos); el valor predeterminado es Ninguno.
Forma de flecha: permite cambiar
la apariencia de cualquier flecha. Forma de sombrero: para líneas anchas sin flechas, esto controla cómo se dibujan los extremos de la línea; uno de tope (predeterminado), sobresaliente o redondeado
Método de unión: para líneas anchas con múltiples segmentos, esto controla cómo se dibuja cada vértice; uno de redondeado (predeterminado), biselado o
liso a inglete: si especificado como verdadero (o Bézier), dibuja curvas suaves (a través de splines cuadráticos) entre múltiples segmentos de línea en lugar de usar líneas rectas; raw especifica diferentes tipos de splines curvas (cúbicas) Pasos: Controla la suavidad de las curvas, es decir, aquellas curvas con
el conjunto de opciones

6.2 Rectángulo

        Un rectángulo se especifica por las coordenadas de sus esquinas opuestas, como la superior izquierda y la inferior derecha. Se pueden rellenar con un color (mediante relleno), mientras que los contornos se rellenan con un color diferente.

        canvas.create_rectangle(10, 10, 200, 50, relleno='rojo', contorno='azul')

6.3 Óvalo

        Los elementos ovalados funcionan exactamente como rectángulos.

        lienzo.create_oval(10, 10, 200, 150, relleno='rojo', contorno='azul')

6.4 Polígonos

        Los proyectos de polígonos le permiten crear formas arbitrarias definidas por una serie de puntos. Las coordenadas se dan de la misma forma que para las líneas multipunto. Tk asegura que el polígono esté "cerrado", agregando el último punto al primer punto si es necesario. Al igual que los óvalos y los rectángulos, pueden tener colores de relleno y contorno separados. También admiten los atributos de estilo de unión, suavidad y pasos de spline de la línea de pedido.

        canvas.create_polygon(10, 10, 200, 50, 90, 150, 50, 80, 120, 55, relleno='rojo', contorno='azul')

6,5 arco

        Los elementos de arco dibujan parte de un óvalo; piense en un gráfico circular. Su visualización está controlada por tres propiedades:

        Inicio: qué tan lejos debe comenzar el arco a lo largo de la elipse, en grados (0 es la posición de las 3 en punto)
        Rango: qué tan "ancho" debe ser el arco en grados, valores positivos en sentido antihorario desde el inicio, valores negativos estilo de valor en el sentido de las agujas del reloj
        : uno de pieslice (predeterminado), arco (dibuja solo el perímetro exterior) o cuerda (dibuja el área entre la línea recta que conecta los puntos inicial y final del arco y el perímetro exterior).

 canvas.create_arc(10, 10, 200, 150, relleno='amarillo', contorno='negro', inicio=45, extensión=135, ancho=5)

6.6 Imagen

        Los elementos de imagen pueden mostrar cualquier imagen. De forma predeterminada, el elemento está centrado en las coordenadas que usted especifica, pero esto se puede cambiar usando las opciones de anclaje, por ejemplo, nw significa que las coordenadas son donde colocar la esquina superior izquierda de la imagen.

        myimg = FotoImagen(archivo='bonita.png')

        También hay un tipo de elemento de mapa de bits para imágenes que tienen sólo dos colores, que se pueden cambiar por primer plano y fondo. No se usan comúnmente hoy en día.

6.7 Texto

        Los elementos de texto pueden mostrar bloques de texto. Coloque el texto de la misma manera que coloca los elementos de la imagen. Utilice la propiedad de texto para especificar el texto que se mostrará. Todo el texto del elemento tendrá el mismo color (especificado por la propiedad de relleno) y la misma fuente (especificada por la propiedad de fuente).

        Los elementos de texto pueden mostrar varias líneas de texto si \n está incrustado en el texto. Alternativamente, puede agrupar elementos en varias líneas proporcionando una propiedad de ancho que represente el ancho máximo de la línea. La alineación del texto de varias líneas se puede configurar utilizando el atributo de justificación, que puede ser a la izquierda (predeterminado), a la derecha o al centro.

canvas.create_text(100, 100, text='Una historia maravillosa', Anchor='nw', font='TkMenuFont', fill='red')

6.8 Aparatos

        Una de las mejores cosas que puedes hacer con los widgets de lienzo es insertar otros widgets dentro de ellos. Esto podría ser un botón de bajo nivel, un elemento (piense en la edición in situ de elementos de texto), un cuadro de lista, un marco que contenga un conjunto complejo de widgets... ¡cualquier cosa! ¿Recuerdas que dijimos hace mucho tiempo que el widget de lienzo puede actuar como un administrador de geometría? Esto es lo que queremos decir.

        Los elementos del lienzo que muestran otros widgets se denominan widgets (el término a largo plazo de Tk para widgets). Su ubicación es similar a la de los elementos de texto e imagen. Puede darles propiedades explícitas de ancho y alto; por defecto tienen el tamaño preferido del widget. Finalmente, es importante que el widget que coloque en la propiedad del lienzo (a través de la ventana) sea un widget secundario del lienzo.

b = ttk.Button(lienzo, texto='¡Implodar!')

6.9 Modificar proyecto

        Hemos visto cómo modificar las opciones de configuración de un elemento: su color, ancho, etc. También puede realizar algunas otras operaciones en el proyecto.

        Para eliminar un elemento, utilice el método de eliminación.

        Para cambiar el tamaño y la posición de un elemento, puede utilizar el método de coordenadas. Usted proporciona nuevas coordenadas para el artículo, especificándolas de la misma manera que cuando creó el artículo por primera vez. Llamar a este método sin un nuevo conjunto de coordenadas devolverá las coordenadas actuales del elemento. Puede utilizar el método de movimiento para desplazar uno o más elementos horizontal o verticalmente desde su posición actual.

        Todos los elementos están ordenados de arriba a abajo en lo que se llama orden de apilamiento. Si un elemento posterior en el orden de apilamiento se superpone a un elemento debajo de él, el primer elemento se dibuja encima del segundo. Los métodos de subir (levantar en Tkinter) y bajar le permiten ajustar la posición de un elemento en el orden de apilamiento.

        Varias otras operaciones se detallan en el manual de referencia para modificar proyectos y recuperar información sobre ellos.

Siete, vinculación de eventos

        Hemos visto que el widget de lienzo en su conjunto, como cualquier otro widget de Tk, puede capturar eventos mediante comandos vinculantes.

        También puedes adjuntar enlaces a elementos individuales en el lienzo (o grupos de ellos, como veremos usando etiquetas en la siguiente sección). Entonces, si desea saber si se hizo clic en un elemento específico, no necesita monitorear todo el lienzo en busca de eventos de clic del mouse y luego determinar si ese clic ocurrió en su elemento. Tk se encargará de todo por ti.

        Para capturar estos eventos, puede utilizar los comandos de enlace integrados en el lienzo. Funciona exactamente como un comando de enlace normal, utilizando un patrón de evento y devoluciones de llamada. La única diferencia es que usted especifica el elemento del lienzo al que se aplica este enlace.

        lienzo.tag_bind(id, '<1>', ...)

        Agreguemos algo de código al ejemplo de la mesa de trabajo para permitir cambiar el color del trazado. Comenzaremos creando algunos elementos rectangulares diferentes, cada uno relleno con un color diferente. Luego adjuntaremos un enlace a cada uno de estos. Al hacer clic, establecen la variable global en el nuevo color de trazado. Nuestro enlace de movimiento del mouse observará esta variable al crear el segmento de línea.

color = "black"
def setColor(newcolor):
    global color
    color = newcolor

def addLine(event):
    global lastx, lasty
    canvas.create_line((lastx, lasty, event.x, event.y), fill=color)
    lastx, lasty = event.x, event.y

id = canvas.create_rectangle((10, 10, 30, 30), fill="red")
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("red"))
id = canvas.create_rectangle((10, 35, 30, 55), fill="blue")
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("blue"))
id = canvas.create_rectangle((10, 60, 30, 80), fill="black")
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("black"))

        Como puede ver, métodos como withtag aceptan un solo elemento o etiqueta; en el último caso, se aplicarán a todos los elementos con esa etiqueta (o tal vez a ninguna). Los métodos addtag ​​y find tienen muchas otras opciones que le permiten especificar elementos cerca de un punto determinado, superponer un área específica, etc.

        Comencemos usando etiquetas para agregar un borde a cualquier elemento en la paleta seleccionada actualmente.

def setColor(newcolor):
    global color
    color = newcolor
    canvas.dtag('all', 'paletteSelected')
    canvas.itemconfigure('palette', outline='white')
    canvas.addtag('paletteSelected', 'withtag', 'palette%s' % color)
    canvas.itemconfigure('paletteSelected', outline='#999999')

id = canvas.create_rectangle((10, 10, 30, 30), fill="red", tags=('palette', 'palettered'))
id = canvas.create_rectangle((10, 35, 30, 55), fill="blue", tags=('palette', 'paletteblue'))
id = canvas.create_rectangle((10, 60, 30, 80), fill="black", tags=('palette', 'paletteblack', 'paletteSelected'))

setColor('black')
canvas.itemconfigure('palette', width=5)

        También podemos usar etiquetas para hacer que el trazo dibujado actualmente parezca más prominente. Cuando suelte el botón del mouse, devolveremos la línea a la normalidad.

def addLine(event):
    global lastx, lasty
    canvas.create_line((lastx, lasty, event.x, event.y), fill=color, width=5, tags='currentline')
    lastx, lasty = event.x, event.y

def doneStroke(event):
    canvas.itemconfigure('currentline', width=1)        

canvas.bind("<B1-ButtonRelease>", doneStroke)

8. Etiquetas de piezas y acceso.

        Hemos visto que se puede hacer referencia a cada elemento del lienzo mediante un número de identificación único. Existe otra forma cómoda y potente de hacer referencia a elementos en el lienzo: mediante etiquetas.

        Las etiquetas son simplemente identificadores que usted crea y que tienen sentido para su programa. Puede adjuntar etiquetas a los elementos del lienzo; cada elemento puede tener cualquier cantidad de etiquetas. En lugar de un número de identificación de proyecto único para cada proyecto, muchos proyectos pueden compartir la misma etiqueta.

        ¿Qué puedes hacer con las etiquetas? Vimos que puedes modificar los elementos del lienzo usando la identificación del elemento (pronto veremos que puedes realizar otras operaciones en los elementos, como moverlos, eliminarlos, etc.). Siempre que pueda utilizar el ID del proyecto, puede utilizar etiquetas. Por ejemplo, puedes cambiar el color de todos los elementos con una etiqueta específica.

        Las etiquetas son una excelente manera de identificar colecciones de elementos en el lienzo (elementos en una línea de dibujo, elementos en una paleta, etc.). Puede usar etiquetas para asociar elementos del lienzo con objetos específicos en su aplicación (por ejemplo, use la etiqueta "robotX37" para etiquetar todos los elementos del lienzo que pertenecen al robot con ID #X37). Al utilizar etiquetas, no es necesario realizar un seguimiento de la identificación del elemento del lienzo para hacer referencia al grupo de elementos más adelante; las etiquetas permiten que Tk lo haga por usted.

        Puede asignar etiquetas cuando crea un proyecto usando la opción de configuración de proyecto de etiqueta . Puede agregar etiquetas más adelante usando el método addtag ​​o eliminarlas usando el método dtags. Puede usar el método gettags para obtener una lista de etiquetas para un artículo, o usar el comando buscar para devolver una lista de números de identificación de artículos con una etiqueta determinada.

>>> c = Canvas(root)
>>> c.create_line(10, 10, 20, 20, tags=('firstline', 'drawing'))
1
>>> c.create_rectangle(30, 30, 40, 40, tags=('drawing'))
2
>>> c.addtag('rectangle', 'withtag', 2)
>>> c.addtag('polygon', 'withtag', 'rectangle')
>>> c.gettags(2)
('drawing', 'rectangle', 'polygon')
>>> c.dtag(2, 'polygon')
>>> c.gettags(2)
('drawing', 'rectangle')	
>>> c.find_withtag('drawing')
(1, 2)

9. Realizar dibujo en pizarra

from tkinter import *
from tkinter import ttk

root = Tk()

h = ttk.Scrollbar(root, orient=HORIZONTAL)
v = ttk.Scrollbar(root, orient=VERTICAL)
canvas = Canvas(root, scrollregion=(0, 0, 1000, 1000), yscrollcommand=v.set, xscrollcommand=h.set)
h['command'] = canvas.xview
v['command'] = canvas.yview

canvas.grid(column=0, row=0, sticky=(N, W, E, S))
h.grid(column=0, row=1, sticky=(W, E))
v.grid(column=1, row=0, sticky=(N, S))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)

lastx, lasty = 0, 0


def xy(event):
    global lastx, lasty
    lastx, lasty = canvas.canvasx(event.x), canvas.canvasy(event.y)


def setColor(newcolor):
    global color
    color = newcolor
    canvas.dtag('all', 'paletteSelected')
    canvas.itemconfigure('palette', outline='white')
    canvas.addtag('paletteSelected', 'withtag', 'palette%s' % color)
    canvas.itemconfigure('paletteSelected', outline='#999999')


def addLine(event):
    global lastx, lasty
    x, y = canvas.canvasx(event.x), canvas.canvasy(event.y)
    canvas.create_line((lastx, lasty, x, y), fill=color, width=5, tags='currentline')
    lastx, lasty = x, y


def doneStroke(event):
    canvas.itemconfigure('currentline', width=1)


canvas.bind("<Button-1>", xy)
canvas.bind("<B1-Motion>", addLine)
canvas.bind("<B1-ButtonRelease>", doneStroke)

id = canvas.create_rectangle((10, 10, 30, 30), fill="red", tags=('palette', 'palettered'))
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("red"))
id = canvas.create_rectangle((10, 35, 30, 55), fill="blue", tags=('palette', 'paletteblue'))
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("blue"))
id = canvas.create_rectangle((10, 60, 30, 80), fill="black", tags=('palette', 'paletteblack', 'paletteSelected'))
canvas.tag_bind(id, "<Button-1>", lambda x: setColor("black"))

setColor('black')
canvas.itemconfigure('palette', width=5)
root.mainloop()

10. Conclusión

        Arriba describimos cómo generar un tablero de dibujo que pueda dibujar imágenes de usuario, porque hay una serie de operaciones en torno a Canvs, y las expandiremos una por una en este artículo. En cuanto a un conocimiento más profundo, puede consultar los documentos oficiales pertinentes del sitio web.

Tutorial de TkDocs - Lienzo

Supongo que te gusta

Origin blog.csdn.net/gongdiwudu/article/details/132713056
Recomendado
Clasificación