Ôn tập về sự kiện
Sự kiện là những tương tác của người dùng tác động lên các thành phần của trang giao diện.
Các sự kiện phổ biến
Press/Release giữ và thả nút, tác động lên các button.
Click (Press và Release) nhấn nút. tác động lên các button.
Hover di chuột lên các widget.
Enter/Leave tiến vào và rời khỏi widget.
Các bước lập trình sự kiện
B1: Xác định widget mà người dùng sẽ tương tác (ví dụ self.ui.homeButton)
B2: Xác định sự kiện mà người dùng sẽ tạo ra (ví dụ clicked)
B3: Connect sự kiện với hàm hướng dẫn chương trình phản hồi bằng phương thức connect.
self.ui.homeButton.connect(self.show_home)
def show_home(self):
…
Lập trình chuyển trang trong Stack Widget (ls8_sample/main1.py)
Đối với sự kiện toggled của QtoolButton (nút Home trong sample là kiểu checkable nên ta sử dụng sự kiện toggled):
Chỉ cần đặt tên hàm theo format là on_<tên button>_<tên sự kiện>
Chương trình sẽ mặc định đó là hàm phản hồi cho sự kiện của nút mà không cần đến phương thức connect
def on_homeButton_toggled(self):
self.ui.stackedWidget.setCurrentIndex(0)
Cách sự kiện ảnh hưởng đến dữ liệu
Để thực hiện các thao tác CRUD trong ứng dụng, ta cần nhấn các nút tương ứng Add, Edit, Delete.
Khi các sự kiện add/edit/delete button clicked này xảy ra thì chức năng thêm/xóa/sửa tương ứng mới được thực hiện.
à Cần phải kết nối sự kiện nhấn nút với các hàm thêm/xóa/sửa tương ứng.
à Đồng thời, cần phải cập nhật lại dữ liệu trên ổ cứng khi các thao tác này xảy ra
Trong class MainWindow, tiến hành format lại code để setup trang CRUD
# Tạo database
self.dtb = models.AnimeDatabase()
self.dtb.load_data()
# Setup trang CRUD
self.setup_CRUD_page()
# Hiển thị cửa sổ ra màn hình
self.show()
def setup_CRUD_page(self):
# Hiển thị danh sách anime
anime_titles = self.dtb.get_title_list()
self.ui.animeList.addItems(anime_titles)
self.ui.animeList.setCurrentRow(0)
# Xử lý các button
self.ui.addButton.clicked.connect(self.add)
self.ui.editButton.clicked.connect(self.edit)
self.ui.removeButton.clicked.connect(self.delete)
def add(self):
pass
def edit(self):
pass
def delete(self):
pass
def search(self):
pass
Tạo folder widgets à Tạo class AddDialog trong file dialog.py
import os
from datetime import datetime
from PyQt6 import uic
from PyQt6.QtWidgets import QDialog, QFileDialog
from PyQt6.QtCore import QDate, QDir
from models import models
UI_DIR = "ui"
class AddDialog(QDialog):
"""
Hộp thoại Add
"""
UI_LOCATION = os.path.join(UI_DIR, "add_dialog.ui")
STYLE_LOCATION = os.path.join(UI_DIR, "style_popup.qss")
def __init__(self):
super().__init__(AddDialog)
# Load giao diện
self.ui = uic.loadUi(self.UI_LOCATION, self)
with open(self.STYLE_LOCATION, "r") as style_file:
style_config = style_file.read()
self.setStyleSheet(style_config)
# Tạo đối tượng QDir để quản lý đường dẫn
self.dir = QDir()
# Nút tải ảnh từ máy tính
self.ui.uploadImgButton.clicked.connect(self.browse_files)
self.ui.releasedateInput.setDisplayFormat("dd/MM/yyyy") # Format ngày tháng năm
def browse_files(self):
"""
Phương thức mở file dialog để chọn ảnh
"""
fname = QFileDialog.getOpenFileName(self,
'Open file',
'./ui/images',
filter='Image files (*.png, *.jpg, *.svg)'
)
self.ui.uploadImgButton.setText(fname[0])
return fname
def return_input_fields(self) -> dict:
"""
Thu thập dữ liệu của tất cả các trường và trả về một dict
"""
# Xử lý trường ngày tháng năm
date_input = self.ui.releasedateInput.date().toPyDate() # formatted YYYY-mm-dd
image_path_input = self.ui.uploadImgButton.text()
# Xử lý trường URL
if self.ui.urlInput.text():
url_input = self.ui.urlInput.text()
else:
url_input = "None"
# Trả dữ liệu
return {
"title": self.ui.titleInput.text(),
"release_date": date_input.strftime("%b %Y"),
"image": self.dir.relativeFilePath(image_path_input),
"rating": float(self.ui.ratingInput.text()),
"link": url_input
}
Trong class EditDialog cần được lập trình để hiển thị những thông tin sẵn có của đối tượng:
# Hiển thị dữ liệu hiện tại của item
self.ui.titleInput.setText(edit_item.title)
date = datetime.strptime(edit_item.release_date, '%b %Y')
self.ui.releasedateInput.setDate(QDate(date.year, date.month, date.day))
self.ui.uploadImgButton.setText(self.dir.relativeFilePath(edit_item.image))
self.ui.ratingInput.setText(str(edit_item.rating))
self.ui.urlInput.setText(edit_item.link)
Import các class dialog
from widgets import dialog
Phương thức Add
def add(self):
curr_index = self.ui.animeList.currentRow()
# Tạo Dialog Add
add_dialog = dialog.AddDialog()
# Nếu nhấn nút OK trên dialog
if add_dialog.exec():
# Lấy dữ liệu từ dialog
inputs = add_dialog.return_input_fields()
# Thêm item vào List Widget
self.ui.animeList.insertItem(curr_index, inputs["title"])
# Thêm dữ liệu vào database
self.dtb.add_item(inputs)
Phương thức Edit
def edit(self):
# Lấy item đang chọn
curr_index = self.ui.animeList.currentRow()
item = self.ui.animeList.item(curr_index)
item_title = item.text()
edit_item = self.dtb.get_first_item_by_title(item_title)
# Tạo Dialog Edit
if item is not None:
edit_dialog = dialog.EditDialog(edit_item)
# Nếu nhấn nút OK trên dialog
if edit_dialog.exec():
# Lấy dữ liệu từ dialog
inputs = edit_dialog.return_input_fields()
# Sửa lại tên item trên List Widget
item.setText(inputs["title"])
# Sửa dữ liệu trong database
self.dtb.edit_item(item_title, inputs)
Phương thức Delete
def delete(self):
# Lấy item đang chọn
curr_index = self.ui.animeList.currentRow()
item = self.ui.animeList.item(curr_index)
item_title = item.text()
# Tạo Message Box confirm
if item is not None:
choice = QMessageBox.question(self, "Remove Anime",
"Do you want to remove this anime?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
# Nếu chọn nút "Yes"
if choice == QMessageBox.StandardButton.Yes:
# Xoá item khỏi List Widget
item = self.ui.animeList.takeItem(curr_index)
# Xoá dữ liệu trong database
self.dtb.delete_item(item_title)
Thực hành xử lý sự kiện và tương tác với giao diện cho dự án cá nhân
Mục tiêu:
Xử lý sự kiện cho các nút trong giao diện
Xử lý sự kiện nhấn các nút CRUD cho giao diện
Xử lý các hộp thoại liên quan cho giao diện
Nhiệm vụ:
Tạo file app.py chứa code để chạy ứng dụng chính
Lập trình kết nối giao diện ứng dụng với class MainWindow
Lập trình sự kiện clicked của các nút trong giao diện MainWindow
Lập trình kết nối giao diện hộp thoại với class Dialog (nếu có)
Lập trình sự kiện mở cửa sổ duyệt file cho nút trong class Dialog (nếu có)
Lập trình sự kiện mở hộp thoại xác nhận QMessageBox khi xoá đối tượng (nếu có)