< BACK TO PYTHON PROJECTS

Create a Paint Application in Python using Tkinter

Faraz

By Faraz - June 07, 2023

Build a paint application in Python using Tkinter with this step-by-step tutorial. Learn GUI programming and create your own drawing program today!


Paint App in Python using Tkinter.jpg

Python and Tkinter are powerful tools for creating graphical user interfaces (GUI) applications. In this tutorial, we will guide you through the process of creating a paint app using Python and Tkinter. Whether you're an aspiring developer or simply looking to explore the world of GUI programming, this tutorial will help you get started. So let's dive in and unleash your creativity!


Table of Contents


  1. Introduction
  2. Setting up the Environment
  3. Creating the Basic Structure
  4. Full Source Code
  5. Explanation of Source Code
  6. Testing and Troubleshooting
  7. Conclusion
  8. FAQs (Frequently Asked Questions)

I. Introduction


Python is a popular programming language known for its simplicity and versatility. Tkinter, on the other hand, is a standard Python library for creating GUI applications. Combining these two technologies, we can develop a paint app that allows users to draw and create amazing artworks on their computers.


II. Setting up the Environment


Before we begin, we need to set up our development environment. First, make sure you have Python installed on your system. You can download the latest version of Python from the official website and follow the installation instructions.


Once Python is installed, Tkinter should already be available, as it comes bundled with Python by default. To verify the Tkinter installation, open a Python shell and enter the following command:


import tkinter

If no errors occur, the installation is successful. Now we are ready to create our paint app!


III. Creating the Basic Structure


To start, let's create the basic structure of our paint app. We will import the necessary modules and initialize the main window. Open your favorite Python editor and create a new file called paint_app.py. In the file, enter the following code:


import tkinter as tk
from tkinter import ttk

# Initialize the main window
window = tk.Tk()
window.title("Paint App")

# Add your code here

# Start the main loop
window.mainloop()

In this code, we import the tkinter module and initialize the main window using Tk() class. We also set the title of the window to "Paint App". Now, let's proceed to the next step.


IV. Full Source Code


import tkinter as tk
from tkinter import ttk

class PaintApp:
    def __init__(self, root):
        self.root = root
        self.canvas_width = 800
        self.canvas_height = 600
        self.canvas = tk.Canvas(self.root, width=self.canvas_width, height=self.canvas_height, bg="white", bd=3, relief=tk.SUNKEN)
        self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.setup_navbar()
        self.setup_tools()
        self.setup_events()
        self.prev_x = None
        self.prev_y = None

    def setup_navbar(self):
        self.navbar = tk.Menu(self.root)
        self.root.config(menu=self.navbar)

        # File menu
        self.file_menu = tk.Menu(self.navbar, tearoff=False)
        self.navbar.add_cascade(label="File", menu=self.file_menu)
        self.file_menu.add_command(label="Save Snapshot", command=self.take_snapshot)
        self.file_menu.add_separator()
        self.file_menu.add_command(label="Exit", command=self.root.quit)

        # Edit menu
        self.edit_menu = tk.Menu(self.navbar, tearoff=False)
        self.navbar.add_cascade(label="Edit", menu=self.edit_menu)
        self.edit_menu.add_command(label="Undo", command=self.undo)

    def setup_tools(self):
        self.selected_tool = "pen"
        self.colors = ["black", "red", "green", "blue", "yellow", "orange", "purple"]
        self.selected_color = self.colors[0]
        self.brush_sizes = [2, 4, 6, 8]
        self.selected_size = self.brush_sizes[0]
        self.pen_types = ["line", "round", "square", "arrow", "diamond"]
        self.selected_pen_type = self.pen_types[0]

        self.tool_frame = ttk.LabelFrame(self.root, text="Tools")
        self.tool_frame.pack(side=tk.RIGHT, padx=5, pady=5, fill=tk.Y)

        self.pen_button = ttk.Button(self.tool_frame, text="Pen", command=self.select_pen_tool)
        self.pen_button.pack(side=tk.TOP, padx=5, pady=5)

        self.eraser_button = ttk.Button(self.tool_frame, text="Eraser", command=self.select_eraser_tool)
        self.eraser_button.pack(side=tk.TOP, padx=5, pady=5)

        self.brush_size_label = ttk.Label(self.tool_frame, text="Brush Size:")
        self.brush_size_label.pack(side=tk.TOP, padx=5, pady=5)

        self.brush_size_combobox = ttk.Combobox(self.tool_frame, values=self.brush_sizes, state="readonly")
        self.brush_size_combobox.current(0)
        self.brush_size_combobox.pack(side=tk.TOP, padx=5, pady=5)
        self.brush_size_combobox.bind("<<ComboboxSelected>>", lambda event: self.select_size(int(self.brush_size_combobox.get())))

        self.color_label = ttk.Label(self.tool_frame, text="Color:")
        self.color_label.pack(side=tk.TOP, padx=5, pady=5)

        self.color_combobox = ttk.Combobox(self.tool_frame, values=self.colors, state="readonly")
        self.color_combobox.current(0)
        self.color_combobox.pack(side=tk.TOP, padx=5, pady=5)
        self.color_combobox.bind("<<ComboboxSelected>>", lambda event: self.select_color(self.color_combobox.get()))

        self.pen_type_label = ttk.Label(self.tool_frame, text="Pen Type:")
        self.pen_type_label.pack(side=tk.TOP, padx=5, pady=5)

        self.pen_type_combobox = ttk.Combobox(self.tool_frame, values=self.pen_types, state="readonly")
        self.pen_type_combobox.current(0)
        self.pen_type_combobox.pack(side=tk.TOP, padx=5, pady=5)
        self.pen_type_combobox.bind("<<ComboboxSelected>>", lambda event: self.select_pen_type(self.pen_type_combobox.get()))

        self.clear_button = ttk.Button(self.tool_frame, text="Clear Canvas", command=self.clear_canvas)
        self.clear_button.pack(side=tk.TOP, padx=5, pady=5)

    def setup_events(self):
        self.canvas.bind("<B1-Motion>", self.draw)
        self.canvas.bind("<ButtonRelease-1>", self.release)

    def select_pen_tool(self):
        self.selected_tool = "pen"

    def select_eraser_tool(self):
        self.selected_tool = "eraser"

    def select_size(self, size):
        self.selected_size = size

    def select_color(self, color):
        self.selected_color = color

    def select_pen_type(self, pen_type):
        self.selected_pen_type = pen_type

    def draw(self, event):
        if self.selected_tool == "pen":
            if self.prev_x is not None and self.prev_y is not None:
                if self.selected_pen_type == "line":
                    self.canvas.create_line(self.prev_x, self.prev_y, event.x, event.y, fill=self.selected_color,
                                            width=self.selected_size, smooth=True)
                elif self.selected_pen_type == "round":
                    x1 = event.x - self.selected_size
                    y1 = event.y - self.selected_size
                    x2 = event.x + self.selected_size
                    y2 = event.y + self.selected_size
                    self.canvas.create_oval(x1, y1, x2, y2, fill=self.selected_color, outline=self.selected_color)
                elif self.selected_pen_type == "square":
                    x1 = event.x - self.selected_size
                    y1 = event.y - self.selected_size
                    x2 = event.x + self.selected_size
                    y2 = event.y + self.selected_size
                    self.canvas.create_rectangle(x1, y1, x2, y2, fill=self.selected_color, outline=self.selected_color)
                elif self.selected_pen_type == "arrow":
                    x1 = event.x - self.selected_size
                    y1 = event.y - self.selected_size
                    x2 = event.x + self.selected_size
                    y2 = event.y + self.selected_size
                    self.canvas.create_polygon(x1, y1, x1, y2, event.x, y2, fill=self.selected_color,
                                               outline=self.selected_color)
                elif self.selected_pen_type == "diamond":
                    x1 = event.x - self.selected_size
                    y1 = event.y
                    x2 = event.x
                    y2 = event.y - self.selected_size
                    x3 = event.x + self.selected_size
                    y3 = event.y
                    x4 = event.x
                    y4 = event.y + self.selected_size
                    self.canvas.create_polygon(x1, y1, x2, y2, x3, y3, x4, y4, fill=self.selected_color,
                                               outline=self.selected_color)
            self.prev_x = event.x
            self.prev_y = event.y

    def release(self, event):
        self.prev_x = None
        self.prev_y = None

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

    def take_snapshot(self):
        self.canvas.postscript(file="snapshot.eps")

    def undo(self):
        items = self.canvas.find_all()
        if items:
            self.canvas.delete(items[-1])

if __name__ == "__main__":
    root = tk.Tk()
    root.title("Paint Application")
    app = PaintApp(root)
    root.mainloop()

V. Explanation of Source Code


Let's go through the code and understand its different components:


1. Importing libraries:


  • tkinter: This library provides the necessary functions and classes for creating a graphical user interface (GUI) in Python.
  • ttk: This module in Tkinter provides themed widgets that have a more modern look and feel.

2. Class PaintApp:


  • This class represents the main application and contains the logic for handling user interactions and drawing on the canvas.

3. Method __init__(self, root):


  • This method is the constructor of the PaintApp class and is called when an instance of the class is created.
  • It initializes the attributes of the class, including the root window, canvas dimensions, and sets up the navbar, tools, and event bindings.
  • It also initializes variables for storing the previous x and y coordinates for drawing purposes.

4. Method setup_navbar(self):


  • This method sets up the menu bar at the top of the application window.
  • It creates a menu bar (navbar) and adds two cascading menus: "File" and "Edit".
  • Under the "File" menu, there are options to save a snapshot and exit the application.
  • Under the "Edit" menu, there is an option to undo the last drawing action.

5. Method setup_tools(self):


  • This method sets up the tools section of the application, which includes buttons, labels, and comboboxes for selecting different drawing tools, sizes, colors, and pen types.
  • It also includes a button to clear the canvas.

6. Method setup_events(self):


  • This method sets up the event bindings for the canvas.
  • It binds the left mouse button motion event (<B1-Motion>) to the draw method and the left mouse button release event (<ButtonRelease-1>) to the release method.

7. Methods for tool selection:


  • select_pen_tool(self): Sets the selected tool to "pen".
  • select_eraser_tool(self): Sets the selected tool to "eraser".
  • select_size(self, size): Sets the selected brush size.
  • select_color(self, color): Sets the selected color.
  • select_pen_type(self, pen_type): Sets the selected pen type.

8. Method draw(self, event):


  • This method is called when the user moves the mouse with the left button pressed on the canvas.
  • It draws the selected tool (pen or eraser) on the canvas based on the user's mouse movement and selected options (color, size, pen type).
  • The different pen types include line, round, square, arrow, and diamond.

9. Method release(self, event):


  • This method is called when the user releases the left mouse button on the canvas.
  • It resets the previous coordinates to None, indicating that no drawing action is in progress.

10. Method clear_canvas(self):


  • This method is called when the user clicks the "Clear Canvas" button.
  • It clears all the items drawn on the canvas by deleting everything.

11. Method take_snapshot(self):


  • This method is called when the user selects the "Save Snapshot" option from the "File" menu.
  • It captures the current state of the canvas and saves it as a PostScript file named "snapshot.eps".

12. Method undo(self):


  • This method is called when the user selects the "Undo" option from the "Edit" menu.
  • It deletes the most recent item drawn on the canvas, effectively undoing the last drawing action.

13. Main section:


  • The code block under if __name__ == "__main__": is executed when the script is run as the main program.
  • It creates the root window (root), sets the title, and creates an instance of the PaintApp class (app).
  • Finally, it starts the Tkinter event loop by calling root.mainloop(), which listens for user interactions and updates the GUI accordingly.

VI. Testing and Troubleshooting


Before we conclude, it's essential to test our paint app and handle any potential issues that may arise. Run the paint_app.py file and test the drawing functionality, color selection, additional features, saving and loading, and interface customization. If you encounter any issues, check your code for errors or consult the official documentation for Python and Tkinter.


VII. Conclusion


Congratulations! You have successfully created a paint app in Python using Tkinter. We explored the process of setting up the environment, creating the basic structure, implementing drawing functionality, adding colors and brushes, including additional features, enabling the saving and loading of drawings, customizing the interface, and testing the app. Now you can unleash your creativity and create amazing artwork with your paint app.


Feel free to explore further and add more features to enhance your paint app. Tkinter provides a wide range of widgets and options for creating interactive GUI applications. Enjoy your coding journey and keep discovering the vast possibilities of Python and Tkinter!


VIII. FAQs (Frequently Asked Questions)


Q1: Can I run this paint app on any operating system?

A1: Yes, you can run this paint app on any operating system that supports Python and Tkinter.


Q2: Is it possible to resize the canvas in the paint app?

A2: Yes, you can resize the canvas by modifying the width and height parameters when creating the canvas widget.


Q3: How can I change the default background color of the canvas?

A3: You can change the background color of the canvas by modifying the bg parameter when creating the canvas widget.


Q4: Can I add more brush sizes to the paint app?

A4: Yes, you can add more brush sizes by creating additional buttons and implementing the desired functionality for each size.


Q5: Is it possible to export the drawing as a different file format?

A5: By default, the paint app saves the drawing as an image file in a format supported by Tkinter. However, you can explore external libraries to export the drawing in different file formats if needed.

That’s a wrap!

I hope you enjoyed this article

Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee.

And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!

Thanks!
Faraz 😊

End of the article

Subscribe to my Newsletter

Get the latest posts delivered right to your inbox


Latest Post