- Introduction
- Setup and Installation
- Basic PyQt5 Concepts
- Building the Application
- Packaging the Application
- Creating an Installer
This tutorial will guide you through creating a professional task management application using PyQt5. We'll cover everything from basic concepts to advanced features, and finally package it into a distributable Windows application.
- A task management application with deadline tracking
- Features include:
- Adding tasks with deadlines
- Marking tasks as complete
- Deadline notifications with sound
- Persistent storage
- Professional UI styling
- Python (3.8 or newer)
- PyQt5
- PyInstaller (for packaging)
- Inno Setup (for creating installers)
# Create a virtual environment
python -m venv venv
# Activate virtual environment
# Windows:
venv\Scripts\activate
# Linux/Mac:
source venv/bin/activate
# Install required packages
pip install PyQt5 PyInstaller
project_folder/
│
├── assets/
│ ├── app.png
│ └── alarm.mp3
│
├── src/
│ └── app.py
│
└── requirements.txt
from PyQt5.QtWidgets import QApplication, QMainWindow
# Every PyQt application needs ONE QApplication instance
app = QApplication(sys.argv)
# QMainWindow is your main application window
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
window = MainWindow()
window.show()
sys.exit(app.exec_())
PyQt5 uses widgets (UI elements) and layouts (arrangement systems) to build interfaces.
QLabel
: Display textQPushButton
: Clickable buttonQLineEdit
: Single-line text inputQListWidget
: List of itemsQTimeEdit
: Time input widget
QVBoxLayout
: Vertical arrangementQHBoxLayout
: Horizontal arrangementQGridLayout
: Grid-based arrangement
Example:
# Creating a vertical layout
layout = QVBoxLayout()
# Adding widgets to layout
layout.addWidget(QPushButton("Button 1"))
layout.addWidget(QPushButton("Button 2"))
# Setting layout to main widget
main_widget = QWidget()
main_widget.setLayout(layout)
PyQt5 uses signals and slots for event handling. Signals are emitted when something happens (like a button click), and slots are functions that respond to these signals.
# Connect button click to function
button = QPushButton("Click Me")
button.clicked.connect(self.button_clicked)
def button_clicked(self):
print("Button was clicked!")
We use Python's dataclass
for task representation:
@dataclass
class Task:
description: str
deadline: Optional[datetime] = None
completed: bool = False
notified: bool = False
The TaskManager
class handles task operations and persistence:
class TaskManager:
def __init__(self):
self.tasks = []
def add_task(self, description: str, deadline_str: Optional[str] = None):
# Convert string time to datetime
deadline = None
if deadline_str:
time = datetime.strptime(deadline_str, "%H:%M").time()
deadline = datetime.combine(datetime.now().date(), time)
The MustDo
class creates our main application window:
class MustDo(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("MustDo")
self.setup_ui()
PyQt5 uses Qt Style Sheets (QSS), similar to CSS:
# Button styling
button.setStyleSheet("""
QPushButton {
background-color: #4682B4;
color: white;
border: none;
border-radius: 5px;
padding: 5px 15px;
}
QPushButton:hover {
background-color: #5692C4;
}
""")
- Create a spec file:
pyi-makespec --onefile --windowed --icon=assets/app.png --add-data "assets/*;assets" app.py
- Edit the spec file to include assets:
# app.spec
a = Analysis(
['app.py'],
pathex=[],
binaries=[],
datas=[('assets/*', 'assets')], # Include assets folder
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
noarchive=False,
)
- Build the executable:
pyinstaller app.spec --noconfirm
In this section, we will guide you through the process of creating an installer for your application using Inno Setup. This tool simplifies the distribution of your software by packaging it into a single executable file that users can easily install.
For detailed instructions, visit this Inno Setup guide: Making Executables Installable with Inno Setup
- Version Control
git init
echo "venv/" > .gitignore
echo "dist/" >> .gitignore
echo "build/" >> .gitignore
git add .
git commit -m "Initial commit"
- Requirements Management
pip freeze > requirements.txt
- Testing
- Test the application thoroughly
- Test the packaged executable
- Test the installer on a clean system
- Resource Management
# Handle missing resources gracefully
if not os.path.exists(alarm_file_path):
QMessageBox.warning(self, "Resource Missing",
f"Alarm sound file not found: {alarm_file_path}")
- Error Handling
try:
# Potentially dangerous operation
self.task_manager.save_tasks(self.TASK_FILE)
except Exception as e:
QMessageBox.critical(self, "Save Error",
f"Failed to save tasks: {str(e)}")
- Performance Optimization
# Use timer for periodic checks instead of continuous loops
self.timer = QTimer()
self.timer.timeout.connect(self.check_deadlines)
self.timer.start(60000) # Check every minute
This tutorial covers the basics of PyQt5 development and application distribution. For more advanced topics, consider exploring:
- Custom widgets
- Threading in PyQt
- Database integration
- Network operations
- Automated testing
- Continuous Integration/Deployment
Remember to always check the official PyQt5 documentation for detailed information about specific components and features.