使用自定义模型和委托的自定义 ComboBox

问题描述

我有一个形式为(stringintegerbool)的项目列表,如下所示:

[ ('Item 1',12,True),('Item 2',156,('Item 3',19,False) ]

我想通过以下方式在 QComboBox 中显示:

Custom QCombobox with a green rectangle,grey text to the left and a darker number to the right

  • 元组的第一个元素左对齐
  • 数字以较深的颜色右对齐
  • 如果第三个元素设置为 True,则会显示一个彩色矩形(将替换为图标)。
    如果设置为 False,则不显示矩形,但空间应保持为空,而不是将文本向左移动

这是我到目前为止:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class MyModel(QAbstractListModel):

    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)

        self.data = [
            ('Item 1',False)
        ]

    def data(self,index,role=None):
        if role == Qt.DisplayRole:
            text = self.data[index.row()][0]
            return text

        if role == Qt.DecorationRole:
            status = self.data[index.row()][2]

            if status:
                return QColor('#22FF35')

    def rowCount(self,parent=None,**kwargs):
        return len(self.data)


class MyDelegate(QStyledItemDelegate):

    def __init__(self,**kwargs)

    def paint(self,painter,option,index):
        painter.save()

        options = QStyleOptionViewItem(option)
        self.initStyleOption(options,index)

        style = options.widget.style()

        style.drawItemText(painter,options.widget.rect(),Qt.AlignLeft,options.widget.palette(),True,options.text,QPalette.Text)

        painter.restore()


class MyComboBox(QComboBox):

    def __init__(self,**kwargs)

        self.setFixedSize(200,75)

        self.model = MyModel()
        self.setModel(self.model)

        self.setItemDelegate(MyDelegate())


if __name__ == '__main__':
    app = QApplication([])
    window = MyComboBox()
    window.show()
    app.exec()

代码显然不完整,没有实现我的想法。
出现了一些问题,例如:

如何将第一项和第二项都传递给委托?
如果模型返回列表或元组,则委托中的 options.text 将为空。

解决方法

在这种情况下,只需在默认文本上绘制右侧的文本:

TEXT_ROLE,VALUE_ROLE,STATUS_ROLE = ((Qt.UserRole + i + 1) for i in range(3))


class MyModel(QAbstractListModel):
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)

        self.data = [
            ("Item 1",12,True),("Item 2",156,("Item 3",19,False),("Item 4",126,("Item 5",100,]

    def data(self,index,role=None):
        if 0 <= index.row() < self.rowCount():
            item = self.data[index.row()]
            if role in (TEXT_ROLE,Qt.DisplayRole):
                return item[0]
            elif role == VALUE_ROLE:
                return item[1]
            elif role == STATUS_ROLE:
                return item[2]

    def rowCount(self,parent=QModelIndex()):
        if parent.isValid():
            return 0
        return len(self.data)


class MyDelegate(QStyledItemDelegate):
    RIGHT_MARGIN = 4

    def initStyleOption(self,option,index):
        super().initStyleOption(option,index)
        status = index.data(STATUS_ROLE)
        option.features |= QStyleOptionViewItem.HasDecoration
        pixmap = QPixmap(option.decorationSize)
        pixmap.fill(QColor("#22FF35" if status else "transparent"))
        option.icon = QIcon(pixmap)

    def paint(self,painter,index):
        value = index.data(VALUE_ROLE)
        super().paint(painter,index)
        painter.drawText(
            option.rect.adjusted(0,-self.RIGHT_MARGIN,0),Qt.AlignRight | Qt.AlignVCenter,str(value),)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...