Trong bài này Tui sẽ tiếp tục trình bày chi tiết về SQLite database trong Python với framework PyQt6. Các bạn sẽ tự tay tạo ra một cơ sở dữ liệu SQLite database bằng DB Browswer, rồi từ PyQt6 viết các mã lệnh Python để: Xem, thêm, sửa, xóa dữ liệu. Giao diện phần mềm của bài này mà chúng ta xây dựng sẽ như dưới đây:
- Tạo Cơ sở dữ liệu SQLite bằng DB Browser, thiết kế các bảng dữ liệu có cột Id Primary Key là Auto Increment.
- Viết chức năng đọc toàn bộ dữ liệu trong CSDL SQLite lên giao diện QTableWidget trong mục List Products
- Xử lý sự kiện người dùng chọn các dòng dữ liệu trên QTableWidget và hiển thị thông tin chi tiết xuống phần Product Details
- Chức năng “New” sẽ xóa dữ liệu đang nhập ở các ô QLineEdit và focus tới ô Product code
- Chức năng “Save”, viết mã lệnh để chương trình tự xử lý 2 trường hợp là lưu mới dữ liệu xuống SQLite hoặc là lưu cập nhập xuống SQLite
- Chức năng “Remove”, viết mã lệnh để xóa dòng dữ liệu đang chọn, cho người dùng xác thực trước khi xóa.
Chúng ta thực hiện chi tiết từng bước như dưới đây:
Bước 1: Tạo một dự án tên “LearnQTableWidgetPart4“
- Thư mục “database” sẽ lưu trữ SQLite “MyDatabase.sqlite” mà ta sẽ làm chi tiết ở bước sau.
- Thư mục “images” lưu trữ các hình ảnh, icon của phần mềm
- File “MainWindow.ui” là file giao diện thiết kế bằng Qt Designer
- File “MainWindow.py” là file Generate Python code
- File “MainWindowEx.py” là file mã lệnh kế thừa từ MainWindow.py để xử lý các nghiệp vụ phần mềm mà không lệ thuộc vào giao diện có thay đổi hay không trong tương lai
- File “MyApp.py” là file thực thi phần mềm
Bước 2: Thiết kế cơ sở dữ liệu SQLite, đặt tên “MyDatabase.sqlite”
Từ phần mềm DB Browser (đã học ở bài 24), Các bạn chọn “New Database“
Sau đó chọn nơi lưu trữ, ta lưu vào thư mục “database” trong bước 1.
Đặt tên “MyDatabase.sqlite” rồi bấm “Save” lúc này màn hình tạo Table sẽ hiển thị ra như dưới đây:
Trong mục Table ta đặt tên, rồi nhấn vào nút “Add” để thêm các thuộc tính. Ví dụ ta tạo bảng User như dưới đây:
- Mỗi thuộc tính nó sẽ có kiểu dữ liệu tương ứng, ở trên ta thấy thuộc tính Id Tui chọn Type là INTEGER và tick vào PK(Primary Key) và AI (Auto Increment) là khóa chính tự động tăng.
- Thuộc tính UserName, Password có type là TEXT
Sau khi tạo xong các thuộc tính ta nhấn nút OK và xem kết quả:
Tiếp theo ta nhập một vài dữ liệu mẫu cho bảng User này bằng cách nhấn vào thẻ “Browse Data”:
Để thêm dữ liệu cho bảng thì bấm vào biểu tượng New Record mà Tui tô khung đỏ ở trên, sau đó nhập dữ liệu và các dòng và cột tương ứng ở chỗ mũi tên màu đỏ.
Tương tự như thế, ta tạo bảng tiếp theo có tên “Product” bằng cách bấm vào biểu tượng “Create Table” trong thẻ “Database Structure”:
Ta thiết kế bảng Product như dưới đây:
Tương tự như bảng User, bảng Product Tui cũng cấu hình Id là cột khóa chính (PK) và tự động tăng (AI – Auto Increment)
- cột ProductCode để lưu mã Product có kiểu TEXT
- cột productName để lưu tên Product có kiểu TEXT
- và cuối cùng là cột UnitPrice để lưu giá Product có kểu REAL
sau khi cấu hình xong thì bấm OK , ta có kết quả:
- Tương tự như bảng User ta nhập một số dữ liệu mẫu ban đầu cho Product:
Ta nhấn CTRL+S để lưu sự thay đổi của SQLITE mà ta mới cấu hình.
- Bảng User Tui sẽ không hướng dẫn code truy vấn. Bài này là bài tập các bạn cần thiết kết màn hình đăng nhập, nếu đăng nhập thành công thì vào màn hình quản lý sản phẩm
- Bảng Product Tui sẽ hướng dẫn chi tiết để quản lý sản phẩm: Xem, thêm, sửa, xóa….
Bước 3: Thiết kế giao diện “MainWindow.ui” bằng Qt Designer được tích hợp trong Pycharm mà Tui đã hướng dẫn ở những bài đầu tiên của chuỗi bài học.
Các bạn kéo thả các Widget và cấu hình cũng như đặt tên cho các Widget như hình trên.
Bước 4: Generate Python code cho file “MainWindow.ui”, lúc này file mã lệnh “MainWindow.py” tự động được tạo ra như dưới đây:
# Form implementation generated from reading ui file 'MainWindow.ui'
#
# Created by: PyQt6 UI code generator 6.4.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(491, 481)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap("images/ic_logo.jpg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
MainWindow.setWindowIcon(icon)
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.groupBox = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox.setGeometry(QtCore.QRect(20, 360, 461, 71))
self.groupBox.setStyleSheet("background-color: rgb(241, 255, 202);")
self.groupBox.setObjectName("groupBox")
self.pushButtonRemove = QtWidgets.QPushButton(parent=self.groupBox)
self.pushButtonRemove.setGeometry(QtCore.QRect(340, 20, 101, 41))
self.pushButtonRemove.setStyleSheet("background-color: rgb(255, 170, 255);")
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap("images/ic_delete.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
self.pushButtonRemove.setIcon(icon1)
self.pushButtonRemove.setIconSize(QtCore.QSize(32, 32))
self.pushButtonRemove.setObjectName("pushButtonRemove")
self.pushButtonNew = QtWidgets.QPushButton(parent=self.groupBox)
self.pushButtonNew.setGeometry(QtCore.QRect(40, 20, 93, 41))
self.pushButtonNew.setStyleSheet("background-color: rgb(255, 170, 255);")
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap("images/ic_new.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
self.pushButtonNew.setIcon(icon2)
self.pushButtonNew.setIconSize(QtCore.QSize(32, 32))
self.pushButtonNew.setObjectName("pushButtonNew")
self.pushButtonSave = QtWidgets.QPushButton(parent=self.groupBox)
self.pushButtonSave.setGeometry(QtCore.QRect(190, 20, 101, 41))
self.pushButtonSave.setStyleSheet("background-color: rgb(255, 170, 255);")
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap("images/ic_save.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
self.pushButtonSave.setIcon(icon3)
self.pushButtonSave.setIconSize(QtCore.QSize(32, 32))
self.pushButtonSave.setObjectName("pushButtonSave")
self.groupBox_2 = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox_2.setGeometry(QtCore.QRect(20, 240, 461, 111))
self.groupBox_2.setStyleSheet("background-color: rgb(234, 254, 255);")
self.groupBox_2.setObjectName("groupBox_2")
self.lineEditUnitPrice = QtWidgets.QLineEdit(parent=self.groupBox_2)
self.lineEditUnitPrice.setGeometry(QtCore.QRect(110, 80, 341, 22))
self.lineEditUnitPrice.setStyleSheet("background-color: rgb(241, 255, 202);")
self.lineEditUnitPrice.setObjectName("lineEditUnitPrice")
self.lineEditProductCode = QtWidgets.QLineEdit(parent=self.groupBox_2)
self.lineEditProductCode.setGeometry(QtCore.QRect(110, 20, 341, 22))
self.lineEditProductCode.setStyleSheet("background-color: rgb(241, 255, 202);")
self.lineEditProductCode.setObjectName("lineEditProductCode")
self.lineEditProductName = QtWidgets.QLineEdit(parent=self.groupBox_2)
self.lineEditProductName.setGeometry(QtCore.QRect(110, 50, 341, 22))
self.lineEditProductName.setStyleSheet("background-color: rgb(241, 255, 202);")
self.lineEditProductName.setObjectName("lineEditProductName")
self.label_2 = QtWidgets.QLabel(parent=self.groupBox_2)
self.label_2.setGeometry(QtCore.QRect(10, 50, 91, 16))
self.label_2.setObjectName("label_2")
self.label = QtWidgets.QLabel(parent=self.groupBox_2)
self.label.setGeometry(QtCore.QRect(10, 20, 81, 16))
self.label.setObjectName("label")
self.label_3 = QtWidgets.QLabel(parent=self.groupBox_2)
self.label_3.setGeometry(QtCore.QRect(10, 80, 91, 16))
self.label_3.setObjectName("label_3")
self.groupBox_3 = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox_3.setGeometry(QtCore.QRect(20, 30, 461, 201))
self.groupBox_3.setStyleSheet("background-color: rgb(241, 255, 202);")
self.groupBox_3.setObjectName("groupBox_3")
self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox_3)
self.verticalLayout.setObjectName("verticalLayout")
self.tableWidgetProduct = QtWidgets.QTableWidget(parent=self.groupBox_3)
self.tableWidgetProduct.setStyleSheet("background-color: rgb(255, 255, 255);")
self.tableWidgetProduct.setObjectName("tableWidgetProduct")
self.tableWidgetProduct.setColumnCount(4)
self.tableWidgetProduct.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidgetProduct.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidgetProduct.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidgetProduct.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidgetProduct.setHorizontalHeaderItem(3, item)
self.verticalLayout.addWidget(self.tableWidgetProduct)
self.label_4 = QtWidgets.QLabel(parent=self.centralwidget)
self.label_4.setGeometry(QtCore.QRect(70, 0, 341, 31))
font = QtGui.QFont()
font.setPointSize(15)
font.setBold(True)
font.setItalic(True)
font.setWeight(75)
self.label_4.setFont(font)
self.label_4.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.label_4.setObjectName("label_4")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 491, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Trần Duy Thanh - SQLite"))
self.groupBox.setTitle(_translate("MainWindow", "Action"))
self.pushButtonRemove.setText(_translate("MainWindow", "Remove"))
self.pushButtonNew.setText(_translate("MainWindow", "New"))
self.pushButtonSave.setText(_translate("MainWindow", "Save"))
self.groupBox_2.setTitle(_translate("MainWindow", "Product Detail:"))
self.label_2.setText(_translate("MainWindow", "Product Name:"))
self.label.setText(_translate("MainWindow", "Product Code:"))
self.label_3.setText(_translate("MainWindow", "Unit Price:"))
self.groupBox_3.setTitle(_translate("MainWindow", "List Products:"))
item = self.tableWidgetProduct.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Id"))
item = self.tableWidgetProduct.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Product Code"))
item = self.tableWidgetProduct.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Product Name"))
item = self.tableWidgetProduct.horizontalHeaderItem(3)
item.setText(_translate("MainWindow", "Unit Price"))
self.label_4.setText(_translate("MainWindow", "Product - SQLite"))
Bước 5: Viết file mã lệnh “MainWindowEx.py” kế thừa từ “MainWindow.py” để xử lý sự kiện người dùng, cũng như không bị lệ thuộc vào giao diện trong tương lai thay đổi mà phải generate lại mã nguồn giao diện.
from PyQt6.QtSql import QSqlDatabase, QSqlTableModel, QSqlRecord
from PyQt6.QtWidgets import QTableWidgetItem, QMessageBox
from MainWindow import Ui_MainWindow
class MainWindowEx(Ui_MainWindow):
def __init__(self):
self.databasePath="database/MyDatabase.sqlite"
self.selectedRecord=None
self.selectedRow=None
Trong MainWindowEx, Tui định nghĩa 3 biến:
- databasePath để lưu trữ đường dẫn tới SQLite mà ta thiết kế
- selectedRecord là biến lưu trữ đối tượng QSqlRecord đang chọn để hỗ trợ cho việc Lưu mới hay cập nhật dữ liệu tiện lợi nhất
- selectedRow là biến lưu trữ dòng hiện tại đang chọn (index) để hỗ trợ cho việc Lưu mới hay cập nhật dữ liệu tiện lợi nhất
Hàm setupUi được override để định mặc định gọi các kết nối và hiển thị dữ liệu danh sách Product lên QTableWidget, cũng như gán các signal để xử lý sử kiện người dùng:
def setupUi(self, MainWindow):
super().setupUi(MainWindow)
self.MainWindow=MainWindow
self.connectDatabase()
self.loadProduct()
self.pushButtonNew.clicked.connect(self.processNew)
self.tableWidgetProduct.itemSelectionChanged.connect(self.processItemSelection)
self.pushButtonSave.clicked.connect(self.processSave)
self.pushButtonRemove.clicked.connect(self.processRemove)
Hàm connectDatabase sẽ gọi các kết nối tới cơ sở dữ liệu SQLite:
def connectDatabase(self):
# create QSqlDatabase object
self.db = QSqlDatabase("QSQLITE")
# set the database selected path
self.db.setDatabaseName(self.databasePath)
# Open the SQLite database
self.db.open()
# Create QSqlTableModel object, and self.db is assigned
self.model = QSqlTableModel(db=self.db)
Đối tượng QSqlitableModel được kích hoạt và được giao cho biến model quản lý
biến model này sẽ trỏ tới bất kỳ bảng dữ liệu nào mà ta mong muốn truy suất.
Hàm loadProduct để truy vấn toàn bộ dữ liệu trong bảng Product và hiển thị lên QTableWidget:
def loadProduct(self):
# select table name to invoke data
tableName = "Product"
self.model.setTable(tableName)
# active for selecting data
self.model.select()
# reset QTableWidget to 0 row
self.tableWidgetProduct.setRowCount(0)
# loop for insert new row:
for i in range(self.model.rowCount()):
# insert new row:
self.tableWidgetProduct.insertRow(i)
# get a record with i index:
record = self.model.record(i)
itemId = QTableWidgetItem(str(record.value(0)))
itemProductCode = QTableWidgetItem(str(record.value(1)))
itemProductName = QTableWidgetItem(str(record.value(2)))
itemUnitPrice = QTableWidgetItem(str(record.value(3)))
self.tableWidgetProduct.setItem(i, 0, itemId)
self.tableWidgetProduct.setItem(i, 1, itemProductCode)
self.tableWidgetProduct.setItem(i, 2, itemProductName)
self.tableWidgetProduct.setItem(i, 3, itemUnitPrice)
hàm processNew để xóa toàn bộ dữ liệu trong QLineEdit và focus tới ô Code để hỗ trợ nhập liệu nhanh chóng. Đồng thời các biến selectedRecord và selectedRow cũng được reset về None để đánh dấu rằng khi nhấn “Save” là lưu mới 1 record:
def processNew(self):
self.lineEditProductCode.setText("")
self.lineEditProductName.setText("")
self.lineEditUnitPrice.setText("")
self.lineEditProductCode.setFocus()
self.selectedRecord=None
self.selectedRow=None
Hàm processItemSelection sẽ xử lý sự kiện người dùng chọn từng dòng trên QTableWidget, nó truy vấn dữ liệu trong model và hiển thị lên phần Product Details:
def processItemSelection(self):
#Get current row index on the QTableWidget
self.selectedRow=self.tableWidgetProduct.currentRow()
if self.selectedRow==-1:
return
#call record(index) method from model
self.selectedRecord=self.model.record(self.selectedRow)
#Get detail information from QSqlRecord
#id=self.selectedRecord.value(0)
productCode=self.selectedRecord.value(1)
productName=self.selectedRecord.value(2)
unitPrice=self.selectedRecord.value(3)
# show detail information into the QLineEdit
self.lineEditProductCode.setText(productCode)
self.lineEditProductName.setText(productName)
self.lineEditUnitPrice.setText(str(unitPrice))
Hàm processSave sẽ thực hiện 2 tác vụ: Lưu mới và lưu cập nhật, nếu selectedRecord là None thì lưu mới, còn selectedRecord là khác None thì lưu cập nhật:
def processSave(self):
#Get lasted row
row = self.model.rowCount()
if self.selectedRecord==None:#if new product
#Get the QSqlRecord from record(row)
record=self.model.record(row)
#assign the value for QSqlRecord
#record.setValue(0, None)
record.setValue(1,self.lineEditProductCode.text())
record.setValue(2, self.lineEditProductName.text())
record.setValue(3, float(self.lineEditUnitPrice.text()))
#call the insertRecord for storing a new record into SQLite
result=self.model.insertRecord(row,record)
#if saving successful then result =True
if result==True:
#save the lasted record and reload products
self.selectedRecord=record
self.selectedRow=row
self.loadProduct()
else:#if updating the QSqlRecord
# assign the value for QSqlRecord
self.selectedRecord.setValue(1, self.lineEditProductCode.text())
self.selectedRecord.setValue(2, self.lineEditProductName.text())
self.selectedRecord.setValue(3, float(self.lineEditUnitPrice.text()))
# call the updateRowInTable for updating selected record into SQLite
result=self.model.updateRowInTable(self.selectedRow,self.selectedRecord)
# if saving successful then result =True
if result == True:
#reload products
self.loadProduct()
- hàm insertRecord(row,record) để lưu mới, nếu lưu thành công thì nó trả kết quả về là True
- hàm updateRowInTable(row,record) để lưu cập nhật, nếu lưu thành công thì nó trả kết quả về là True
Khi lưu thành công thì chương trình sẽ nạp lại dữ liệu lên QTableWidget.
Hàm processRemove dùng để xóa QSqlRecord đang chọn trên QTableWidget:
def processRemove(self):
dlg = QMessageBox(self.MainWindow)
if self.selectedRecord == None:
dlg.setWindowTitle("Deleteing error")
dlg.setIcon(QMessageBox.Icon.Critical)
dlg.setText("You have to select a Product to delete")
dlg.exec()
return
dlg.setWindowTitle("Confirmation Deleting")
dlg.setText("Are you sure you want to delete?")
buttons = QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
dlg.setStandardButtons(buttons)
button = dlg.exec()
if button == QMessageBox.StandardButton.Yes:
#call removeRow method to remove QSqlRecord from the SQLite
result=self.model.removeRow(self.selectedRow)
# if saving successful then result =True
if result == True:
# save the lasted record and reload products
self.loadProduct()
self.processNew()
- Tui coding dùng QMessageBox để hiển thị cửa sổ xác nhận có muốn xóa hay không
- Hàm removeRow(row) dùng để xóa dòng dữ liệu đang chọn ra khỏi bảng. Nếu xóa thành công thì kết quả trả về là True, lúc này ta nạp lại dữ liệu lên giao diện QTableWidget, đồng thời gọi hàm processNew để xóa dữ liệu trong QLineEdit đi
Dưới đây là coding đầy đủ của chương trình:
from PyQt6.QtSql import QSqlDatabase, QSqlTableModel, QSqlRecord
from PyQt6.QtWidgets import QTableWidgetItem, QMessageBox
from MainWindow import Ui_MainWindow
class MainWindowEx(Ui_MainWindow):
def __init__(self):
self.databasePath="database/MyDatabase.sqlite"
self.selectedRecord=None
self.selectedRow=None
def setupUi(self, MainWindow):
super().setupUi(MainWindow)
self.MainWindow=MainWindow
self.connectDatabase()
self.loadProduct()
self.pushButtonNew.clicked.connect(self.processNew)
self.tableWidgetProduct.itemSelectionChanged.connect(self.processItemSelection)
self.pushButtonSave.clicked.connect(self.processSave)
self.pushButtonRemove.clicked.connect(self.processRemove)
def connectDatabase(self):
# create QSqlDatabase object
self.db = QSqlDatabase("QSQLITE")
# set the database selected path
self.db.setDatabaseName(self.databasePath)
# Open the SQLite database
self.db.open()
# Create QSqlTableModel object, and self.db is assigned
self.model = QSqlTableModel(db=self.db)
def loadProduct(self):
# select table name to invoke data
tableName = "Product"
self.model.setTable(tableName)
# active for selecting data
self.model.select()
# reset QTableWidget to 0 row
self.tableWidgetProduct.setRowCount(0)
# loop for insert new row:
for i in range(self.model.rowCount()):
# insert new row:
self.tableWidgetProduct.insertRow(i)
# get a record with i index:
record = self.model.record(i)
itemId = QTableWidgetItem(str(record.value(0)))
itemProductCode = QTableWidgetItem(str(record.value(1)))
itemProductName = QTableWidgetItem(str(record.value(2)))
itemUnitPrice = QTableWidgetItem(str(record.value(3)))
self.tableWidgetProduct.setItem(i, 0, itemId)
self.tableWidgetProduct.setItem(i, 1, itemProductCode)
self.tableWidgetProduct.setItem(i, 2, itemProductName)
self.tableWidgetProduct.setItem(i, 3, itemUnitPrice)
def processNew(self):
self.lineEditProductCode.setText("")
self.lineEditProductName.setText("")
self.lineEditUnitPrice.setText("")
self.lineEditProductCode.setFocus()
self.selectedRecord=None
self.selectedRow=None
def processItemSelection(self):
#Get current row index on the QTableWidget
self.selectedRow=self.tableWidgetProduct.currentRow()
if self.selectedRow==-1:
return
#call record(index) method from model
self.selectedRecord=self.model.record(self.selectedRow)
#Get detail information from QSqlRecord
#id=self.selectedRecord.value(0)
productCode=self.selectedRecord.value(1)
productName=self.selectedRecord.value(2)
unitPrice=self.selectedRecord.value(3)
# show detail information into the QLineEdit
self.lineEditProductCode.setText(productCode)
self.lineEditProductName.setText(productName)
self.lineEditUnitPrice.setText(str(unitPrice))
def processSave(self):
#Get lasted row
row = self.model.rowCount()
if self.selectedRecord==None:#if new product
#Get the QSqlRecord from record(row)
record=self.model.record(row)
#assign the value for QSqlRecord
#record.setValue(0, None)
record.setValue(1,self.lineEditProductCode.text())
record.setValue(2, self.lineEditProductName.text())
record.setValue(3, float(self.lineEditUnitPrice.text()))
#call the insertRecord for storing a new record into SQLite
result=self.model.insertRecord(row,record)
#if saving successful then result =True
if result==True:
#save the lasted record and reload products
self.selectedRecord=record
self.selectedRow=row
self.loadProduct()
else:#if updating the QSqlRecord
# assign the value for QSqlRecord
self.selectedRecord.setValue(1, self.lineEditProductCode.text())
self.selectedRecord.setValue(2, self.lineEditProductName.text())
self.selectedRecord.setValue(3, float(self.lineEditUnitPrice.text()))
# call the updateRowInTable for updating selected record into SQLite
result=self.model.updateRowInTable(self.selectedRow,self.selectedRecord)
# if saving successful then result =True
if result == True:
#reload products
self.loadProduct()
def processRemove(self):
dlg = QMessageBox(self.MainWindow)
if self.selectedRecord == None:
dlg.setWindowTitle("Deleteing error")
dlg.setIcon(QMessageBox.Icon.Critical)
dlg.setText("You have to select a Product to delete")
dlg.exec()
return
dlg.setWindowTitle("Confirmation Deleting")
dlg.setText("Are you sure you want to delete?")
buttons = QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
dlg.setStandardButtons(buttons)
button = dlg.exec()
if button == QMessageBox.StandardButton.Yes:
#call removeRow method to remove QSqlRecord from the SQLite
result=self.model.removeRow(self.selectedRow)
# if saving successful then result =True
if result == True:
# save the lasted record and reload products
self.loadProduct()
self.processNew()
def show(self):
self.MainWindow.show()
Bước 6: Cuối cùng ta tạo “MyApp.py” để thực thi chương trình:
from PyQt6.QtWidgets import QApplication, QMainWindow
from MainWindowEx import MainWindowEx
app=QApplication([])
myWindow=MainWindowEx()
myWindow.setupUi(QMainWindow())
myWindow.show()
app.exec()
Chạy chương trình ta có kết quả như mong muốn:
Như vậy là tới đây các Bạn đã biết cách xây dựng một phần mềm hoàn chỉnh có tương tác SQLite từ khâu: Xem, thêm, sửa xóa. Cũng như ôn tập lại các signal, xử lý sự kiện QMessageBox…
Các bạn có thể áp dụng bài này vào các bài quản lý khác như quản lý Nhân viên, quản lý kho….
Mã lệnh đầy đủ của dự án bạn tải ở đây:
https://www.mediafire.com/file/mcvu25j1fibpliu/LearnQTableWidgetPart4.rar/file
Bài học tiếp theo Tui trình bày về ViewModel để hiển thị dữ liệu dạng Bảng nhưng nó cao cấp hơn. Các bạn chú ý theo dõi:
Chúc các bạn thành công