GUI Programming With Python
GUI Programming With Python
First edition
DISCLAIMER
Chapter One: Introduction to GUI Programming
Importance of GUIs in Software Applications
Overview of Popular Python GUI Frameworks
Tkinter
PyQt
wxPython
Setting Up Your Development Environment
Setting Up Virtual Environments
Setting Up Your IDE
Basic Concepts of GUI Programming
Chapter Two: Getting Started with Tkinter
Combobox
Spinbox
Chapter Three: Tkinter Layout Management
Chapter Four: Advanced Tkinter
Using Canvas for Drawing
Introduction to Canvas
Chapter Five: Getting Started with PyQt
Setting Up Your Development Environment for PyQt
Chapter Ten: PyQt Widgets and Controls
Chapter Ten: PyQt Layout Management
Grid Layouts (QGridLayout)
Form Layouts (QFormLayout)
Chapter Eleven: Advanced PyQt
Subclassing QWidget
Animations with QPropertyAnimation and QGraphicsView
Integrating PyQt with Databases
Chapter Twelve: Deploying PyQt Applications
Conclusion
DISCLAIMER
The concept of graphical user interfaces dates back to the 1960s, with early
experiments at institutions like Stanford Research Institute and Xerox PARC.
The first widely recognized GUI was developed by Xerox PARC for the Xerox
Alto computer in the 1970s. Apple and Microsoft later popularized GUIs in
the 1980s with the release of the Macintosh and Windows operating systems,
respectively.
Python, known for its simplicity and versatility, has a rich history of GUI
development frameworks. Over the years, several libraries have emerged, each
with unique features and advantages:
1. Tkinter: The standard GUI library for Python, known for its simplicity
and ease of use.
2. PyQt: A set of Python bindings for the Qt application framework,
offering a comprehensive set of tools for creating cross-platform
applications.
3. wxPython: A wrapper for the wxWidgets C++ library, providing native
look-and-feel GUIs on multiple platforms.
Importance of GUI Programming
While GUIs offer numerous benefits, they also present unique challenges for
developers:
1. Complexity: Designing and implementing a GUI can be more complex
than a command-line interface, requiring careful planning and testing.
2. Cross-Platform Compatibility: Ensuring that a GUI works
consistently across different operating systems can be challenging.
3. Performance: GUIs can be resource-intensive, requiring optimization to
ensure smooth performance.
4. Usability: Creating an intuitive and accessible interface requires a deep
understanding of user needs and behaviors.
Future of GUI Programming
Tkinter
Introduction to Tkinter
Tkinter is the standard GUI library included with Python, making it readily
available and easy to use for beginners and experienced developers alike.
It provides a simple way to create windows, dialogs, and various widgets like
buttons, labels, and text fields.
Key Features
Ease of Use: Tkinter is known for its straightforward and beginner-
friendly API.
Lightweight: As a lightweight framework, Tkinter is suitable for small to
medium-sized applications.
Cross-Platform: Tkinter applications can run on Windows, macOS, and
Linux without modification.
Limitations
Limited Advanced Features: Tkinter may lack some of the advanced
features and customization options found in other frameworks.
Outdated Look and Feel: Tkinter’s default widgets have a more dated
appearance compared to modern GUI frameworks.
PyQt
Introduction to PyQt
PyQt is a set of Python bindings for the Qt application framework, known for
its comprehensive set of tools for creating sophisticated and feature-rich
desktop applications.
Key Features
Rich Widget Set: PyQt offers a wide range of widgets, including
advanced controls like tree views, table views, and graphics view
frameworks.
Designer Tool: Qt Designer allows developers to design GUIs visually,
generating the corresponding PyQt code automatically.
Cross-Platform: PyQt applications can run on Windows, macOS, and
Linux.
Limitations
Complexity: PyQt has a steeper learning curve compared to Tkinter,
due to its extensive feature set and more complex API.
Licensing: PyQt is available under the GPL and a commercial license,
which may impose limitations on certain types of projects.
wxPython
Introduction to wxPython
wxPython is a Python wrapper for the wxWidgets C++ library, providing a
native look and feel for applications on various platforms.
It is known for its flexibility and the ability to create highly customizable and
responsive applications.
Key Features
Native Look and Feel: wxPython uses the native widgets of the
operating system, ensuring that applications look and behave like native
applications.
Comprehensive Widget Set: wxPython includes a wide range of
widgets and controls, supporting complex layouts and interactions.
Cross-Platform: wxPython applications can run on Windows, macOS,
and Linux.
Limitations
Complexity: wxPython can be more challenging to learn and use
compared to Tkinter, especially for beginners.
Documentation: The documentation for wxPython can be less
comprehensive and up-to-date compared to other frameworks.
Comparison of Tkinter, PyQt, and wxPython
Ease of Use
Tkinter: Best for beginners due to its simplicity and straightforward API.
PyQt: Suitable for developers with some experience, offering a rich set of
features.
wxPython: Requires a steeper learning curve but provides a native look
and feel.
Feature Set
Tkinter: Basic set of widgets and controls.
PyQt: Extensive widget set with advanced features.
wxPython: Comprehensive widget set with native look and feel.
Performance
Tkinter: Lightweight and efficient for small to medium-sized
applications.
PyQt: Can handle complex and resource-intensive applications.
wxPython: Offers good performance with a native look and feel.
Community and Support
Tkinter: Strong community support and extensive online resources.
PyQt: Active community with extensive documentation and commercial
support.
wxPython: Smaller community but dedicated and helpful resources.
In this book, we will delve into each of these frameworks, exploring their
features, strengths, and use cases. By the end of this journey, you will have a
solid understanding of how to leverage Tkinter, PyQt, and wxPython to create
powerful and user-friendly desktop applications.
Installing Python
Installing Tkinter
Installing PyQt
Ensure your virtual environment is activated.
Install PyQt using pip: pip install PyQt5
Verify the installation by running: python -c “from PyQt5 import
QtWidgets”
Installing wxPython
Ensure your virtual environment is activated.
Install wxPython using pip: pip install wxPython
Verify the installation by running: python -c “import wx”
Choosing and Setting Up an IDE
Event-Driven Programming
Event Loop
Event Handlers
Event handlers are functions or methods that define the behavior of the
application in response to specific events.
For example, a button click event might trigger a function that performs a
certain action, such as opening a new window or saving data to a file.
Introduction to Widgets
Widgets, also known as controls, are the basic building blocks of a GUI. They
represent the graphical elements that users interact with.
Types of Widgets
Buttons: Used to trigger actions or events when clicked by the user.
Labels: Display static text or images.
Text Fields: Allow users to input and edit text.
Checkboxes: Enable users to select or deselect options.
Radio Buttons: Allow users to choose one option from a group.
Sliders: Provide a way to adjust a value within a range.
Containers: Widgets like frames or panels that can hold and organize
other widgets.
Creating and Configuring Widgets
Widgets are created using specific classes provided by the GUI framework
(e.g., Button, Label in Tkinter).
They can be configured with various properties such as size, color, font, and
event bindings.
Layout Management
Proper layout management ensures that the GUI is responsive and looks
consistent across different screen sizes and resolutions.
Layout Managers
Pack Geometry Manager (Tkinter): Packs widgets into a container in a
specified order (top, bottom, left, right).
Grid Geometry Manager (Tkinter): Organizes widgets in a grid of rows
and columns.
Place Geometry Manager (Tkinter): Positions widgets at specific
coordinates.
Box Layouts (PyQt and wxPython): Arranges widgets in a horizontal or
vertical box.
Grid Layouts (PyQt and wxPython): Arranges widgets in a grid.
Form Layouts (PyQt): Organizes widgets in a form-like layout.
Best Practices for Layout Management
Event Binding
In Tkinter, events are bound using the bind method, while PyQt and
wxPython use signals and slots.
Common Events
Button Click: Triggered when a button is pressed.
Key Press: Triggered when a key is pressed on the keyboard.
Mouse Events: Include mouse clicks, movement, and scroll events.
Focus Events: Occur when a widget gains or loses focus.
Event Propagation
Events can propagate through the widget hierarchy, allowing parent widgets to
handle events from their child widgets.
Event propagation can be controlled to stop or continue the flow of
events as needed.
Chapter Two: Getting Started with Tkinter
I ntroduction to Tkinter
Tkinter is the standard GUI library for Python and is included with most
Python installations. It provides a fast and easy way to create simple graphical
user interfaces. In this section, we will introduce Tkinter and cover the basics
of creating a Tkinter application.
What is Tkinter?
Overview
Tkinter is a thin object-oriented layer on top of the Tcl/Tk GUI toolkit.
It provides a range of standard GUI elements such as buttons, menus, and
text fields, which can be used to build desktop applications.
History
Tkinter was developed as a Python binding to the Tcl/Tk toolkit.
It has been included with Python since version 1.5 and has become the de
facto standard GUI toolkit for Python.
Setting Up
Ensure Python is installed on your system.
Tkinter is included with Python, so no additional installation is needed.
import tkinter as tk
root = tk.Tk()
root.title("Hello Tkinter")
root.mainloop()
python hello_tkinter.py
root.destroy()
Buttons
Introduction to Buttons
Buttons are interactive elements that users can click to trigger an action
or event.
In Tkinter, buttons are created using the Button class.
Creating a Button
To create a button, you need to specify its parent widget, text, and
command (the function to call when the button is clicked):
import tkinter as tk
def on_button_click():
print("Button clicked!")
root = tk.Tk()
button = tk.Button(root, text="Click Me",
command=on_button_click)
button.pack()
root.mainloop()
Button Events
Buttons can respond to different events, not just clicks. You can bind other
events using the bind method:
def on_button_enter(event):
print("Mouse entered button area")
button.bind("<Enter>", on_button_enter)
Labels
Introduction to Labels
Labels are used to display static text or images in a GUI application.
In Tkinter, labels are created using the Label class.
Creating a Label
To create a label, you need to specify its parent widget and the text or
image to display:
image = tk.PhotoImage(file="path_to_image.png")
label = tk.Label(root, image=image)
label.pack()
Entry Widgets
user_input = entry.get()
print(user_input)
Use the delete and insert methods to modify the text in an entry widget:
In addition to basic widgets, Tkinter provides more advanced widgets like text
widgets for multi-line text input, canvas for drawing and graphical content,
and frames for organizing and grouping other widgets. This section will cover
the usage and features of these widgets.
Text Widgets
Use the insert and delete methods to modify the text content:
def on_text_change(event):
print("Text content changed")
text.bind("<<Modified>>", on_text_change)
Canvas
Introduction to Canvas
Canvas is a versatile widget that allows for drawing shapes, images, and
other graphical content.
In Tkinter, canvas widgets are created using the Canvas class.
Creating a Canvas
To create a canvas, you need to specify its parent widget and dimensions:
image = tk.PhotoImage(file="path_to_image.png")
canvas.create_image(200, 150, image=image)
Canvas Events
Bind events to canvas elements for interactive applications:
def on_canvas_click(event):
print(f"Clicked at {event.x}, {event.y}")
canvas.bind("<Button-1>", on_canvas_click)
Frames
Introduction to Frames
Frames are container widgets used to organize and group other widgets.
In Tkinter, frames are created using the Frame class.
Creating a Frame
To create a frame, you need to specify its parent widget:
Nested Frames
Frames can be nested within other frames to create complex layouts:
Tkinter provides widgets for selecting items from a list, choosing options from
a dropdown, and incrementing or decrementing values. This section covers
the Listbox, Combobox, and Spinbox widgets, which enhance the interactivity
and functionality of your GUI applications.
Listbox
Introduction to Listbox
A Listbox widget displays a list of items from which the user can select one or
more items.
Creating a Listbox
listbox = tk.Listbox(root)
listbox.pack()
def get_selected_item():
selected_indices = listbox.curselection()
selected_items = [listbox.get(i) for i in selected_indices]
print(selected_items)
button = tk.Button(root, text="Get Selected Item",
command=get_selected_item)
button.pack()
Combobox
Introduction to Combobox
A Combobox is a combination of a dropdown list and an entry field,
allowing users to select an item from a list or enter their own value.
In Tkinter, Combobox is part of the ttk module and created using the
Combobox class.
Creating a Combobox
To create a Combobox, you need to import ttk and specify its parent
widget:
def get_selected_value():
print(combobox.get())
button = tk.Button(root, text="Get Selected Value",
command=get_selected_value)
button.pack()
Spinbox
Introduction to Spinbox
A Spinbox widget allows users to select a value from a range by
incrementing or decrementing the value using arrow buttons.
In Tkinter, Spinbox is created using the Spinbox class.
Creating a Spinbox
To create a Spinbox, you need to specify its parent widget and the range of
values:
def on_spinbox_change():
print("Spinbox value changed:", spinbox.get())
spinbox.config(command=on_spinbox_change)
Chapter Three: Tkinter Layout Management
Overview
The Pack geometry manager organizes widgets in blocks before placing
them in the parent widget.
Widgets can be arranged in four directions: top, bottom, left, and right.
Basic Usage
To use the Pack geometry manager, call the pack method on a widget:
import tkinter as tk
root = tk.Tk()
button1 = tk.Button(root, text="Button 1")
button1.pack()
root.mainloop()
Packing Widgets
Packing Order
Widgets are packed in the order they are created and packed.
The first widget packed is placed at the edge specified, and subsequent
widgets are placed next to the previous one.
Side Option
The side option determines the side of the parent widget against which
the widget will be packed.
Valid values are tk.TOP, tk.BOTTOM, tk.LEFT, and tk.RIGHT:
button1.pack(side=tk.LEFT)
button2.pack(side=tk.RIGHT)
Fill Option
The fill option determines whether the widget should expand to fill any
extra space in the parent widget.
Valid values are tk.NONE, tk.X, tk.Y, and tk.BOTH:
button1.pack(fill=tk.X)
button2.pack(fill=tk.Y)
Expand Option
The expand option specifies whether the widget should expand to fill any
extra space in the parent widget.
It takes a boolean value (True or False):
button1.pack(expand=True)
Padding
Padding adds space inside and/or outside the widget.
Use the padx and pady options to add horizontal and vertical padding inside
the widget:
button1.pack(padx=10, pady=5)
Margins
Use the ipadx and ipady options to add horizontal and vertical padding
outside the widget:
button1.pack(ipadx=10, ipady=5)
Nested Layouts
You can nest widgets by placing one widget inside another and then
packing the inner widget:
frame = tk.Frame(root)
frame.pack(side=tk.TOP, fill=tk.X)
button1 = tk.Button(frame, text="Button 1")
button2 = tk.Button(frame, text="Button 2")
button1.pack(side=tk.LEFT)
button2.pack(side=tk.RIGHT)
root = tk.Tk()
top_frame = tk.Frame(root)
top_frame.pack(side=tk.TOP, fill=tk.X)
button1 = tk.Button(top_frame, text="Button 1")
button2 = tk.Button(top_frame, text="Button 2")
button1.pack(side=tk.LEFT)
button2.pack(side=tk.RIGHT)
bottom_frame = tk.Frame(root)
bottom_frame.pack(side=tk.BOTTOM, fill=tk.X)
button3 = tk.Button(bottom_frame, text="Button 3")
button4 = tk.Button(bottom_frame, text="Button 4")
button3.pack(side=tk.LEFT)
button4.pack(side=tk.RIGHT)
root.mainloop()
Overview
The Grid geometry manager arranges widgets in a grid of rows and
columns.
Each cell in the grid can contain one widget, and widgets can span
multiple rows or columns.
Basic Usage
To use the Grid geometry manager, call the grid method on a widget:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="Label")
label.grid(row=0, column=0)
root.mainloop()
Sticky Option
The sticky option determines how the widget expands to fill the cell. Valid
values are combinations of N, S, E, and W:
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
Weight Option
The weight option determines how extra space is distributed among rows
and columns. A higher weight value means the row or column will expand
more:
root.grid_rowconfigure(0, weight=1)
root.grid_rowconfigure(1, weight=2)
Padding
Use the padx and pady options to add padding inside and outside the
widget:
IPadding
Use the ipadx and ipady options to add internal padding to the widget:
root = tk.Tk()
for i in range(5):
for j in range(5):
tk.Button(root, text=f"R{i}C{j}").grid(row=i, column=j,
padx=5, pady=5, sticky="NSEW")
for i in range(5):
root.grid_rowconfigure(i, weight=1)
root.grid_columnconfigure(i, weight=1)
root.mainloop()
The Place geometry manager is a flexible but less commonly used layout
manager in Tkinter that allows you to specify the exact location and size of
widgets within a parent widget. This approach is useful for applications where
precise control over widget placement is required. In this section, we will
explore the basics of the Place geometry manager and how to use it to position
widgets.
Overview
The Place geometry manager positions widgets based on explicit
coordinates.
It offers precise control over widget placement and size.
Basic Usage
To use the Place geometry manager, call the place method on a widget and
specify the desired coordinates and size:
import tkinter as tk
root = tk.Tk()
button = tk.Button(root, text="Click Me")
button.place(x=50, y=50, width=100, height=30)
root.mainloop()
Configuring Placement
Absolute Positioning
Widgets can be positioned using absolute coordinates (x, y):
button.place(x=100, y=150)
Relative Positioning
Widgets can also be positioned relative to the parent widget’s size using
relx and rely:
Specifying Size
The size of widgets can be specified using absolute or relative dimensions:
button.place(width=100, height=50)
button.place(relwidth=0.5, relheight=0.3)
Anchoring
The anchor option specifies which part of the widget is placed at the (x, y)
or (relx, rely) position:
Examples
Simple Placement Example
root = tk.Tk()
label1 = tk.Label(root, text="Label 1", bg="red")
label1.place(x=20, y=20, width=80, height=30)
label2 = tk.Label(root, text="Label 2", bg="green")
label2.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
root.mainloop()
root = tk.Tk()
for i in range(5):
for j in range(5):
button = tk.Button(root, text=f"R{i}C{j}")
button.place(relx=j*0.2, rely=i*0.2, relwidth=0.18,
relheight=0.18)
root.mainloop()
Menus
Introduction to Menus
Menus are used to organize application commands in a hierarchical
structure.
In Tkinter, menus are created using the Menu class.
Creating a Menu Bar
The menu bar is the top-level menu that holds all other menus:
root = tk.Tk()
menubar = tk.Menu(root)
root.config(menu=menubar)
file_menu.add_command(label="New", command=new_file)
file_menu.add_command(label="Open", command=open_file)
file_menu.add_separator()
file_menu.add_command(label="Exit", command=root.quit)
Submenus
Create submenus by adding another Menu to an existing menu:
Toolbars
Introduction to Toolbars
Toolbars provide quick access to frequently used commands.
In Tkinter, toolbars are typically created using the Frame widget.
Creating a Toolbar
Create a frame for the toolbar and pack it at the top of the window:
new_icon = tk.PhotoImage(file="new_icon.png")
new_button = tk.Button(toolbar, image=new_icon,
command=new_file)
new_button.image = new_icon # Keep a reference to avoid garbage
collection
new_button.pack(side=tk.LEFT, padx=2, pady=2)
open_icon = tk.PhotoImage(file="open_icon.png")
open_button = tk.Button(toolbar, image=open_icon,
command=open_file)
open_button.image = open_icon # Keep a reference to avoid
garbage collection
open_button.pack(side=tk.LEFT, padx=2, pady=2)
Examples
Complete Menu Example
def new_file():
print("New file")
def open_file():
print("Open file")
def find():
print("Find")
def replace():
print("Replace")
root = tk.Tk()
menubar = tk.Menu(root)
root.config(menu=menubar)
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=file_menu)
file_menu.add_command(label="New", command=new_file)
file_menu.add_command(label="Open", command=open_file)
file_menu.add_separator()
file_menu.add_command(label="Exit", command=root.quit)
( q )
edit_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Edit", menu=edit_menu)
find_menu = tk.Menu(edit_menu, tearoff=0)
edit_menu.add_cascade(label="Find", menu=find_menu)
find_menu.add_command(label="Find...", command=find)
find_menu.add_command(label="Replace...", command=replace)
root.mainloop()
def new_file():
print("New file")
def open_file():
print("Open file")
root = tk.Tk()
toolbar = tk.Frame(root, bd=1, relief=tk.RAISED)
toolbar.pack(side=tk.TOP, fill=tk.X)
new_icon = tk.PhotoImage(file="new_icon.png")
new_button = tk.Button(toolbar, image=new_icon,
command=new_file)
new_button.image = new_icon # Keep a reference to avoid garbage
collection
new_button.pack(side=tk.LEFT, padx=2, pady=2)
open_icon = tk.PhotoImage(file="open_icon.png")
open_button = tk.Button(toolbar, image=open_icon,
command=open_file)
open_button.image = open_icon # Keep a reference to avoid
garbage collection
open_button.pack(side=tk.LEFT, padx=2, pady=2)
root.mainloop()
Message Boxes
Introduction to Message Boxes
Message boxes are simple dialogs that display information, warnings, or
errors to the user.
Tkinter provides a set of predefined message boxes in the messagebox
module.
Types of Message Boxes
showinfo: Displays an informational message.
showwarning: Displays a warning message.
showerror: Displays an error message.
askquestion: Asks a yes/no question.
askokcancel: Asks a yes/no question with OK/Cancel options.
askyesno: Asks a yes/no question.
askretrycancel: Asks a retry/cancel question.
Using Message Boxes
To use a message box, import the messagebox module and call the
appropriate function:
import tkinter as tk
from tkinter import messagebox
def show_info():
messagebox.showinfo("Information", "This is an informational
message.")
def show_warning():
messagebox.showwarning("Warning", "This is a warning
message.")
def show_error():
messagebox.showerror("Error", "This is an error message.")
def ask_question():
response = messagebox.askquestion("Question", "Do you want
to continue?")
print(f"Response: {response}")
root = tk.Tk()
tk.Button(root, text="Show Info", command=show_info).pack()
tk.Button(root, text="Show Warning",
command=show_warning).pack()
tk.Button(root, text="Show Error", command=show_error).pack()
tk.Button(root, text="Ask Question",
command=ask_question).pack()
root.mainloop()
Simple Dialogs
Introduction to Simple Dialogs
Simple dialogs are used to get basic input from the user, such as a string
or an integer.
Tkinter provides a set of predefined simple dialogs in the simpledialog
module.
Types of Simple Dialogs
askstring: Asks the user to input a string.
askinteger: Asks the user to input an integer.
askfloat: Asks the user to input a floating-point number.
Using Simple Dialogs
To use a simple dialog, import the simpledialog module and call the
appropriate function:
import tkinter as tk
from tkinter import simpledialog
def ask_for_string():
response = simpledialog.askstring("Input", "Enter your
name:")
print(f"Name: {response}")
def ask_for_integer():
response = simpledialog.askinteger("Input", "Enter your
age:")
print(f"Age: {response}")
def ask_for_float():
response = simpledialog.askfloat("Input", "Enter your
weight:")
print(f"Weight: {response}")
root = tk.Tk()
tk.Button(root, text="Ask for String",
command=ask_for_string).pack()
tk.Button(root, text="Ask for Integer",
command=ask_for_integer).pack()
tk.Button(root, text="Ask for Float",
command=ask_for_float).pack()
root.mainloop()
File Dialogs
Introduction to File Dialogs
File dialogs allow users to open or save files.
Tkinter provides a set of predefined file dialogs in the filedialog module.
Types of File Dialogs
askopenfilename: Opens a dialog to select a file to open.
asksaveasfilename: Opens a dialog to select a file to save.
askopenfile: Opens a file and returns a file object.
asksaveasfile: Opens a file and returns a file object for saving.
Using File Dialogs
To use a file dialog, import the filedialog module and call the appropriate
function:
import tkinter as tk
from tkinter import filedialog
def open_file():
file_path = filedialog.askopenfilename(title="Open File",
filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")])
print(f"Selected file: {file_path}")
def save_file():
file_path = filedialog.asksaveasfilename(title="Save File",
defaultextension=".txt", filetypes=[("Text Files", "*.txt"),
("All Files", "*.*")])
print(f"File saved as: {file_path}")
root = tk.Tk()
tk.Button(root, text="Open File", command=open_file).pack()
tk.Button(root, text="Save File", command=save_file).pack()
root.mainloop()
Custom Dialogs
Creating Custom Dialogs
Custom dialogs can be created by subclassing the Toplevel widget.
Define the layout and behavior of the custom dialog within the subclass.
Example of a Custom Dialog
import tkinter as tk
from tkinter import simpledialog
class CustomDialog(simpledialog.Dialog):
def body(self, master):
tk.Label(master, text="Name:").grid(row=0)
tk.Label(master, text="Age:").grid(row=1)
self.name_entry = tk.Entry(master)
self.age_entry = tk.Entry(master)
self.name_entry.grid(row=0, column=1)
self.age_entry.grid(row=1, column=1)
return self.name_entry
def apply(self):
self.result = {
"name": self.name_entry.get(),
"age": self.age_entry.get()
}
def open_custom_dialog():
dialog = CustomDialog(root)
print(f"Dialog result: {dialog.result}")
root = tk.Tk()
tk.Button(root, text="Open Custom Dialog",
command=open_custom_dialog).pack()
root.mainloop()
Introduction to Canvas
Overview
The Canvas widget provides a surface for drawing shapes, lines, text, and
images.
It supports various drawing methods and event handling to create
interactive graphics.
Creating a Canvas
To create a Canvas, you need to specify its parent widget and optional
dimensions:
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=300, bg="white")
canvas.pack()
root.mainloop()
Drawing Shapes
Drawing Lines
Use the create_line method to draw lines on the Canvas:
Drawing Rectangles
Use the create_rectangle method to draw rectangles:
Drawing Polygons
Use the create_polygon method to draw polygons with multiple points:
canvas.create_polygon(100, 150, 150, 250, 50, 250,
outline="purple", width=2, fill="violet")
Drawing Arcs
Use the create_arc method to draw arcs:
Adding Text
Drawing Text
Use the create_text method to add text to the Canvas:
Customizing Text
Text can be customized with various font and style options:
Handling Events
Binding Events
Bind events to Canvas items to make them interactive:
def on_canvas_click(event):
print(f"Clicked at {event.x}, {event.y}")
canvas.bind("<Button-1>", on_canvas_click)
Item-Specific Events
Bind events to specific items on the Canvas:
rect_id = canvas.create_rectangle(50, 50, 150, 100,
outline="red", width=2, fill="yellow")
def on_rectangle_click(event):
print("Rectangle clicked")
canvas.tag_bind(rect_id, "<Button-1>", on_rectangle_click)
image = tk.PhotoImage(file="path_to_image.png")
canvas.create_image(200, 150, image=image)
Image Positioning
Position images using the create_image method with anchor points:
Examples
Complete Drawing Example
root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=300, bg="white")
canvas.pack()
# Draw shapes
canvas.create_line(10, 10, 200, 200, fill="blue", width=2)
canvas.create_rectangle(50, 50, 150, 100, outline="red",
width=2, fill="yellow")
canvas.create_oval(100, 100, 200, 200, outline="green", width=2,
fill="lightgreen")
canvas.create_polygon(100, 150, 150, 250, 50, 250,
outline="purple", width=2, fill="violet")
canvas.create_arc(200, 150, 300, 250, start=0, extent=180,
outline="orange", width=2, fill="peachpuff")
# Draw text
canvas.create_text(200, 50, text="Hello, Canvas!", font=
("Helvetica", 16), fill="black")
canvas.create_text(200, 100, text="Custom Font", font=
("Courier", 20, "bold"), fill="blue")
root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=300, bg="white")
canvas.pack()
rect_id = canvas.create_rectangle(50, 50, 150, 100,
outline="red", width=2, fill="yellow")
def on_rectangle_click(event):
print("Rectangle clicked")
canvas.tag_bind(rect_id, "<Button-1>", on_rectangle_click)
root.mainloop()
Custom widgets allow you to extend the functionality of Tkinter and tailor the
user interface to specific requirements. By creating custom widgets, you can
encapsulate complex functionality, create reusable components, and enhance
the visual appearance of your application. This section will cover the basics of
creating custom widgets in Tkinter.
Introduction to Custom Widgets
Overview
Custom widgets are created by subclassing existing Tkinter widgets or
the Frame widget.
Subclassing allows you to add new methods, override existing methods,
and customize the behavior and appearance of the widget.
Benefits
Encapsulation: Encapsulate complex functionality within a single widget.
Reusability: Create reusable components that can be used across different
parts of the application.
Customization: Enhance and customize the visual appearance and
behavior of widgets.
Creating a Custom Widget
Subclassing a Tkinter Widget
Create a custom widget by subclassing an existing Tkinter widget or the
Frame widget:
import tkinter as tk
class CustomButton(tk.Button):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
self.config(bg="lightblue", fg="darkblue", font=
("Arial", 14))
self.bind("<Enter>", self.on_enter)
self.bind("<Leave>", self.on_leave)
def on_enter(self, event):
self.config(bg="darkblue", fg="white")
def on_leave(self, event):
self.config(bg="lightblue", fg="darkblue")
root = tk.Tk()
custom_button = CustomButton(root, text="Custom Button")
custom_button.pack(pady=20)
root.mainloop()
class CustomButton(tk.Button):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
self.config(bg="lightblue", fg="darkblue", font=
("Arial", 14))
self.bind("<Enter>", self.on_enter)
self.bind("<Leave>", self.on_leave)
def on_enter(self, event):
self.config(bg="darkblue", fg="white")
def on_leave(self, event):
self.config(bg="lightblue", fg="darkblue")
def set_text(self, text):
self.config(text=text)
def get_text(self):
return self.cget("text")
root = tk.Tk()
custom_button = CustomButton(root, text="Custom Button")
custom_button.pack(pady=20)
custom_button.set_text("New Text")
print(custom_button.get_text())
root.mainloop()
class CustomLabel(tk.Label):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
self.config(bg="yellow", fg="black", font=("Helvetica",
12))
self.bind("<Double-1>", self.on_double_click)
def on_double_click(self, event):
self.config(text="Double-clicked!")
root = tk.Tk()
custom_label = CustomLabel(root, text="Double-click me")
custom_label.pack(pady=20)
root.mainloop()
class CustomFrame(tk.Frame):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
self.label = tk.Label(self, text="Label in Frame")
self.label.pack(pady=5)
self.entry = tk.Entry(self)
self.entry.pack(pady=5)
self.button = tk.Button(self, text="Submit",
command=self.on_submit)
self.button.pack(pady=5)
def on_submit(self):
print(f"Entry content: {self.entry.get()}")
root = tk.Tk()
custom_frame = CustomFrame(root, bg="lightgrey", padx=10,
pady=10)
custom_frame.pack(pady=20)
root.mainloop()
class DynamicList(tk.Frame):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
self.items = []
self.listbox = tk.Listbox(self)
self.listbox.pack(side=tk.LEFT, fill=tk.BOTH,
expand=True)
self.scrollbar = tk.Scrollbar(self, orient=tk.VERTICAL,
command=self.listbox.yview)
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.listbox.config(yscrollcommand=self.scrollbar.set)
self.entry = tk.Entry(self)
self.entry.pack(pady=5)
self.add_button = tk.Button(self, text="Add Item",
command=self.add_item)
self.add_button.pack(pady=5)
def add_item(self):
item = self.entry.get()
if item:
self.items.append(item)
self.listbox.insert(tk.END, item)
self.entry.delete(0, tk.END)
root = tk.Tk()
dynamic_list = DynamicList(root, padx=10, pady=10)
dynamic_list.pack(pady=20, fill=tk.BOTH, expand=True)
root.mainloop()
Chapter Five: Getting Started with PyQt
I ntroduction to PyQt
PyQt is a set of Python bindings for the Qt application framework. It is known
for its extensive feature set and the ability to create complex and feature-rich
GUI applications. This section will introduce PyQt and guide you through the
basics of creating a PyQt application.
What is PyQt?
Overview
PyQt is a Python binding for the Qt toolkit, which is a popular
framework for developing cross-platform applications.
It combines the power of Qt with the simplicity and versatility of Python.
Advantages of Using PyQt
Rich Widget Set: PyQt offers a wide range of standard and advanced
widgets.
Cross-Platform: Applications built with PyQt can run on Windows,
macOS, and Linux.
Qt Designer: A visual tool for designing GUIs, generating the
corresponding PyQt code automatically.
Comprehensive Documentation: Extensive resources and community
support.
Installing Qt Designer
Qt Designer is a powerful tool for designing GUIs visually.
Download and install Qt Designer from the Qt website.
Creating Your First PyQt Application
Basic Structure
A PyQt application typically consists of a main window and various
widgets.
Import the necessary PyQt modules and create a basic application structure:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Hello PyQt")
self.setGeometry(100, 100, 600, 400)
label = QLabel("Hello, PyQt!", self)
label.move(50, 50)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Running the Application
Save the code to a file (e.g., hello_pyqt.py) and run it using Python:
python hello_pyqt.py
Application Initialization
Every PyQt application needs to initialize a QApplication object, which
handles application-wide settings and resources.
Example:
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
Main Window
The main window of the application is created using the QMainWindow
class.
Example:
Adding Widgets
Widgets are added to the main window. A common widget to start with
is QLabel for displaying text.
Example:
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Hello PyQt")
self.setGeometry(100, 100, 600, 400)
label = QLabel("Hello, PyQt!", self)
label.move(50, 50)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Save this code to a file named hello_pyqt.py and run it using the Python
interpreter:
python hello_pyqt.py
You should see a window titled “Hello PyQt” with a label displaying “Hello,
PyQt!”.
Understanding the Code
Imports
sys is imported to handle command-line arguments.
QApplication, QMainWindow, and QLabel are imported from the
PyQt5.QtWidgets module.
QApplication
The QApplication object is created with sys.argv to handle command-line
arguments.
This object manages application-wide settings and starts the event loop.
QMainWindow
A subclass of QMainWindow is created to define the main window.
The __init__ method initializes the main window, sets its title and
geometry, and adds a QLabel widget.
Event Loop
app.exec_() starts the event loop, which waits for user interactions and
updates the GUI accordingly.
sys.exit(app.exec_()) ensures that the application exits cleanly when the
main window is closed.
Customizing the Main Window
Window Title and Geometry
The setWindowTitle method sets the title of the main window.
The setGeometry method sets the position and size of the main window.
Adding More Widgets
Additional widgets can be added to the main window by creating
instances of widget classes and setting their properties.
Example:
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("path_to_ui_file.ui", self)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("main_window.ui", self)
self.pushButton.clicked.connect(self.on_button_click)
def on_button_click(self):
self.label.setText("Button clicked!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
You should see a window with a label “Hello, PyQt!” and a button “Click
Me”. Clicking the button will change the label text to “Button clicked!”.
Chapter Ten: PyQt Widgets and Controls
PyQt provides a rich set of widgets that allow you to create complex and
feature-rich GUI applications. This section covers three fundamental widgets:
QPushButton, QLabel, and QLineEdit. These widgets are commonly used for
user interaction and display purposes.
QPushButton
Introduction to QPushButton
QPushButton is a standard button widget in PyQt that users can click to
trigger actions.
It is one of the most commonly used widgets for interactive applications.
Creating a QPushButton
To create a QPushButton, you need to specify its parent widget and
optional text:
Customizing QPushButton
Customize the button with properties such as font, color, and size:
button.setFont(QFont("Arial", 16))
button.setStyleSheet("background-color: lightblue; color:
darkblue")
QLabel
Introduction to QLabel
QLabel is a widget used to display text or images.
It is commonly used for labels, instructions, and other static content.
Creating a QLabel
To create a QLabel, you need to specify its parent widget and optional text:
from PyQt5.QtWidgets import QLabel, QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QLabel Example")
self.setGeometry(100, 100, 400, 300)
label = QLabel("Hello, PyQt!", self)
label.move(150, 100)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Customizing QLabel
Customize the label with properties such as font, color, and alignment:
QLineEdit
Introduction to QLineEdit
QLineEdit is a widget that allows users to input and edit a single line of
text.
It is commonly used for form fields, search boxes, and other text input
scenarios.
Creating a QLineEdit
To create a QLineEdit, you need to specify its parent widget:
from PyQt5.QtWidgets import QLineEdit, QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QLineEdit Example")
self.setGeometry(100, 100, 400, 300)
line_edit = QLineEdit(self)
line_edit.move(150, 100)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QLineEdit Example")
self.setGeometry(100, 100, 400, 300)
self.line_edit = QLineEdit(self)
self.line_edit.move(150, 100)
self.line_edit.textChanged.connect(self.on_text_changed)
def on_text_changed(self):
print(f"Text changed: {self.line_edit.text()}")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Customizing QLineEdit
Customize the line edit with properties such as placeholder text, font, and
input masks:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel,
QPushButton, QLineEdit
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt Widgets Example")
self.setGeometry(100, 100, 400, 300)
self.label = QLabel("Enter your name:", self)
self.label.move(50, 50)
self.line_edit = QLineEdit(self)
self.line_edit.move(50, 100)
self.button = QPushButton("Greet", self)
self.button.move(50, 150)
self.button.clicked.connect(self.on_button_click)
def on_button_click(self):
name = self.line_edit.text()
self.label.setText(f"Hello, {name}!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
python pyqt_widgets_example.py
You should see a window with a label, a text input field, and a button.
Entering a name in the text field and clicking the button will update the
label to greet the user.
QTextEdit, QTableWidget, and QTreeWidget
PyQt provides advanced widgets for text editing, displaying tables, and
organizing data in a tree structure. This section covers the usage and features
of QTextEdit, QTableWidget, and QTreeWidget.
QTextEdit
Introduction to QTextEdit
QTextEdit is a widget that allows users to input and edit rich text.
It supports features like text formatting, undo/redo, and clipboard
operations.
Creating a QTextEdit
To create a QTextEdit, you need to specify its parent widget:
text_edit.setPlainText("Hello, PyQt!")
print(text_edit.toPlainText())
Customizing QTextEdit
Customize the QTextEdit with properties like font, color, and alignment:
text_edit.setFont(QFont("Times", 14))
text_edit.setStyleSheet("background-color: lightgray; color:
darkblue")
QTableWidget
Introduction to QTableWidget
QTableWidget is a widget that provides a table view to display and edit
tabular data.
It supports features like sorting, resizing, and custom cell rendering.
Creating a QTableWidget
To create a QTableWidget, you need to specify its parent widget and
optionally the number of rows and columns:
# Adding items
table_widget.setItem(0, 0, QTableWidgetItem("Item 1"))
table_widget.setItem(0, 1, QTableWidgetItem("Item 2"))
table_widget.setItem(0, 2, QTableWidgetItem("Item 3"))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
item = table_widget.item(1, 0)
print(item.text())
Customizing QTableWidget
Customize the QTableWidget with properties like font, color, and cell
alignment:
table_widget.setFont(QFont("Arial", 12))
table_widget.setStyleSheet("QTableWidget { background-color:
white; } QTableWidget::item { padding: 5px; }")
QTreeWidget
Introduction to QTreeWidget
QTreeWidget is a widget that provides a tree view to display hierarchical
data.
It supports features like expanding/collapsing nodes, drag-and-drop, and
custom item rendering.
Creating a QTreeWidget
To create a QTreeWidget, you need to specify its parent widget:
from PyQt5.QtWidgets import QTreeWidget, QApplication,
QMainWindow, QTreeWidgetItem
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QTreeWidget Example")
self.setGeometry(100, 100, 600, 400)
tree_widget = QTreeWidget(self)
tree_widget.setGeometry(50, 50, 500, 300)
tree_widget.setHeaderLabels(["Column 1", "Column 2"])
# Adding items
root_item = QTreeWidgetItem(tree_widget, ["Root", "Root
Data"])
child_item = QTreeWidgetItem(root_item, ["Child", "Child
Data"])
tree_widget.addTopLevelItem(root_item)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
print(child_item.text(0))
Customizing QTreeWidget
Customize the QTreeWidget with properties like font, color, and item
icons:
tree_widget.setFont(QFont("Courier", 10))
tree_widget.setStyleSheet("QTreeWidget { background-color:
lightgreen; } QTreeWidget::item { padding: 5px; }")
root_item.setIcon(0, QIcon("path_to_icon.png"))
( ( p p g ))
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow,
QTextEdit, QTableWidget, QTableWidgetItem, QTreeWidget,
QTreeWidgetItem
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt Advanced Widgets Example")
self.setGeometry(100, 100, 800, 600)
# QTextEdit
self.text_edit = QTextEdit(self)
self.text_edit.setGeometry(50, 50, 300, 200)
self.text_edit.setPlainText("Hello, PyQt!")
# QTableWidget
self.table_widget = QTableWidget(3, 3, self)
self.table_widget.setGeometry(400, 50, 350, 200)
self.table_widget.setHorizontalHeaderLabels(["Column 1",
"Column 2", "Column 3"])
self.table_widget.setItem(0, 0, QTableWidgetItem("Item
1"))
self.table_widget.setItem(0, 1, QTableWidgetItem("Item
2"))
self.table_widget.setItem(0, 2, QTableWidgetItem("Item
3"))
# QTreeWidget
self.tree_widget = QTreeWidget(self)
self.tree_widget.setGeometry(50, 300, 300, 200)
self.tree_widget.setHeaderLabels(["Column 1", "Column
2"])
root_item = QTreeWidgetItem(self.tree_widget, ["Root",
"Root Data"])
child_item = QTreeWidgetItem(root_item, ["Child", "Child
Data"])
self.tree_widget.addTopLevelItem(root_item)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Running the Application
Save the code to a file (e.g., pyqt_advanced_widgets_example.py) and run it
using Python:
python pyqt_advanced_widgets_example.py
Overview
QHBoxLayout arranges widgets in a horizontal line.
QVBoxLayout arranges widgets in a vertical line.
Both layouts automatically manage the size and position of their child
widgets.
Creating Box Layouts
To create a box layout, instantiate QHBoxLayout or QVBoxLayout and add
widgets to it:
layout.addWidget(QPushButton("Button"))
Use the addStretch method to add flexible space that grows with the layout:
Stretch Factors
Stretch factors determine how space is distributed among widgets:
layout.addWidget(QPushButton("Button 1"), 1) # Stretch factor of
1
layout.addWidget(QPushButton("Button 2"), 2) # Stretch factor of
2
Alignment
Align widgets within the layout using alignment flags:
layout.addWidget(QPushButton("Aligned Button"),
alignment=Qt.AlignRight)
Nested Layouts
Combining Layouts
Layouts can be nested to create more complex layouts:
main_layout = QVBoxLayout()
h_layout = QHBoxLayout()
h_layout.addWidget(QPushButton("Button 1"))
h_layout.addWidget(QPushButton("Button 2"))
v_layout = QVBoxLayout()
v_layout.addWidget(QPushButton("Button 3"))
v_layout.addWidget(QPushButton("Button 4"))
main_layout.addLayout(h_layout)
main_layout.addLayout(v_layout)
grid_layout.addWidget(QPushButton("Button 1"), 0, 0)
grid_layout.addWidget(QPushButton("Button 2"), 0, 1)
grid_layout.addWidget(QPushButton("Wide Button"), 2, 0, 1, 2) #
Spans 1 row and 2 columns
Alignment
Align widgets within their grid cells using alignment flags:
grid_layout.addWidget(QPushButton("Aligned Button"), 3, 0,
alignment=Qt.AlignRight)
python grid_layout_form_example.py
You should see a form with labels and text input fields arranged in a grid.
Overview
QFormLayout arranges widgets in a two-column layout where the left
column contains labels and the right column contains fields.
It ensures that labels and fields are properly aligned.
Creating a Form Layout
To create a form layout, instantiate QFormLayout and add rows of labels
and fields to it:
Adding Rows
Use the addRow method to add a label and field pair to the form layout:
form_layout.addRow(QLabel("Contact Information"))
form_layout.addRow(QLineEdit())
form_layout.addRow(QLabel("Notes:"), QLineEdit(), 1, 2)
form_layout.setLabelAlignment(Qt.AlignRight)
form_layout.setFormAlignment(Qt.AlignHCenter)
Spacing and Margins
Set the spacing between rows and the margins around the layout:
form_layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGr
ow)
python form_layout_example.py
You should see a registration form with labels and input fields arranged
in a clean and organized manner.
Chapter Eleven: Advanced PyQt
Overview
Custom widgets are created by subclassing existing widgets or QWidget.
You can add new properties, methods, and custom rendering logic to
your custom widgets.
Benefits
Encapsulation: Encapsulate complex functionality within a single widget.
Reusability: Create reusable components that can be used across different
parts of the application.
Customization: Enhance and customize the visual appearance and
behavior of widgets.
Subclassing QWidget
Basic Custom Widget
Create a custom widget by subclassing QWidget:
from PyQt5.QtWidgets import QWidget, QApplication, QLabel,
QVBoxLayout
class CustomWidget(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Custom Widget Example")
layout = QVBoxLayout()
self.label = QLabel("This is a custom widget")
layout.addWidget(self.label)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
custom_widget = CustomWidget()
custom_widget.show()
sys.exit(app.exec_())
class CustomWidget(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Custom Widget Example")
layout = QVBoxLayout()
self.label = QLabel("This is a custom widget")
layout.addWidget(self.label)
self.setLayout(layout)
def set_custom_text(self, text):
self.label.setText(text)
def get_custom_text(self):
return self.label.text()
if __name__ == "__main__":
app = QApplication(sys.argv)
custom_widget = CustomWidget()
custom_widget.set_custom_text("Updated custom widget text")
custom_widget.show()
print(custom_widget.get_custom_text())
sys.exit(app.exec_())
class CustomPaintWidget(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Custom Paint Widget")
self.resize(400, 300)
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.setBrush(QColor(100, 200, 100))
painter.drawRect(10, 10, 200, 100)
painter.setBrush(QColor(200, 100, 100))
painter.drawEllipse(250, 50, 100, 100)
painter.setPen(QColor(0, 0, 0))
painter.drawText(50, 200, "Custom Drawing")
if __name__ == "__main__":
app = QApplication(sys.argv)
custom_widget = CustomPaintWidget()
custom_widget.show()
sys.exit(app.exec_())
Introduction to QPropertyAnimation
Advanced Animations
Animating Multiple Properties
You can animate multiple properties by creating multiple
QPropertyAnimation objects and using a QParallelAnimationGroup:
Introduction to QGraphicsView
Overview
QGraphicsView provides a widget for displaying and interacting with a
large number of custom 2D graphical items.
It uses the QGraphicsScene and QGraphicsItem classes for managing and
rendering items.
Creating a QGraphicsView
Create a QGraphicsView and set a QGraphicsScene to it:
Animating QGraphicsItems
Using QPropertyAnimation with QGraphicsItems
Animate QGraphicsItems using QPropertyAnimation:
import sys
from PyQt5.QtWidgets import QApplication, QGraphicsView,
QGraphicsScene, QGraphicsEllipseItem
from PyQt5.QtCore import QPropertyAnimation, QRectF,
QEasingCurve
from PyQt5.QtGui import QColor
class MainWindow(QGraphicsView):
def __init__(self):
super().__init__()
self.setWindowTitle("QGraphicsView Animation Example")
self.resize(600, 400)
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.ellipse = QGraphicsEllipseItem(0, 0, 100, 100)
self.ellipse.setBrush(QColor(255, 0, 0))
self.scene.addItem(self.ellipse)
self.animation = QPropertyAnimation(self.ellipse,
b"rect")
self.animation.setDuration(1000)
self.animation.setStartValue(QRectF(0, 0, 100, 100))
self.animation.setEndValue(QRectF(200, 200, 300, 300))
self.animation.setEasingCurve(QEasingCurve.OutBounce)
self.setMouseTracking(True)
def mousePressEvent(self, event):
self.animation.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
python graphics_view_animation_example.py
You should see a window with an ellipse that animates when you click the
mouse.
Introduction to QtSql
Overview
The QtSql module provides classes for accessing and managing SQL
databases.
It supports various database systems, including SQLite, MySQL, and
PostgreSQL.
Supported Classes
QSqlDatabase: Represents a connection to a database.
QSqlQuery: Executes SQL queries.
QSqlTableModel: Provides an editable data model for a database table.
QSqlQueryModel: Provides a read-only data model for SQL queries.
Connecting to a Database
Establishing a Connection
Create a QSqlDatabase object and establish a connection to the database:
if not db.open():
print(f"Database Error: {db.lastError().text()}")
return False
Using QSqlQuery
Use QSqlQuery to execute SQL queries:
from PyQt5.QtSql import QSqlQuery
def create_table():
query = QSqlQuery()
query.exec_(
"""
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE
)
"""
)
if __name__ == "__main__":
if create_connection():
create_table()
Inserting Data
Insert data into the database using QSqlQuery:
Retrieving Data
Retrieve data from the database using QSqlQuery:
def get_contacts():
query = QSqlQuery("SELECT id, name, email FROM contacts")
while query.next():
id = query.value(0)
name = query.value(1)
email = query.value(2)
print(f"ID: {id}, Name: {name}, Email: {email}")
if __name__ == "__main__":
if create_connection():
create_table()
()
add_contact("John Doe", "[email protected]")
get_contacts()
Customizing QTableView
Customize the appearance and behavior of QTableView:
self.view.setAlternatingRowColors(True)
self.view.setColumnHidden(0, True) # Hide the ID column
self.view.setSelectionBehavior(QTableView.SelectRows)
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow,
QTableView, QWidget, QVBoxLayout, QPushButton, QLineEdit,
QLabel, QHBoxLayout
from PyQt5.QtSql import QSqlDatabase, QSqlTableModel, QSqlQuery
def create_connection():
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("example.db")
if not db.open():
print(f"Database Error: {db.lastError().text()}")
return False
return True
def create_table():
query = QSqlQuery()
query.exec_(
"""
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE
)
"""
)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Database Example")
self.resize(600, 400)
self.model = QSqlTableModel()
self.model.setTable("contacts")
self.model.select()
self.view = QTableView()
self.view.setModel(self.model)
self.view.setAlternatingRowColors(True)
self.view.setColumnHidden(0, True)
self.view.setSelectionBehavior(QTableView.SelectRows)
self.name_edit = QLineEdit()
self.email_edit = QLineEdit()
self.add_button = QPushButton("Add Contact")
self.add_button.clicked.connect(self.add_contact)
form_layout = QHBoxLayout()
form_layout.addWidget(QLabel("Name:"))
form_layout.addWidget(self.name_edit)
form_layout.addWidget(QLabel("Email:"))
form_layout.addWidget(self.email_edit)
form_layout.addWidget(self.add_button)
layout = QVBoxLayout()
layout.addLayout(form_layout)
layout.addWidget(self.view)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
def add_contact(self):
name = self.name_edit.text()
email = self.email_edit.text()
query = QSqlQuery()
query.prepare("INSERT INTO contacts (name, email) VALUES
(?, ?)")
query.addBindValue(name)
query.addBindValue(email)
if not query.exec_():
print(f"Insert Error: {query.lastError().text()}")
self.model.select()
if __name__ == "__main__":
app = QApplication(sys.argv)
if create_connection():
create_table()
window = MainWindow()
window.show()
sys.exit(app.exec_())
You should see a window with a form for adding contacts and a table view
displaying the contacts.
Chapter Twelve: Deploying PyQt Applications
Introduction to Packaging
Overview
Packaging tools bundle your application code, resources, and
dependencies into a single executable or installer.
This simplifies the distribution and installation process for end-users.
Common Packaging Tools
PyInstaller: Converts Python applications into stand-alone executables.
cx_Freeze: Creates executables from Python scripts, including
dependencies.
Using PyInstaller
Installing PyInstaller
Install PyInstaller using pip:
Creating an Executable
Use PyInstaller to create a single executable for your application:
pyinstaller --onefile your_script.py
# your_script.spec
from PyInstaller.utils.hooks import collect_submodules
hiddenimports = collect_submodules('PyQt5')
a = Analysis(['your_script.py'],
pathex=['.'],
binaries=[],
datas=[('path_to_data_file',
'destination_folder')],
hiddenimports=hiddenimports,
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='your_script',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='your_script')
Running the Executable
Navigate to the dist directory and run the executable:
./your_script
Using cx_Freeze
Installing cx_Freeze
Install cx_Freeze using pip:
./your_script
Cross-Platform Packaging
Packaging for Windows
Use PyInstaller or cx_Freeze on a Windows machine to create a Windows
executable.
Example for PyInstaller:
Creating an Installer
Using Inno Setup for Windows
Inno Setup is a free installer for Windows programs.
Download and install Inno Setup from the Inno Setup website.
Create a script to define the installer settings:
ini
[Setup]
AppName=YourApplication
AppVersion=1.0
DefaultDirName={pf}\YourApplication
DefaultGroupName=YourApplication
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
[Files]
Source: "dist\your_script.exe"; DestDir: "{app}"; Flags:
ignoreversion
[Setup]
AppName=YourApplication
AppVersion=1.0
DefaultDirName={pf}\YourApplication
DefaultGroupName=YourApplication
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
[Files]
Source: "dist\your_script.exe"; DestDir: "{app}"; Flags:
ignoreversion
I nthethisdepths
comprehensive exploration of GUI programming, we have delved into
of two powerful libraries: Tkinter and PyQt. Starting from the
fundamental concepts, we built a solid foundation in GUI programming,
understanding its importance in enhancing user experience. With Tkinter, we
embarked on a journey from the basics, learning how to set up the
environment and create simple applications. As we progressed, we mastered
layout management, explored advanced concepts, and expanded our
capabilities to craft sophisticated applications.
Transitioning to PyQt, we explored a different approach to GUI
development. Starting with the essentials, we familiarized ourselves with the
structure and workflow of PyQt, creating our first applications. We examined
a variety of widgets and controls, understanding how to use them to build
interactive and functional interfaces. By mastering layout management in
PyQt, we learned to create well-organized and visually appealing applications.
Our journey didn’t stop at the basics. We ventured into advanced topics,
exploring custom widgets, event handling, and integrating third-party
libraries. This advanced knowledge empowered us to push the boundaries of
what our applications could achieve. Finally, we covered the crucial aspect of
deploying PyQt applications, ensuring that our creations could be packaged,
distributed, and used effectively by others.
As we conclude this book, it’s important to recognize that GUI
programming is a dynamic and ever-evolving field. The knowledge and skills
you’ve acquired here are just the beginning. Continue to experiment, explore,
and innovate. Whether you are building simple tools or complex systems, the
principles and techniques you’ve learned will serve as a solid foundation.
Thank you for embarking on this journey into GUI programming with
Tkinter and PyQt. Your dedication and curiosity will undoubtedly lead to the
creation of amazing applications that enhance the user experience. Keep
coding, keep learning, and keep pushing the limits of what you can achieve.