一、前言
由於最近的項目需要具有復選功能,但過多的復選框會影響界面布局和美觀,因而想到把 PyQt5 的下拉列表和復選框結合起來,但在 PyQt5 中並沒有這樣的組件供我們使用,所以想要自己實現一個下拉復選框,主要就是繼承 QComboBox 類,然后將復選框 QCheckBox 加入其中,並實現相應的功能。
最終實現的下拉復選框效果如下:

二、代碼實現
1.主要方法
在 PyQt5 中,有幾個主要的方法需要了解一下,方法名稱和對應的含義如下:
- QtWidgets.QComboBox.setView(itemView):設置組合框彈出窗口中使用的視圖
,組合框獲取視圖的所有權。 - QtWidgets.QcomboBox.setLineEdit(QLineEdit):設置組合框使用的行,而不是當前行編輯窗口小部件。
- QtWidgets.QListWidget.setItemWidget(item, widget):設置
要在給定的 item 中的 widget 組件。
2.具體代碼
實現下拉復選框的思路為用 setView() 方法將 QComboBox 下拉列表的視圖改為 QListWidget 組件,然后將 QCheckBox 復選框用在 QListWiget 中,具體代碼如下:
1 class ComboCheckBox(QComboBox): 2 def __init__(self, items: list): 3 """ 4 initial function 5 :param items: the items of the list 6 """ 7 super(ComboCheckBox, self).__init__() 8 self.items = items # items list 9 self.box_list = [] # selected items 10 self.text = QLineEdit() # use to selected items 11 self.text.setReadOnly(True) 12 13 q = QListWidget() 14 for i in range(len(self.items)): 15 self.box_list.append(QCheckBox()) 16 self.box_list[i].setText(self.items[i]) 17 item = QListWidgetItem(q) 18 q.setItemWidget(item, self.box_list[i]) 19 self.box_list[i].stateChanged.connect(self.show_selected) 20 21 self.setLineEdit(self.text) 22 self.setModel(q.model()) 23 self.setView(q) 24 25 def get_selected(self) -> list: 26 """ 27 get selected items 28 :return: 29 """ 30 ret = [] 31 for i in range(len(self.items)): 32 if self.box_list[i].isChecked(): 33 ret.append(self.box_list[i].text()) 34 return ret 35 36 def show_selected(self): 37 """ 38 show selected items 39 :return: 40 """ 41 self.text.clear() 42 ret = '; '.join(self.get_selected()) 43 self.text.setText(ret)
其中 show_selected() 用於顯示被選中的內容,get_selected() 則用於獲取所有被選中的內容並返回。
3.增加全選
要增加全選功能,首先是要在最前面加一個全選的選擇框,然后為這個全選的選擇框綁定相應的方法,用於實現全選功能和取消全選功能,具體代碼如下:
1 def all_selected(self): 2 """ 3 decide whether to check all 4 :return: 5 """ 6 # change state 7 if self.state == 0: 8 self.state = 1 9 for i in range(1, len(self.items)): 10 self.box_list[i].setChecked(True) 11 else: 12 self.state = 0 13 for i in range(1, len(self.items)): 14 self.box_list[i].setChecked(False) 15 self.show_selected()
4.修改樣式
由於默認的樣式並不美觀,所以我們可以對控件的樣式進行自定義,例如字體大小、字體粗細等等,例如:
q.setStyleSheet("font-size: 20px; font-weight: bold; height: 40px; margin-left: 5px")
self.setStyleSheet("width: 300px; height: 50px; font-size: 21px; font-weight: bold")
三、完整程序
完善后的下拉復選框的運行程序代碼如下:
1 from PyQt5.QtWidgets import QComboBox, QLineEdit, QListWidgetItem, QListWidget, QCheckBox, \ 2 QApplication, QVBoxLayout, QWidget 3 import sys 4 5 6 class ComboCheckBox(QComboBox): 7 def __init__(self, items: list): 8 """ 9 initial function 10 :param items: the items of the list 11 """ 12 super(ComboCheckBox, self).__init__() 13 self.items = ["全選"] + items # items list 14 self.box_list = [] # selected items 15 self.text = QLineEdit() # use to selected items 16 self.state = 0 # use to record state 17 18 q = QListWidget() 19 for i in range(len(self.items)): 20 self.box_list.append(QCheckBox()) 21 self.box_list[i].setText(self.items[i]) 22 item = QListWidgetItem(q) 23 q.setItemWidget(item, self.box_list[i]) 24 if i == 0: 25 self.box_list[i].stateChanged.connect(self.all_selected) 26 else: 27 self.box_list[i].stateChanged.connect(self.show_selected) 28 29 q.setStyleSheet("font-size: 20px; font-weight: bold; height: 40px; margin-left: 5px") 30 self.setStyleSheet("width: 300px; height: 50px; font-size: 21px; font-weight: bold") 31 self.text.setReadOnly(True) 32 self.setLineEdit(self.text) 33 self.setModel(q.model()) 34 self.setView(q) 35 36 def all_selected(self): 37 """ 38 decide whether to check all 39 :return: 40 """ 41 # change state 42 if self.state == 0: 43 self.state = 1 44 for i in range(1, len(self.items)): 45 self.box_list[i].setChecked(True) 46 else: 47 self.state = 0 48 for i in range(1, len(self.items)): 49 self.box_list[i].setChecked(False) 50 self.show_selected() 51 52 def get_selected(self) -> list: 53 """ 54 get selected items 55 :return: 56 """ 57 ret = [] 58 for i in range(1, len(self.items)): 59 if self.box_list[i].isChecked(): 60 ret.append(self.box_list[i].text()) 61 return ret 62 63 def show_selected(self): 64 """ 65 show selected items 66 :return: 67 """ 68 self.text.clear() 69 ret = '; '.join(self.get_selected()) 70 self.text.setText(ret) 71 72 73 class UiMainWindow(QWidget): 74 def __init__(self): 75 super(UiMainWindow, self).__init__() 76 self.setWindowTitle('Test') 77 self.resize(600, 400) 78 combo = ComboCheckBox(["Python", "Java", "Go", "C++", "JavaScript", "PHP"]) 79 layout = QVBoxLayout() 80 layout.addWidget(combo) 81 self.setLayout(layout) 82 83 84 if __name__ == "__main__": 85 app = QApplication(sys.argv) 86 ui = UiMainWindow() 87 ui.show() 88 sys.exit(app.exec_())
