Bài 22: Hiển thị dữ liệu dạng bảng- QTableWidget–Part 1

Ở các bài học trước, Chúng ta đã dùng QComboBox, QListWidget để hiển thị dữ liệu dạng danh sách, tuy nhiên nó chưa được chi tiết hóa cho từng thuộc tính. QTableWidget là một widget dùng để hiển thị dữ liệu dạng bảng (lưới) giúp cho việc quan sát dữ liệu được chi tiết, rõ ràng hơn. Và trong thực tế các dữ liệu của chúng ta cũng thường có nhiều thuộc tính để hiển thị, do đó QTableWidget là một trong các Widget quan trọng thường dùng để hiển thị dữ liệu.

Bài học này Tui sẽ trình bày cách thức kéo thả QTableWidget, tạo các cột, dòng dữ liệu bằng Qt Designer để các bạn có cảm giác trước, các bài học sau Tui sẽ trình bày các kỹ thuật nâng cao về TableWidget chẳng hạn như cách nạp dữ liệu runtime, kết hợp mô hình hướng đối tượng, xử lý MVC Model cho QTable Widget, tương tác dữ liệu với SQLite….

Trước tiên chúng ta cần biết sơ qua Các thuộc tính, phương thức và signal thường dùng của QTableWidget:

Thuộc tính, phương thức, signalÝ nghĩa chức năng
QTableWidget()Constructor để tạo đối tượng QTableWidget
QTableWidget(rows, columns)Constructor để tạo đối tượng QTableWidget, mặc định có rows dòng và columns cột
setRowCount(rows)Hàm thiết lập số dòng cho QTableWidget
setColumnCount(columns)Hàm thiết lập số cột cho QTableWidget
setHorizontalHeaderLabels(labels)Hàm thiết lập tiêu đề cột
setColumnWidth(column, width)Hàm thiết lập độ rộng của cột
rowCount()Hàm trả về số dòng trong QTableWidget
insertRow(row)Hàm chèn một item mới vào vị trí row trong QTableWidget
setItem(row, column, item)Hàm thiết lập các giá trị cho CELL của Item.
removeRow(current_row)Hàm xóa dòng khỏi QTableWidget
itemSelectionChangedsignal để lắng nghe người sử dụng đang chọn dòng dữ liệu nào trong QTableWidget
currentRow()Hàm trả về vị trí của dòng đang lựa chọn trên giao diện
item(row,column)Trả về ô giao nhau giữa row và column

Ví dụ dưới đây Tui sẽ hướng dẫn các bạn cách dùng Qt Designer để kéo thả, thiết kế giao diện cho QTableWidget.

Bước 1: Tạo một dự án “LearnQTableWidget” trong Pycharm

Bước 2: Dùng Qt Designer để thiết kế giao diện cho MainWindow.ui

Kéo thả TableWidget vào MainWindow như hình dưới đây:

Sau đó bổ sung các Columns, Rows, Items cho QTableWidget cũng như các Widget cơ bản như hình dưới:

Các QLineEdit, QPushButton các bạn đã được học rất kỹ ở các bài trước rồi nên Tui không nhắc lại.

Bây giờ chúng ta sẽ cấu hình Cột và Dòng cũng như Items cho QTableWidget:

Chúng ta chỉ cần Double Click chuột vào QTableWidget hoặc bấm chuột phải vào nó rồi chọn “Edit Items”:

Lúc này màn hình Edit Table Widget sẽ hiển thị ra như bên dưới:

  • Thẻ “Columns” dùng để định nghĩa tiêu đề cột: Ở đây các bạn gõ Song ID, Song Name, và Singer. Có thể thêm Columns bằng cách nhấn vào biểu tưởng dấu +, Có thể xóa bằng biểu tượng dấu trừ, thay đổi vị trí xuất hiện bằng các mũi tên lên xuống

Tương tự như vậy ta vào thẻ “Rows” để tạo các tiêu đề dòng cho QTableWidget:

  • Thẻ “Rows” dùng để định nghĩa tiêu đề dòng: Ở đây các bạn thêm các tiêu đề dòng từ 1 tới 5. Có thể thêm Rows bằng cách nhấn vào biểu tưởng dấu +, Có thể xóa bằng biểu tượng dấu trừ, thay đổi vị trí xuất hiện bằng các mũi tên lên xuống.

Cuối cùng là thẻ “Items” dùng để nhập dữ liệu cho QTableWidget:

Ngoài ra QTableWidget cũng cung cấp chức năng định dạng nâng cao cho cả “Columns”, “Rows” và “Items” bằng cách nhấn vào nút “Properties“:

Tương ứng với mỗi thẻ “Columns”, “Rows” hay “Items” mà QTableWidget sẽ cung cấp các thuộc tính khác nhau trong “Properties”. Tùy vào nhu cầu sử dụng mà các bạn có thể cấu hình chẳng hạn như: Chuỗi hiểu thị, Icon, font chữ, màu nền, màu chữ…

Sau khi kéo thả đầy đủ các Widget như giao diện thiết kế, các bạn tiến hành đặt tên cho chúng để ta lập trình:

Bước 3: Dùng Công cụ Generate Python code tự động cho giao diện cho MainWindow.ui để tạo file mã lệnh Python “MainWindow.py“:

# Form implementation generated from reading ui file 'MainWindow.ui'
#
# Created by: PyQt6 UI code generator 6.5.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(476, 376)
        self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidgetSong = QtWidgets.QTableWidget(parent=self.centralwidget)
        self.tableWidgetSong.setGeometry(QtCore.QRect(10, 10, 451, 191))
        self.tableWidgetSong.setObjectName("tableWidgetSong")
        self.tableWidgetSong.setColumnCount(3)
        self.tableWidgetSong.setRowCount(5)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setVerticalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setVerticalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setVerticalHeaderItem(2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setVerticalHeaderItem(3, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setVerticalHeaderItem(4, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setHorizontalHeaderItem(2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(0, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(0, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(0, 2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(1, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(1, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(1, 2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(2, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(2, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(2, 2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(3, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(3, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(3, 2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(4, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(4, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetSong.setItem(4, 2, item)
        self.label = QtWidgets.QLabel(parent=self.centralwidget)
        self.label.setGeometry(QtCore.QRect(20, 220, 71, 16))
        self.label.setObjectName("label")
        self.lineEditSongID = QtWidgets.QLineEdit(parent=self.centralwidget)
        self.lineEditSongID.setGeometry(QtCore.QRect(110, 220, 351, 20))
        self.lineEditSongID.setObjectName("lineEditSongID")
        self.lineEditSongName = QtWidgets.QLineEdit(parent=self.centralwidget)
        self.lineEditSongName.setGeometry(QtCore.QRect(110, 250, 351, 20))
        self.lineEditSongName.setObjectName("lineEditSongName")
        self.label_2 = QtWidgets.QLabel(parent=self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(20, 250, 81, 16))
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(parent=self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(20, 280, 81, 16))
        self.label_3.setObjectName("label_3")
        self.lineEditSinger = QtWidgets.QLineEdit(parent=self.centralwidget)
        self.lineEditSinger.setGeometry(QtCore.QRect(110, 280, 351, 20))
        self.lineEditSinger.setObjectName("lineEditSinger")
        self.pushButtonClose = QtWidgets.QPushButton(parent=self.centralwidget)
        self.pushButtonClose.setGeometry(QtCore.QRect(110, 310, 75, 23))
        self.pushButtonClose.setObjectName("pushButtonClose")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 476, 22))
        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)
        self.pushButtonClose.clicked.connect(MainWindow.close) # type: ignore
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Trần Duy Thanh-QTableWidget"))
        item = self.tableWidgetSong.verticalHeaderItem(0)
        item.setText(_translate("MainWindow", "1"))
        item = self.tableWidgetSong.verticalHeaderItem(1)
        item.setText(_translate("MainWindow", "2"))
        item = self.tableWidgetSong.verticalHeaderItem(2)
        item.setText(_translate("MainWindow", "3"))
        item = self.tableWidgetSong.verticalHeaderItem(3)
        item.setText(_translate("MainWindow", "4"))
        item = self.tableWidgetSong.verticalHeaderItem(4)
        item.setText(_translate("MainWindow", "5"))
        item = self.tableWidgetSong.horizontalHeaderItem(0)
        item.setText(_translate("MainWindow", "Song ID"))
        item = self.tableWidgetSong.horizontalHeaderItem(1)
        item.setText(_translate("MainWindow", "Song Name"))
        item = self.tableWidgetSong.horizontalHeaderItem(2)
        item.setText(_translate("MainWindow", "Singer"))
        __sortingEnabled = self.tableWidgetSong.isSortingEnabled()
        self.tableWidgetSong.setSortingEnabled(False)
        item = self.tableWidgetSong.item(0, 0)
        item.setText(_translate("MainWindow", "S1"))
        item = self.tableWidgetSong.item(0, 1)
        item.setText(_translate("MainWindow", "Không yêu đừng nói lời cay đắng"))
        item = self.tableWidgetSong.item(0, 2)
        item.setText(_translate("MainWindow", "Tèo Mộng Mơ"))
        item = self.tableWidgetSong.item(1, 0)
        item.setText(_translate("MainWindow", "P2"))
        item = self.tableWidgetSong.item(1, 1)
        item.setText(_translate("MainWindow", "Người ấy và Tui Em phải chọn"))
        item = self.tableWidgetSong.item(1, 2)
        item.setText(_translate("MainWindow", "Tý Khốn Khổ"))
        item = self.tableWidgetSong.item(2, 0)
        item.setText(_translate("MainWindow", "P3"))
        item = self.tableWidgetSong.item(2, 1)
        item.setText(_translate("MainWindow", "Yêu Em mà không dám nói"))
        item = self.tableWidgetSong.item(2, 2)
        item.setText(_translate("MainWindow", "Bin Nhút Nhát"))
        item = self.tableWidgetSong.item(3, 0)
        item.setText(_translate("MainWindow", "P4"))
        item = self.tableWidgetSong.item(3, 1)
        item.setText(_translate("MainWindow", "Đập Vỡ Cây Đàn"))
        item = self.tableWidgetSong.item(3, 2)
        item.setText(_translate("MainWindow", "Tin Nóng Tánh"))
        item = self.tableWidgetSong.item(4, 0)
        item.setText(_translate("MainWindow", "P5"))
        item = self.tableWidgetSong.item(4, 1)
        item.setText(_translate("MainWindow", "Áo Em Chưa Mặc 1 Lần"))
        item = self.tableWidgetSong.item(4, 2)
        item.setText(_translate("MainWindow", "Tủn Thợ May"))
        self.tableWidgetSong.setSortingEnabled(__sortingEnabled)
        self.label.setText(_translate("MainWindow", "Song ID:"))
        self.label_2.setText(_translate("MainWindow", "Song Name:"))
        self.label_3.setText(_translate("MainWindow", "Singer:"))
        self.pushButtonClose.setText(_translate("MainWindow", "Close"))

Bước 4: Tạo một lớp kế thừa lớp Generate từ bước 4, đặt tên “MainWindowEx.py“:

from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        self.tableWidgetSong.itemSelectionChanged.connect(self.processSelectedItem)
    def processSelectedItem(self):
        row=self.tableWidgetSong.currentRow()
        songId=self.tableWidgetSong.item(row,0)
        songName=self.tableWidgetSong.item(row,1)
        singer=self.tableWidgetSong.item(row,2)
        self.lineEditSongID.setText(songId.text())
        self.lineEditSongName.setText(songName.text())
        self.lineEditSinger.setText(singer.text())
    def show(self):
        self.MainWindow.show()

Mã lệnh trong “MainWindowEx” Tui có lập trình gọi signal itemSelectionChanged để xử lý dòng dữ liệu mà người dùng chọn trên QTableWidget. Tui tạo slot processSelectedItem tương ứng để xử lý cho signal này. Slot này sẽ lấy dữ liệu của các ô trong dòng đang chọn của QTableWidget và hiển thị lên các QLineEdit.

Bước 5: 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 “MyApp.py” ta có kết quả:

Các bạn thấy giao diện của chương trình xuất hiện như trên, các bạn chọn dòng nào thì chi tiết dữ liệu của dòng đó sẽ hiển thị vào QLineEdit ở bên dưới.

Coding đây đủ của bài này các bạn tải ở đây:

https://www.mediafire.com/file/lc84wnz3ikq7mhy/LearnQTableWidget.rar/file

Như vậy là tới đây các bạn đã biết cách sử dụng QTableWidget bằng cách kéo thả vào giao diện, biết cách tạo các Columns, Rows và Item cho QTableWidget. Đồng thời cũng biết cách cấu hình các thuộc tính nâng cao trong nhóm “Properties”. Và cũng biết sử dụng signal itemSelectionChanged để xử lý sự kiện người dùng lựa chọn các dòng trong giao diện QTableWidget.

Bài học sau Tui sẽ tiếp tục hướng dẫn các bạn cách sử dụng và lập trình QTableWidget kéo thả nhưng ở mức nâng cao hơn. Đó là các dữ liệu sẽ được thêm vào QTableWidget lúc Run time, cũng như hướng dẫn các bạn cách xử lý Sửa, Xóa các dòng dữ liệu trong QTableWidget bằng mã lệnh.

Chúc các bạn thành công.

One thought on “Bài 22: Hiển thị dữ liệu dạng bảng- QTableWidget–Part 1”

Leave a Reply