Contents

Como construir uma aplicação de pintura usando Python

Uma simples ferramenta de pintura é uma das aplicações mais comuns que pode encontrar na maioria dos computadores. Permite ao artista cometer erros sem medo, escolher qualquer cor com o clique de um botão e alterar o tamanho das pinceladas instantaneamente. Pode ser utilizada para criar logótipos de marcas, concetualizar interfaces de utilizador e fazer anotações em diagramas.

De que forma se pode construir um programa de pintura?

O módulo Tkinter e Pillow

Para desenvolver uma aplicação de pintura usando Python, é necessário ter os módulos Tkinter e Pillow instalados no sistema. A estrutura Tkinter está entre as escolhas mais populares quando se trata de conceber interfaces gráficas de utilizador (GUI) para aplicações de ambiente de trabalho baseadas em Python. Esta estrutura fornece uma vasta gama de widgets incorporados, tais como etiquetas, caixas de texto, telas e botões que permitem aos programadores criar interfaces visualmente apelativas e interactivas de forma rápida e fácil.

Pillow, um derivado da venerável Python Imaging Library (PIL), serve como um versátil conjunto de ferramentas de processamento de imagem para aplicações Python. Tirando partido das suas capacidades, os utilizadores podem realizar facilmente várias operações em suportes visuais digitais, como abrir, redimensionar, rodar e cortar imagens. Além disso, esta biblioteca facilita a conversão de formatos, permite o desenvolvimento de algoritmos complexos, como sistemas de recomendação de receitas, e fornece funcionalidades para obter imagens aleatoriamente a partir de uma base de dados.

Para instalar estes módulos, execute:

 pip install tk pillow 

Definir a estrutura da aplicação de pintura

O código-fonte completo deste projeto está disponível no nosso repositórioGitHub, ao qual pode aceder navegando para o URL acima mencionado.

Para começar, vamos importar os módulos necessários. De seguida, vamos criar uma instância da classe DrawApp , definir as suas propriedades, tais como o título da janela, a cor do ponteiro e a cor da borracha. Também vamos garantir que a aplicação abre em modo de ecrã inteiro, invocando o método setup_widgets() .

 import tkinter as tk
from tkinter.ttk import Scale
from tkinter import colorchooser, filedialog, messagebox
import PIL.ImageGrab as ImageGrab

class DrawApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Kids' Paint App")
        self.root.attributes("-fullscreen", True)
        self.pointer = "black"
        self.erase = "white"
        self.setup_widgets()

Para criar uma interface com widgets, estabeleça uma função chamada setup_widgets . Nesta função, crie um componente etiquetado que exiba um título, especificando a sua relação parental, a mensagem a apresentar, a configuração do tipo de letra, a tonalidade do fundo e a tonalidade do conteúdo textual. Além disso, crie uma estrutura em torno de um painel de seleção de cores, atribuindo responsabilidades como a definição do elemento parental, a inscrição a apresentar, as definições do tipo de letra e as dimensões do contorno.Por fim, configure o limite com uma série de ondulações e defina o tom de fundo como branco.

     def setup_widgets(self):
        self.title_label = tk.Label(
            self.root,
            text="Kids' Paint App",
            font=("Comic Sans MS", 30),
            bg="lightblue",
            fg="purple",
        )
        self.title_label.pack(fill=tk.X, pady=10)
        self.color_frame = tk.LabelFrame(
            self.root,
            text="Colors",
            font=("Comic Sans MS", 15),
            bd=5,
            relief=tk.RIDGE,
            bg="white",
        )
        self.color_frame.place(x=10, y=80, width=90, height=180) 

Crie uma lista para definir um conjunto de cores para a paleta de cores. Utilize a iteração para gerar um botão para cada tonalidade, tendo em conta o valor RGB correspondente. Especifique o contentor principal, a tonalidade de fundo, a espessura do rebordo, as propriedades de estilo e a largura de cada botão. Além disso, estabeleça a ação que será executada ao clicar em cada um deles. Disponha todos os componentes utilizando margens adequadas e organize as cores em pares.

         colors = [
            "blue",
            "red",
            "green",
            "orange",
            "violet",
            "black",
            "yellow",
            "purple",
            "pink",
            "gold",
            "brown",
            "indigo",
        ]
        i, j = 0, 0
        for color in colors:
            tk.Button(
                self.color_frame,
                bg=color,
                bd=2,
                relief=tk.RIDGE,
                width=3,
                command=lambda col=color: self.select_color(col),
            ).grid(row=i, column=j, padx=2, pady=2)
            i \\+= 1
            if i == 4:
                i = 0
                j = 1 

De forma semelhante, vamos delinear botões para a borracha, um para limpar o ecrã e outro para preservar a ilustração.

         self.eraser_btn = tk.Button(
            self.root,
            text="Eraser",
            bd=4,
            bg="white",
            command=self.eraser,
            width=9,
            relief=tk.RIDGE,
            font=("Comic Sans MS", 12),
        )
        self.eraser_btn.place(x=10, y=310)
        self.clear_screen_btn = tk.Button(
            self.root,
            text="Clear Screen",
            bd=4,
            bg="white",
            command=self.clear_screen,
            width=12,
            relief=tk.RIDGE,
            font=("Comic Sans MS", 12),
        )
        self.clear_screen_btn.place(x=10, y=370)
        self.save_as_btn = tk.Button(
            self.root,
            text="Save Drawing",
            bd=4,
            bg="white",
            command=self.save_as,
            width=12,
            relief=tk.RIDGE,
            font=("Comic Sans MS", 12),
        )
        self.save_as_btn.place(x=10, y=430)
        self.bg_btn = tk.Button(
            self.root,
            text="Background",
            bd=4,
            bg="white",
            command=self.canvas_color,
            width=12,
            relief=tk.RIDGE,
            font=("Comic Sans MS", 12),
        )
        self.bg_btn.place(x=10, y=490)
        self.pointer_frame = tk.LabelFrame(
            self.root,
            text="Size",
            bd=5,
            bg="white",
            font=("Comic Sans MS", 15, "bold"),
            relief=tk.RIDGE,
        ) 

Para criar um widget de escala personalizado que possa ajustar o tamanho do ponteiro e da borracha dentro de um intervalo e comprimento de pixel especificados, é necessário definir um widget de escala. Este widget deve ter um elemento pai, uma orientação e um intervalo em pixels, bem como um comprimento para a barra deslizante. Adicionalmente, seria benéfico incluir um elemento Canvas com o seu próprio elemento pai, cor de fundo, largura do rebordo e um relevo estriado com dimensões específicas.

Posicione a tela nas coordenadas adequadas e configure a sua ancoragem no canto noroeste (a margem superior esquerda). Em seguida, associe o manipulador de eventos B1-Motion à função de pintura designada. Neste contexto, “B1” significa o estado deprimido do botão esquerdo do rato, enquanto “Movimento” denota o movimento subsequente que resulta da entrada do utilizador. Essencialmente, a utilização desta configuração permite a monitorização dos movimentos do rato à medida que o botão esquerdo é continuamente premido.

         self.pointer_frame.place(x=10, y=580, height=150, width=70)
        self.pointer_size = Scale(
            self.pointer_frame, orient=tk.VERTICAL, from_=48, to=1, length=120
        )
        self.pointer_size.set(1)
        self.pointer_size.grid(row=0, column=1, padx=15)
        self.canvas = tk.Canvas(
            self.root, bg="white", bd=5, relief=tk.GROOVE, height=650, width=1300
        )
        self.canvas.place(x=160, y=120, anchor="nw")
        self.canvas.bind("<B1-Motion>", self.paint) 

Definir as características da aplicação Paint

Para executar o processo de pintura na nossa aplicação, implementámos um método chamado “paint”. Esta abordagem envolve o desenho contínuo de pequenas formas elípticas no ecrã. Para tal, calculamos o canto superior esquerdo de cada elipse subtraindo dois às coordenadas X e Y do evento mais recente do rato. Por outro lado, o canto inferior direito é determinado adicionando dois aos respectivos valores de X e Y. Em última análise, estes limites definem a forma da elipse que será criada para cada fotograma subsequente até novo aviso.

Ajuste a cor de preenchimento, a cor do contorno e a espessura da linha de acordo com a escolha do utilizador para o cursor.

     def paint(self, event):
        x1, y1 = (event.x - 2), (event.y - 2)
        x2, y2 = (event.x \\+ 2), (event.y \\+ 2)
        self.canvas.create_oval(
            x1,
            y1,
            x2,
            y2,
            fill=self.pointer,
            outline=self.pointer,
            width=self.pointer_size.get(),
        ) 

select_color , eraser , e clear_screen .A função select_color aceita um único argumento que representa um valor de cor específico, que é depois utilizado para definir a cor atual que está a ser desenhada pelo ponteiro. Isto permite uma seleção fácil de cores diferentes, conforme necessário.pythondef select_color(self, color):self.selected_color = colorDe seguida, temos a função eraser , que também requer apenas um parâmetro de entrada. É responsável por criar um efeito de “borracha” quando se desenha na tela, resultando em linhas semi-transparentes que se misturam

     def select_color(self, col):
        self.pointer = col

    def eraser(self):
        self.pointer = self.erase

    def clear_screen(self):
        self.canvas.delete("all") 

Incorpore a funcionalidade fornecida pelo método canvas_color na classe TurtleScreen de modo a abrir um seletor de cores que apresente várias tonalidades para seleção pelo utilizador. Uma vez efectuada a escolha, utilizar o método configure para estabelecer a cor de fundo do ecrã e, subsequentemente, aplicar esta cor ao aspeto do apagador.

     def canvas_color(self):
        color = colorchooser.askcolor()
        if color:
            self.canvas.configure(background=color[1])
            self.erase = color[1] 

Incorpore as etapas fornecidas em uma resposta elegante em inglês: “Defina um método chamado ‘save\_as’, que solicita que o usuário selecione um nome de arquivo e um local para salvar a captura de tela. Utilize a classe ImageGrab do Pillow para capturar o ecrã inteiro, apresentando uma caixa de diálogo de ficheiro. Uma vez selecionado, utilize técnicas de recorte utilizando as coordenadas especificadas para obter a região de tela desejada. Ajuste iterativamente as coordenadas conforme necessário para obter a área específica de interesse.

Claro! Aqui está a minha tentativa de parafrasear o teu código numa linguagem mais formal:pythondef save_image(filepath):try:p = PILImage.create(filename=filepath)if isinstance(p, ImageGrab.InvalidGrab):raise Exception(“Failed to load the image”)# Guarda a imagem e apresenta uma mensagem de confirmação boxp.save(str(filepath))tkinter.messagebox.showinfo(‘Success’, ‘The image has been saved’)except Exception as e:# Trata as excepções e apresenta uma mensagem de erro boxtkinter.messagebox.showerror(‘Error’, str(e))

     def save_as(self):
        file_path = filedialog.asksaveasfilename(
            defaultextension=".jpg", filetypes=[("Image files", "*.jpg")]
        )
        if file_path:
            try:
                y = 148
                x = 200
                y1 = 978
                x1 = 1840
                ImageGrab.grab().crop((x, y, x1, y1)).save(file_path)
                messagebox.showinfo("Save Drawing", "Image file saved successfully!")
            except Exception as e:
                messagebox.showerror("Error", f"Failed to save the image file: {e}") 

Utilize as capacidades do módulo Tkinter instanciando instâncias das classes Tk e DrawApp, ao mesmo tempo que utiliza a funcionalidade fornecida pelo método mainloop para iniciar o ciclo de eventos Tkinter e monitorizar continuamente as interacções do utilizador com a interface gráfica até esta ser fechada.

 if __name__ == "__main__":
    root = tk.Tk()
    app = DrawApp(root)
    root.mainloop() 

Testar diferentes funcionalidades de pintura utilizando Python

Ao executar a aplicação Paint, é apresentada aos utilizadores uma interface gráfica do utilizador com uma ferramenta de seleção de cores, quatro teclas funcionais, um controlo de ajuste deslizante e uma superfície de tela em branco na qual podem criar trabalhos artísticos:

/pt/images/initial-screen-of-paint-application.jpg

Seleccione uma tonalidade clicando nela e, em seguida, utilize o botão esquerdo do rato para criar um trabalho artístico na superfície da tela com a tonalidade escolhida:

/pt/images/drawing-using-different-paint-colors.jpg

Ao clicar na opção “Eraser” (Borracha) e ao deslizar o cursor vertical na direção ascendente, pode optar por aumentar a ferramenta de borracha. Para testar a sua funcionalidade, basta desenhar com o pincel selecionado e, em seguida, utilizar a borracha para remover as linhas do seu trabalho artístico.

/pt/images/increasing-size-and-erasing-in-middle.jpg

Ao clicar na opção “Limpar ecrã”, o software elimina qualquer trabalho artístico executado anteriormente. Para modificar a tonalidade do fundo, basta tocar no separador “Fundo”, que revelará um espetro de cores à escolha.

/pt/images/clearing-the-screen-and-adding-background-color.jpg

Ao selecionar a opção “Guardar desenho”, aparece uma janela que lhe permite selecionar a localização desejada e atribuir um título ao ficheiro guardado. O software guarda automaticamente o ficheiro no diretório indicado.

/pt/images/saving-the-paint-as-an-image.jpg

Melhorar a aplicação de pintura

Para aumentar a versatilidade do software de pintura, recomenda-se a implementação de uma funcionalidade que permita aos utilizadores incorporar formas geométricas nos seus trabalhos artísticos. Além disso, a disponibilização de opções para selecionar o estilo do pincel e as definições de transparência permitiria expandir ainda mais as capacidades do programa. Além disso, a integração de uma função que permita a inserção de texto e de autocolantes gráficos pode ser benéfica para alargar o âmbito das potenciais criações. Por último, a incorporação de características como a capacidade de desfazer, refazer, dimensionar ou rodar imagens simplificaria significativamente o processo geral de desenho.

Para gerar vários elementos visuais, é possível empregar uma variedade de técnicas utilizando os métodos create\_rectangle, create\_oval, create\_line e create\_polygon. Adicionalmente, para incorporar conteúdo escrito ou imagens, é possível utilizar as funções create\_text e create\_image. Além disso, se pretendido, as funcionalidades de redimensionamento e transposição do Pillow podem ser utilizadas para alterar as dimensões e a orientação das imagens.