Bài 16: QCombobox – Basic Widgets – PyQt6

Nếu bạn muốn hiển thị dữ liệu dạng danh sách và cho người dùng lựa chọn một phần tử trong danh sách này thì ta dùng QComboBox. Ví dụ như bạn muốn hiển thị danh sách Tỉnh Thành, hiển thị danh sách Danh mục Sản phẩm, hiển thị Danh sách Phòng ban…. thì QComboBox là một trong các lựa chọn khá phù hợp.

Một số thuộc tính, signal, phương thức thường dùng của QComboBox:

Thuộc tính/Phương thức/signalÝ nghĩa/ Chức năng
QCombobBox(self)Constructor để tạo đối tượng QComboBox
addItem(text, userData)Hàm thêm một phần tử vào cuối QComboBox. userData là đối tượng tương ứng lúc thêm phần tử, nó có thể None
insertItem(index, text, userData)Hàm chèn một phần tử vào vị trí index trong QComboBox. userData là đối tượng tương ứng lúc chèn phần tử, nó có thể None
addItems(texts)Hàm thêm nhiều phần tử vào QComboBox
insertItems(index,texts)Hàm chèn nhiều phần tử vào QComboBox bắt đầu từ vị trí index
currentData()Hàm trả về đối tượng tại phần tử đang chọn trên QComboBox
currentIndex()Hàm trả về vị trí hiện tại phần tử đang chọn trên QComboBox
currentText()Hàm trả về text hiện tại phần tử đang chọn trên QComboBox
setEditable(True/False)Hàm thiết lập cho phép nhập liệu trong QComboBox hay không
activatedsignal để xử lý lấy dữ liệu mà người dùng đang chọn phần tử trong QComboBox.

Dưới đây là các bước cơ bản để tạo và sử dụng QCombobox với dữ liệu cơ bản (các ví dụ sau ta sẽ sử dụng dữ liệu dạng đối tượng), tạo dự án “LearnQComboBox” trong Pycharm, sau đó tạo tập tin “QComboBoxBasicDemo.py” viết mã lệnh trong tập tin này:

Bước 1: Gọi thư viện để sử dụng QComboBox

from PyQt6.QtWidgets import QComboBox

Bước 2: Tạo đối tượng QComboBox

self.cboCategory = QComboBox(self)

Bước 3: Thêm các dữ liệu vào QComboBox bằng addItem hoặc insertItem

self.cboCategory.addItem('Laptop')
self.cboCategory.addItem('Phone & Tablet')
self.cboCategory.addItem('Smart Watch')
self.cboCategory.insertItem(1,"Head Phone")

Chúng ta cũng có thể chèn hoặc thêm nhiều dữ liệu cùng một lúc vào QComboBox:

self.cboCategory.insertItems(2,["Mouse","Mouse Pad"])
self.cboCategory.addItems(["Game & Stream","Monitor"])

Bước 4: Xử lý signal khi người dùng nhấn chọn phần tử trên QComboBox

self.cboCategory.activated.connect(self.processSelectedComboBox)

Slot processSelectedComboBox để lấy index và text của phần tử đang chọn trên QComboBox:

def processSelectedComboBox(self):
    index=self.cboCategory.currentIndex()
    text=self.cboCategory.currentText()
    self.result_label.setText(
        f'You selected index= {index}, text={text}')

Dưới đây là mã lệnh đầy đủ minh họa sử dụng và xử lý sự kiện cho QComboBox mức cơ bản:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QComboBox

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('Tran Duy Thanh')
        self.setMinimumWidth(300)

        # create a grid layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        cb_label = QLabel('Please select a Category:', self)

        # create a combobox
        self.cboCategory = QComboBox(self)
        self.cboCategory.addItem('Laptop')
        self.cboCategory.addItem('Phone & Tablet')
        self.cboCategory.addItem('Smart Watch')
        self.cboCategory.insertItem(1,"Head Phone")

        self.cboCategory.insertItems(2,["Mouse","Mouse Pad"])
        self.cboCategory.addItems(["Game & Stream","Monitor"])

        self.cboCategory.activated.connect(self.processSelectedComboBox)

        self.result_label = QLabel('', self)

        layout.addWidget(cb_label)
        layout.addWidget(self.cboCategory)
        layout.addWidget(self.result_label)

        self.show()

    def processSelectedComboBox(self):
        index=self.cboCategory.currentIndex()
        text=self.cboCategory.currentText()
        self.result_label.setText(
            f'You selected index= {index}, text={text}')
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())

Chạy phần mềm lên ta có giao diện, chọn một item bất kỳ:

Chọn Item bất kỳ ta có kết quả:

Bây giờ Tui sẽ nâng cấp bài trên bằng cách bổ sung các lớp mô hình lớp hướng đối tượng để lưu trữ, hiển thị và xử lý thao tác người dùng tốt hơn trong trường hợp dữ liệu có nhiều thông tin khác nhau.

Bổ sung vào dự án “LearnQComboBox” có cấu trúc như dưới đây:

  • Thư mục “images” để lưu trữ một số hình ảnh cho các danh mục sản phẩm
  • Category.py là lớp đối tượng Danh Mục có id và name
  • QComboBoxAdvancedDemo.py để tạo giao diện sử dụng QComboBox của dữ liệu là hướng đối tượng Category và các icon tương ứng.

Lớp Category.py có mã lệnh như dưới đây:

class Category:
    def __init__(self,id,name):
        self.id=id
        self.name=name
    def __str__(self):
        return str(self.id)+"-"+self.name

Lớp Category có 2 thuộc tính là id và name. Ta cung cấp 2 hàm, hàm thứ nhất là contructor nhận vào 2 đối số id, name. Hàm thứ 2 là __str__() hàm này tương đương với các hàm toString() của ngôn ngữ Java, C#… nó sẽ tự động được triệu gọi khi ta hiển thị đối tượng lên giao diện. Do đó, muốn dữ liệu hiển thị như thế nào thì ta có thể hiệu trong trong hàm __str__()

Lớp “QComboBoxAdvancedDemo.py” có sự khác biệt so với BasicDemo là ta thêm Icon và các Đối tượng cho QComboBox:

self.cboCategory = QComboBox(self)

laptop_icon=QIcon("images/laptop.png")
laptop_model=Category(100,"Laptop")
self.cboCategory.addItem(laptop_icon,laptop_model.name,laptop_model)

phone_icon = QIcon("images/phone.png")
phone_model = Category(200, "Phone")
self.cboCategory.addItem(phone_icon, phone_model.name, phone_model)

smart_icon = QIcon("images/smartwatch.png")
smart_model = Category(300, "Smart Watch")
self.cboCategory.addItem(smart_icon, smart_model.name, smart_model)

Mã lệnh ở trên khi đưa dữ liệu lên QComboBox sẽ gồm 3 dữ liệu: Icon, text hiển thị, và đối tượng tương ứng. Đối tượng tương ứng này sẽ rất hiểu quả trong quá trình xử lý dữ liệu được lựa chọn trên giao diện.

Để xử lý sự kiện, ta cũng gán signal như bình thường, ở đây ta có thể lấy currentData() để truy suất tới đối tượng lúc đưa vào QComboBox, lấy currentText(), lấy currentIndex(). Trong bài này Tui minh họa cách lấy currentData() còn các hàm khác làm tương tự như ví dụ trước đó:

self.cboCategory.activated.connect(self.processSelectedComboBox)
def processSelectedComboBox(self):
    data=self.cboCategory.currentData()
    self.result_label.setText(
        f'You selected index= {data}')

Khi data được hiển thị lên màn hình thì hàm __str__() sẽ tự động được triệu gọi.

Dưới đây là mã lệnh đầy đủ của “QComboBoxAdvancedDemo.py”:

import sys

from PyQt6.QtGui import QIcon
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QComboBox

from Category import Category


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('Tran Duy Thanh')
        self.setMinimumWidth(300)

        # create a grid layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        cb_label = QLabel('Please select a Category:', self)

        # create a combobox
        self.cboCategory = QComboBox(self)

        laptop_icon=QIcon("images/laptop.png")
        laptop_model=Category(100,"Laptop")
        self.cboCategory.addItem(laptop_icon,laptop_model.name,laptop_model)

        phone_icon = QIcon("images/phone.png")
        phone_model = Category(200, "Phone")
        self.cboCategory.addItem(phone_icon, phone_model.name, phone_model)

        smart_icon = QIcon("images/smartwatch.png")
        smart_model = Category(300, "Smart Watch")
        self.cboCategory.addItem(smart_icon, smart_model.name, smart_model)


        self.cboCategory.activated.connect(self.processSelectedComboBox)

        self.result_label = QLabel('', self)

        layout.addWidget(cb_label)
        layout.addWidget(self.cboCategory)
        layout.addWidget(self.result_label)

        self.show()

def processSelectedComboBox(self):
    data=self.cboCategory.currentData()
    self.result_label.setText(
        f'You selected index= {data}')
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())

Chạy phần mềm lên ta có kết quả:

Mã lệnh đầy đủ của 2 ví dụ về QComboBox này các bạn tải ở đây:

https://www.mediafire.com/file/8hjvyv8lncuyhae/LearnQComboBox.rar/file

Bây giờ Tui hướng dẫn các bạn ứng dụng QComboBox vào việc xây dựng phần mềm như dưới đây:

Tạo một dự án tên “LearnQComboBoxAdvanced” trong Pycharm:

Trong dự án ở trên, tạo thư mục “images”, bổ sung thêm các biểu tượng liên quan tới các thành phố.

Sau đó dùng Qt Designer để thiết kế giao diện như dưới đây (MainWindow.ui):

Các widget kéo ra như trên, định dạng và đặt tên cho các Widget này như hình:

ComboBox City ta kéo vào, và nhập dữ liệu cho widget này như sau (double click vào widget sau khi kéo vào giao diện):

  • Nhấn biểu tượng dấu “+” để nhập thêm item cho QComboBox
  • Nhấn biểu tượng dấu “-” để xóa item đang chọn ra khỏi QComboBox
  • Các biểu tượng mũi tên lên, xuống để thay đổi vị trí của các item trong QComboBox
  • Nút lệnh “Properties” để hiển thị chi tiết các thuộc tính của từng item trong QComboBox. Bạn muốn thêm Icon cho item thì bấm chọn Choose File… trong nhóm icon như hình trên.

Sau khi chọn đầy đủ các hình cho Item ta có kết quả như hình bên dưới:

Sau khi thiết kế xong giao diện, ta lưu lại với tên “MainWindow.ui” rồi qua lại Pycharm để Generate code Python thành “MainWindow.py”. Sau đó tiến hành bổ sung thêm 1 class tên là “Employee” có các thông số sau:

class Employee:
    def __init__(self,fullName,gender,city):
        self.fullName=fullName
        self.gender=gender
        self.city=city

Tiếp theo tạo “MainWindowEx.py” kế thừa từ lớp được Generate trong “MainWindow.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
    def show(self):
        self.MainWindow.show()

Các mã lệnh chi tiết xử lý sự kiện ta sẽ bổ sung sau cho MainWindowEx.

Tiếp theo 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()

Ta xem cấu trúc dữ liệu cuối cùng trong Pycharm:

Chạy “MyApp.py” ta có kết quả:

Như vậy ta có được giao diện như mong muốn.

Bây giờ ta bổ sung thêm hàm __str__ để trả về chuỗi json:

import json

class Employee:
    def __init__(self,fullName,gender,city):
        self.fullName=fullName
        self.gender=gender
        self.city=city
    def __str__(self):
        return json.dumps(self.__dict__)

Hàm __str__ sẽ được sử dụng khi ta hiển thị đối tượng lên giao diện

Sau đó ta tiếp tục bổ sung mã lệnh cho MainWindow.py để xử lý sự kiện:

from Employee import Employee
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.pushButtonClose.clicked.connect(self.processClose)
        self.pushButtonConfirm.clicked.connect(self.processConfirmation)
    def processConfirmation(self):
        name=self.lineEditfullName.text()
        gender="Man"
        if self.chkGender.isChecked():
            gender="Woman"
        city=self.cboCity.currentText()
        emp=Employee(name,gender,city)
        self.plainTextEditOutput.setPlainText(str(emp))
    def processClose(self):
        self.MainWindow.close()
    def show(self):
        self.MainWindow.show()

Mã lệnh slot “processConfirmation” ở trên sẽ lắng nghe và xử lý lấy các dữ liệu từ giao diện mà người dùng cung cấp.

Dòng lệnh 18 sẽ khởi tạo 1 đối tượng Employee

Dòng lệnh 19 dùng str(emp) để chương trình tự động triệu gọi __str__ để lấy chuỗi JSON của đối tượng và sau đó hiển thị lên giao diện.

Khi nhấn nút “Confirm” sẽ hiển thị dữ liệu JSON vào màn hình OutPut, nhấn “Close” sẽ đóng cửa sổ:

Như vậy tới đây Tui đã trình bày xong các kiến thức liên quan tới QComboBox cũng như các kỹ thuật lập trình, ứng dụng QComboBox và các dự án mẫu. Thông qua 3 ví dụ ở trên các bạn đã có đủ kiến thức và kỹ năng để sử dụng và phát triển mở rộng QComboBox ở các trường hợp khác nhau. Các bạn cố gắng thực hành lại nhiều lần để hiểu rõ hơn về Widget này.

Mã lệnh của bài này các bạn tải ở đây:

https://www.mediafire.com/file/evpr0v8xdx82el2/LearnQComboBoxAdvanced.rar/file

Bài học sau, Tui sẽ trình bày về wiget QListWidget, nó cũng là một dạng widget dùng để hiển thị dữ liệu dạng danh sách nhưng nó có một chút ít khác biết so với QComboBox.

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

One thought on “Bài 16: QCombobox – Basic Widgets – PyQt6”

Leave a Reply