如何在Qt中使用委托更改图标

How to change icon using delegate in Qt

本文关键字:图标 Qt      更新时间:2023-10-16

我在Qtreeview中使用一个委托,它只是在文本旁边显示一个图标。

我想要能够做的是单击列表中的一个项目,并更改该项目的图标。我已经看了一些例子,但他们都使用编辑器,我不想这样做。我希望更改在单击项时自动发生。

我猜,我将不得不添加一个新的函数到我的委托类与项目的索引,我已经点击这是好的,但我如何改变图标?我是否需要用一个新图标来重新调用绘制函数?

这是我正在使用的委托:

void SeqNavDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
       const QModelIndex &index) const
{
    QStyledItemDelegate::paint(painter, option, index);
    if (index.column() == 0 && option.state & QStyle::State_Enabled)//State_MouseOver)
    {
        const QIcon icon(QLatin1String(":/SeqNavMenu/images/grey.png"));
        QRect iconRect(option.rect.right() - option.rect.height(),
                       option.rect.top(),
                       option.rect.height(),
                       option.rect.height());
        icon.paint(painter, iconRect, Qt::AlignRight);
    }
}

我只是用不同的图标路径重新实现这个函数吗?

谢谢你的帮助

处理单击

让我们从用户点击一行开始。订阅QAbstractItemView的一个信号clicked (const QModelIndex&)

根据Model/View的概念View显示模型提供的数据。要显示文本,您已经在模型中重新实现了方法data,并且模型开始提供文本。现在要显示图标。在只需要显示一个图标之前,您可以通过委托来完成。现在,您需要让您的模型提供所需的图标或一个可以选择图标的状态。
要提供图标,模型应该知道每行应该显示哪个图标。创建一个变量来保持每行的单击状态。

在连接到clicked的插槽信号中通知模型一行的点击状态发生了变化:

 {
   bool oldState = m_model->data(index, Qt::UserRole).toBool();
   m_model->setData(index, !oldState, Qt::UserRole);
 }

添加Qt:UserRolesetData的处理:

{
  if (role == Qt:UserRole)
    setClickedState(index, value.toBool());
}

不要忘记通知视图本行中的数据已经更改。在setData的末尾调用emit dataChanged(index, index)。这就是你的问题的答案如何使视图重绘。一收到您的信号,它就会保持状态。

添加Qt:UserRoledata的处理:

if (role == Qt::UserRole)
   return clickedState(index);

向委托请求单击状态并绘制所需图标

const QAbstractItemModel* model = index.model();
const bool state = model->data(index, Qt::UserRole).toBool();
const QIcon& iconToBeDrawn = state ? checkedIcon : icon;

注:您将自定义委托用于错误的目的。当你需要绘制一些不能用标准QStyledItemDelegate绘制的东西时,需要一个自定义委托。但是它可以画图标。
要绘制图标,您需要在模型中处理Qt::DecorationRole,如下所示:

virtual QVariant data (const QModelIndex& index, int role) const
{
  ...
  if (role == Qt::DecorationRole)
        return someIcon;
  ...
}

QStyledItemDelegate默认在左侧绘制一个图标。在我的评论中,我建议你如何把它画在一排的右边:委托删除QTreeView中的文本使用QStandardItemModel

与为每行提供文本的方式相同,您可以提供一个图标:

if (role == Qt::DecorationRole)
   return ifClicked(index) ? someIcon : otherIcon;

实际上,通过在QStyledItemDelegate的派生中重新实现initStyleOption()是非常简单的。我需要我的项目,代表文件夹,改变图标从关闭到打开,以响应用户的操作:

class MyDelegate : public QStyledItemDelegate
{
public:
    MyDelegate(QObject *parent = 0)
        : QStyledItemDelegate(parent)
    {
    }
protected:
    virtual void initStyleOption(QStyleOptionViewItem * option, const QModelIndex & index) const
    {
        QStyledItemDelegate::initStyleOption(option, index);
        if (QStyleOptionViewItemV4 *v4 = qstyleoption_cast<QStyleOptionViewItemV4 *>(option))
        {
            const MyModel *model(static_cast<const MyModel *>(index.model()));
            if ((option->state & QStyle::State_Open) && model->isFolderItem(index))
                v4->icon = QIcon(toFolderIconStr(true));
        }
    }
};