Exploring More in Tkinter

posted 10 min read

In this article, we'll delve into some of the more intricate aspects of Tkinter, exploring advanced techniques that will empower you to create even more powerful and polished GUI applications. Throughout our exploration, we'll uncover invaluable tools such as the ttk module for enhanced widget styling, the Canvas widget for versatile graphics rendering, and the Grid geometry manager for precise layout control. From custom themes to file handling strategies, gear up to elevate your Tkinter expertise to the next level.

If you are new to Tkinter, I highly recommend you to thoroughly review this article or the official documentation. Familiarizing yourself with its contents will provide a solid foundation for understanding and effectively utilizing Tkinter.

In the code snippets provided, add these lines in the beginning:

import tkinter as tk
from tkinter import ttk
window = tk.Tk()
window.geometry("457x335")

and this line at the end:

window.mainloop()

Custom Styles and Themes

Tkinter enables customized visual presentation through custom styles and themes, using the ttk module for personalized widget designs, ensuring consistency across platforms.

To deepen our understanding, let's personalize our textbox, button, and label by customizing their appearance:

import tkinter as tk
from tkinter import ttk

def submit_text():
    text = text_entry.get()
    text_label.config(text=text, font=("Times New Roman", 12, "bold"), foreground="green")     #customize label

window = tk.Tk()
window.geometry("457x335")
window.title("Custom Styles")

style = ttk.Style()     #to define custom styles
style.configure("Custom.TEntry", foreground="blue", fieldbackground="lightblue")     #customize textbox
style.configure("Custom.TButton", foreground="red", background="red")     #customize button

text_entry = ttk.Entry(window, width=30, style="Custom.TEntry")
text_entry.pack(padx=10, pady=10)
submit_button = ttk.Button(window, text="Submit", command=submit_text, style="Custom.TButton")     #sends entered text to the submit_text() function
submit_button.pack(padx=10, pady=5)
text_label = ttk.Label(window)
text_label.pack(padx=10, pady=10)
window.mainloop()

Tkinter_custom

The submit_text function retrieves your text from the text_entry textbox and updates the text_label with it. The label's appearance is customized using Times New Roman font, size 12, bold, and green color. Custom styles (Custom.TEntry for the textbox and Custom.TButton for the button) are defined and configured using the ttk.Style() method to set properties like foreground and background colors.

Integration with Python Libraries

Tkinter can be integrated with other Python libraries and tools to enhance its functionality:

  • Integration with Matplotlib: You can make your Tkinter app more informative by adding interactive charts to display data trends or visualizations. By integrating Matplotlib, a popular Python library for creating charts and graphs, you can easily embed dynamic plots directly into your Tkinter windows.

  • Integration with Scikit-learn: You can combine Tkinter with Scikit-learn to develop GUI applications for machine learning tasks such as classification, regression, and clustering. This integration enables us to build interactive interfaces for training models, evaluating performance, and making predictions.

Note: In order to install sklearn library locally, run the command: `pip install scikit-learn`
Caution: Ensure local compatibility by installing `matplotlib` and `matplotlib.backends.backend_tkagg` before running this code.

Let's delve into the concept using an example of Linear Regression applied to predict outcomes for the Diabetes dataset:

import tkinter as tk
from tkinter import ttk     #for themed widgets
import matplotlib.pyplot as plt
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

diabetes = load_diabetes()     #Load the dataset
X_train, X_test, y_train, y_test = train_test_split(diabetes.data, diabetes.target, test_size=0.2, random_state=42)

window = tk.Tk()
window.geometry("650x500")
window.title("Diabetes Linear Regression")

def train_and_plot():
    model = LinearRegression()
    model.fit(X_train, y_train)     #train
    y_pred_train = model.predict(X_train)     #predict
    y_pred_test = model.predict(X_test)
    mse_train = mean_squared_error(y_train, y_pred_train)     #calculate mean squared error
    mse_test = mean_squared_error(y_test, y_pred_test)
    
    plt.figure(figsize=(8, 6))     #create the plot
    plt.scatter(y_test, y_pred_test, color='blue')
    plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], color='red', linestyle='--')
    plt.xlabel("Actual")
    plt.ylabel("Predicted")
    plt.title("Linear Regression Graph")
    plt.grid(True)
    plt.tight_layout()     #ensures the plot fits within the Tkinter window
    result_label.config(text=f"Train MSE: {mse_train:.2f}\tTest MSE: {mse_test:.2f}")
    canvas = FigureCanvasTkAgg(plt.gcf(), master=window)     #converts the plot into a format that can be displayed in the Tkinter window
    canvas.draw()
    canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)     #adds the canvas widget to the Tkinter window.

train_button = ttk.Button(window, text="Train and Plot", command=train_and_plot)
train_button.pack(pady=10)
result_label = ttk.Label(window, text="")
result_label.pack()
window.mainloop()

Tkinter_interface

The train_and_plot function trains a linear regression model on the dataset, predicts the target values, calculates the mean squared error for both training and testing sets, and then plots the predicted values against the actual values using matplotlib. It also displays the calculated mean squared errors on your GUI window.

Advanced Widgets

Tkinter provides a wide range of widgets beyond the basic ones like labels and buttons. You can explore and utilize widgets like treeview, notebook, progressbar, etc. to create sophisticated user interfaces.

  • A treeview to display hierarchical data, like a file explorer.

     import tkinter as tk
     from tkinter import ttk     #for themed widgets
     window = tk.Tk()
     window.geometry("640x300")
     tree = ttk.Treeview(window)
     tree["columns"] = ("Fruits", "Quantity")
     tree.heading("#0", text="Sr. No.")     #First column (index=0) will be Sr. No.
     tree.heading("Fruits", text="Fruits")
     tree.heading("Quantity", text="Quantity (kg)")
     tree.insert("", tk.END, text="1", values=("Apple", 30))
     tree.insert("", tk.END, text="2", values=("Orange", 25))
     tree.insert("", tk.END, text="3", values=("Mango", 29))
     tree.pack()
     window.mainloop()
    
    

    treeview

The Treeview widget tree consists of two columns: "Fruits" and "Quantity (kg)". The heading method sets headings for each column, and the insert method adds items to the Treeview. Each item is inserted with a unique identifier "Sr. No." and its corresponding values for "Fruits" and "Quantity" are entered.

  • A notebook to organize your app into different tabs, like in a web browser.

     import tkinter as tk
     from tkinter import ttk     #for themed widgets
     window = tk.Tk()
     window.geometry("457x335")
     notebook = ttk.Notebook(window)
     tab1 = ttk.Frame(notebook)
     tab2 = ttk.Frame(notebook)
     tab3 = ttk.Frame(notebook)
     label1 = tk.Label(tab1, text="This is Tab 1")     #for tab 1
     label1.pack()
     entry2 = tk.Entry(tab2)     #for tab 2
     entry2.pack()
     check_var = tk.BooleanVar()
     check_button3 = tk.Checkbutton(tab3, text="This is Tab 3", variable=check_var)     #for tab 3
     check_button3.pack()
     notebook.add(tab1, text="Tab 1")
     notebook.add(tab2, text="Tab 2")
     notebook.add(tab3, text="Tab 3")
     notebook.pack()
     window.mainloop()
    
    

    Tab1

    Tab2

    Tab3

It creates a Notebook widget notebook, which allows 3 tabs to be displayed, namely Tab 1, Tab 2, and Tab 3, ceated using ttk.Frame. Tab 1 contains a Label widget with the text "This is Tab 1". Tab 2 contains an Entry widget for user input. Tab 3 contains a Checkbutton widget with the text "This is Tab 3".

  • A progressbar to show how far along a task is, like when you're downloading a file.

     import tkinter as tk
     from tkinter import ttk
     import time
        
     def start_task():
         progress_bar.start(10)     #start the progressbar (animation is updated every 10 milliseconds)
         window.after(3000, stop_task)     #simulate task completion after 3 seconds
        
     def stop_task():
         progress_bar.stop()      #stop the progressbar
        
     window = tk.Tk()
     window.geometry("457x335")
     progress_bar = ttk.Progressbar(window, orient="horizontal", length=200, mode="indeterminate")
     progress_bar.pack()
     start_button = tk.Button(window, text="Start Task", command=start_task)
     start_button.pack(pady=20)
     window.mainloop()
    

    Tkinter_progressbar

When the "Start Task" button is clicked, it triggers the start_task function, which starts the progress bar animation using the start method. The after method is used to schedule the stop_task function to run after 3 seconds. The stop_task function stops the progress bar animation using the stop method.

Advanced Layout Management

Advanced Layout Management can be used to make your Tkinter app look polished. Layout management helps you move widgets around and make your app look just the way you want using grid, place, and pack managers.

  • Grid
    You can place widgets in rows and columns, and they will organize neatly into place.

      import tkinter as tk
      window = tk.Tk()
      window.geometry("457x335")
      label1 = tk.Label(window, text="Subject")
      label2 = tk.Label(window, text="Marks")
      entry1 = tk.Entry(window)     #Widgets
      entry2 = tk.Entry(window)
      entry3 = tk.Entry(window)
      entry4 = tk.Entry(window)
      label1.grid(row=0, column=0)     #Layout
      label2.grid(row=0, column=1)
      entry1.grid(row=1, column=0)
      entry2.grid(row=1, column=1)
      entry3.grid(row=2, column=0)
      entry4.grid(row=2, column=1)
      window.mainloop()
    

    Tkinter_grid

This code sets up 2 labels Subject and Marks and 4 entry widgets for data input. The layout is organized with Subject in row 0, column 0, Marks in row 0, column 1. Entry widgets entry1 and entry2 occupy row 1, columns 0 and 1 respectively, while entry3 and entry4 are in row 2, columns 0 and 1.

  • Pack
    You can stack widgets on top of each other or arrange them side by side, and Tkinter will figure out how to fit them all in.

      import tkinter as tk
      window = tk.Tk()
      window.geometry("457x335")
      button1 = tk.Button(window, text="Left")     #Widgets
      button2 = tk.Button(window, text="Top")
      button3 = tk.Button(window, text="Right")
      button4 = tk.Button(window, text="Bottom")
      button1.pack(side=tk.LEFT)     #Layout
      button2.pack(side=tk.TOP)
      button3.pack(side=tk.RIGHT)
      button4.pack(side=tk.BOTTOM)
      window.mainloop()
    

    Tkinter_pack

The buttons button1, button2, button3 and button4 are positioned by providing the side parameter with values tk.LEFT, tk.TOP, tk.RIGHT, or tk.BOTTOM respectively.

  • Place
    You can specify exactly where you want each widget to go by giving it coordinates, like x and y coordinates on a graph.

      import tkinter as tk
      window = tk.Tk()
      window.geometry("457x335")
      label1 = tk.Label(window, text="x_50_y_50")     #Widgets
      label2 = tk.Label(window, text="x_200_y_200")
      label1.place(x=50, y=50)     #Layout
      label2.place(x=200, y=200)
      window.mainloop()
    
    

    Tkinter_place

The place method is used to position label widgets. label1 is placed at coordinates (50, 50), and label2 is placed at coordinates (200, 200).

File Handling

Tkinter facilitates file handling through the filedialog tool, enabling users to interactively select files on their computer. With this feature, your application can support tasks like creating, opening, saving, and editing various file types such as documents, images, or spreadsheets.

Let's understand this using an example:

import tkinter as tk
from tkinter import filedialog

def open_file():
    file_path = filedialog.askopenfilename()     #opens a dialog window to select an existing file or create a new one
    if not file_path:
        return
    with open(file_path, 'a+') as file:     #'a+' to append the text to the file
        file.write("January\n")
        file.write("February\n")
        file.write("March\n")
        file.write("April\n")
        file.write("May\n")
    status_label.config(text=f"File '{file_path}' has been written and closed.")

window = tk.Tk()
window.geometry("457x335")
window.title("File Writer")
open_button = tk.Button(window, text="Open a File", command=open_file)
open_button.pack(pady=20)
status_label = tk.Label(window, text="")
status_label.pack()
root.mainloop()

file

file_open_1

file_open_2

When clicked, the button "Open a File" triggers the open_file function, which opens a dialog window allowing you to select an existing file or create a new one. If a file is selected, the code appends the strings "January", "February"..."May" to the file and the file is closed. The status_label is then updated to display a message confirming the file write operation.

Note: The file will automatically be closed when the `with` block is exited. However, you may explicitly close the file by calling `file.close()`.

Modal and Modeless Dialogs

Tkinter offers both modal and modeless dialogs, ideal for user input, confirmation messages, or notifications. The tkinter.messagebox module provides standard message boxes, while custom dialog windows can be created using Toplevel widgets.

  • Modal dialogs are windows that require the user to interact with them before returning to the main application window. They typically block interaction with other windows in the application until they are closed.

      import tkinter as tk
      from tkinter import messagebox
    
      def show_modal_dialog():
          messagebox.showinfo("Modal Dialog", "Pay attention to this dialog box!")     #does not let you proceed until you click the "OK" button
    
      window = tk.Tk()
      window.geometry("457x335")
      window.title("Modal Dialog Example")
      modal_button = tk.Button(window, text="Click me", command=show_modal_dialog)
      modal_button.pack(padx=20, pady=10)
      window.mainloop()
    

    Tkinter_modal_dialog

  • Modeless dialogs are windows that allow the user to interact with both the dialog and the main application window simultaneously. They do not block interaction with other windows in the application, allowing the user to switch between them freely.

      import tkinter as tk
    
      def show_modeless_dialog():
          modeless_dialog = tk.Toplevel(window)     #allows you to interact with other open windows
          modeless_dialog.title("Modeless Dialog")
          modeless_dialog.geometry("250x100")
          label = tk.Label(modeless_dialog, text="Have a nice day!")
          label.pack(padx=20, pady=10)
    
      window = tk.Tk()
      window.geometry("457x335")
      window.title("Modeless Dialog Example")
      modeless_button = tk.Button(window, text="Click me", command=show_modeless_dialog)
      modeless_button.pack(padx=20, pady=10)
      window.mainloop()
    

    Tkinter_modaless_dialog

When clicked, the button "Click me" triggers the show_modeless_dialog function, which creates a modeless dialog box using the Toplevel widget. It will not hinder your interaction with the other windows.

Tip: Using a class for modeless dialogs can organize and encapsulate dialog functionality, particularly for more intricate dialogs with multiple components and interactions.

Conclusion

Tkinter is a versatile Python GUI framework that enhances user interaction and functionality. With features like custom themes, threading, file handling, dialogs, layout management, advanced widgets, and integration with libraries like Matplotlib and scikit-learn, Tkinter empowers developers to create dynamic desktop applications. By leveraging these capabilities, developers can craft unique GUIs that elevate user experience, making Tkinter a top choice for Python GUI projects.

If you read this far, tweet to the author to show them you care. Tweet a Thanks

More Posts

Tkinter library in Python

Tejas Vaij - Mar 12, 2024

Building a Calculator using tkinter

Tejas Vaij - Apr 2, 2024

Tkinter ToDo GUI Application (Step by Step Guide)

Tejas Vaij - Mar 27, 2024

Convert Tkinter Python App to .Exe File [pyinstaller] Step by Step Guide

Tejas Vaij - Apr 1, 2024

Build a Discord python assistant with plain Langchain

Astra Bertelli - Jun 1, 2024
chevron_left