如何自定义QComboBox

1 投票
2 回答
2626 浏览
提问于 2025-04-20 13:12

我想要能够从下拉菜单中选择多个QComboBox的选项(可以通过按住Shift键或Alt键+点击来添加或移除当前选择的项)。

  1. 点击时,QComboBox会展开下拉菜单。

  2. 但是当用户第二次点击鼠标(从下拉菜单中选择一个选项)时,

ComboBox不会像默认那样自动收回(或自我关闭)。相反,它会保持打开状态,这样用户就可以通过Shift+点击来选择更多的ComboBox选项,添加或移除它们。最后,当用户对选择满意时,按下Enter键来“确认”选择。

下面是一张经过Photoshop处理的图片,展示了我想要实现的“多选”QComboBox的概念:

enter image description here

下面的代码创建了一个几乎暴露了所有事件的QComboBox。但我看到的唯一“有效”的事件是onMousePressEvent()。我找不到方法来追踪用户何时从下拉菜单中选择了一个选项……

编辑:

一个小时后,我了解到QComboBox可以通过其.view().setSelectionMode(3)设置为多选。

然后同样的.view()可以用来查询ComboBox中选中的项:

selectedIndexes=self.view().selectionModel().selectedIndexes() 

(其中self是指ComboBox本身)

还有一种方法可以使用selectionModel.select(idx, QtGui.QItemSelectionModel.Select)来选择Combo项。

但到目前为止,我还没有能够做到这一点……

from PyQt4 import QtCore, QtGui

app = QtGui.QApplication([])
class Combo(QtGui.QComboBox):
    def __init__(self, *args, **kwargs):
        super(Combo, self).__init__()
        self.addItems(['Item_1','Item_2','Item_3','Item_4','Item_5'])
        self.view=self.view()
        self.view.setSelectionMode(3)
        self.activated.connect(self.clicked)   
        self.show()

    def clicked(self, arg=None):
        selectionModel=self.view.selectionModel()
        selectedIndexes=selectionModel.selectedIndexes()

        for idx in selectedIndexes:
            selectionModel.select(idx, QtGui.QItemSelectionModel.Select)
            print 'selecting idx: %s'%idx

        self.showPopup()

tree=Combo()
sys.exit(app.exec_())

2 个回答

2

我最后用文字颜色来区分被点击(也就是被选中)的项目和其他项目。

第一次点击下拉框会打开它的下拉菜单。之后的每次点击都是用来选择或取消选择(高亮显示为红色)项目。按下Esc键可以关闭下拉菜单。

在这里输入图片描述

from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])

class Combo(QtGui.QComboBox):
    def __init__(self, *args, **kwargs):
        super(Combo, self).__init__()        
        for each in ['Item_1','Item_2','Item_3','Item_4','Item_5']:
            item=QtGui.QStandardItem(each) 
            self.model().appendRow(item)
            item.setData('black')

        self.activated.connect(self.clicked)   
        self.show()  

    def clicked(self, clickedNumber=None): 
        self.blockSignals(True)  
        self.setCurrentIndex(0)        
        self.showPopup()
        self.view().clearSelection()

        clickedItem=self.model().item(clickedNumber)

        color=clickedItem.data().toString()
        if color=='black': clickedItem.setData('red')
        elif color=='red': clickedItem.setData('black')
        clickedItem.setForeground(QtGui.QColor(clickedItem.data().toString()))

        clickedIndex=self.model().indexFromItem(clickedItem)
        self.view().selectionModel().select(clickedIndex, QtGui.QItemSelectionModel.Select)
        self.setCurrentIndex(clickedNumber)  

        self.blockSignals(False)

tree=Combo()
sys.exit(app.exec_())
3

另外一种方法是,你可以使用类似图标的方式来检查状态。这比使用 QtGui.QStandardItem 要简单得多。你可以使用 QIcon QComboBox.itemIcon (self, int index) 这个方法来获取图标,也可以用 QComboBox.setItemIcon (self, int index, QIcon icon) 这个方法来设置图标。这些方法都可以在 QtGui.QComboBox 这个类中找到。

import sys
from PyQt4 import QtGui

class QCustomComboBox (QtGui.QComboBox):
    CHECK_QICON   = QtGui.QIcon.fromTheme('call-start')
    UNCHECK_QICON = QtGui.QIcon.fromTheme('call-stop')

    def __init__(self, *args, **kwargs):
        super(QCustomComboBox, self).__init__(*args, **kwargs)
        listsItem = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']
        for index in range(0, len(listsItem)):
            self.addItem(listsItem[index])
            self.setItemIcon(index, self.UNCHECK_QICON)
        self.activated.connect(self.customActivated)

    def hidePopup (self):
        pass # Force only ESC button to exit.

    def customActivated (self, index):
        # self.blockSignals(True) # Force first index only
        # self.setCurrentIndex(0)
        # self.blockSignals(False)
        stateQIcon = self.itemIcon(index)
        newQIcon = {
            self.CHECK_QICON.name()   : self.UNCHECK_QICON,
            self.UNCHECK_QICON.name() : self.CHECK_QICON,
        } [stateQIcon.name()]
        self.setItemIcon(index, newQIcon)
        print self.export() # View last update data

    def export (self):
        listsExportItem = []
        for index in range(0, self.count()):
            stateQIcon = self.itemIcon(index)
            state = {
                self.CHECK_QICON.name()   : True,
                self.UNCHECK_QICON.name() : False,
            } [stateQIcon.name()]
            listsExportItem.append([str(self.itemText(index)), state])
        return listsExportItem

myQApplication = QtGui.QApplication([])
myQCustomComboBox = QCustomComboBox()
myQCustomComboBox.show()
sys.exit(myQApplication.exec_())

撰写回答