c++ - 通过 QTreeView 中的 QAbstractItemModel 实现用户可编辑复选框的自定义

标签 c++ qt

我有 QTreeView 和 QAbstractItemModel。一些特定的列应该有用户定义的复选框。我通过覆盖 QAbstractItemModel::data() 函数并发送 Qt::CheckStateRole 角色的检查状态来完成此操作,如代码所示。

我正在获取复选框,并且能够成功选中和取消选中它们。 但要求是自定义其中一些复选框。基本上我需要通过任何方法将一些复选框与其他复选框区分开来,例如:用蓝色填充复选框,将复选框的边界设为蓝色或任何其他方法。但是我不确定如何更改复选框样式,因为我正在通过模型创建复选框。

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();
    if (role == Qt::CheckStateRole && index.column() == COLUMN_WITH_CHECKBOX)
    {
        //return Qt::Checked or Qt::Unchecked here
    }
    //...
}

bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid())
        return false;
    if (role == Qt::CheckStateRole)
    {
        if ((Qt::CheckState)value.toInt() == Qt::Checked)
        {
            //user has checked item
            return true;
        }
        else
        {
            //user has unchecked item
            return true;
        }
    }
    return false;
}

最佳答案

首先你需要实现你自己的 ItemDelegate

class CheckedDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    CheckedDelegate(QObject *parent = nullptr);
    ~CheckedDelegate();

    QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void setEditorData(QWidget *editor, const QModelIndex& index) const;
    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const;
    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex& index) const;
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const;

};

在此委托(delegate)中,您必须实现自定义编辑器和自定义项目绘制。创建自定义编辑器:

QWidget *CheckedDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QCheckBox *chBox = new QCheckBox(parent);
    //customize editor checkbox
    QString strQss = "QCheckBox::indicator:checked { image: url(:/icons/pic/checkboxChecked.png); } ";
    strQss.append("QCheckBox::indicator:unchecked { image: url(:/icons/pic/checkboxUnchecked.png); }");
    chBox->setStyleSheet(strQss);
    return chBox;
}

void CheckedDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    QCheckBox *chBox = dynamic_cast<QCheckBox*> (editor);
    if (index.data(Qt::CheckStateRole).toInt() == Qt::Checked)
    {
        chBox->setChecked(true);
    }
    else
    {
        chBox->setChecked(false);
    }
}

void CheckedDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    QCheckBox *chBox = dynamic_cast<QCheckBox*> (editor);
    model->setData(index, chBox->isChecked() ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
}

void CheckedDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    editor->setGeometry(GetCheckboxRect(option));
}

要计算复选框的几何形状,请使用

QRect GetCheckboxRect(const QStyleOptionViewItem &option)
{
    QStyleOptionButton opt_button;
    opt_button.QStyleOption::operator=(option);
    QRect sz = QApplication::style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt_button);
    QRect r = option.rect;
    // center 'sz' within 'r'
    double dx = (r.width() - sz.width()) / 2;
    double dy = (r.height()- sz.height()) / 2;
    r.setTopLeft(r.topLeft() + QPoint(qRound(dx),qRound(dy)));
    r.setWidth(sz.width());
    r.setHeight(sz.height());

    return r;
}

然后实现自定义绘画。在这个例子中,我使用像素图来自定义复选框,所以我也只绘制像素图。

void CheckedDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItem opt = option;
    QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter);
    if (index.data(Qt::CheckStateRole).toInt() == Qt::Checked) {
        QApplication::style()->drawItemPixmap(painter, GetCheckboxRect(option), Qt::AlignLeft | Qt::AlignVCenter, QPixmap(":/icons/pic/checkboxChecked.png"));
    } else {
        QApplication::style()->drawItemPixmap(painter, GetCheckboxRect(option), Qt::AlignLeft | Qt::AlignVCenter, QPixmap(":/icons/pic/checkboxUnchecked.png"));
    }
}

并设置你的委托(delegate)(在我的示例中我有 TableTiew 而不是 TreeView)

CheckedDelegate *chDel = new CheckedDelegate(this);
ui->tableView->setItemDelegateForColumn(1, chDel);

关于c++ - 通过 QTreeView 中的 QAbstractItemModel 实现用户可编辑复选框的自定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57068569/

相关文章:

C++:如何在 UI 线程和 worker std::thread 之间使用 std::condition_variable

c++ - 不打印带有 int 的字符串构造函数

c++ - 当编译时参数未知时创建 execv 参数数组

C++ 声明一个函数而不是调用一个复杂的构造函数

mysql - 连接Mysql和qt?

c++ - 删除最后一行时,QTableWidget 的单元格小部件无法正确显示

Qt 变更和 LGPL

c++ - "Drawing"在QT中使用完全透明的笔

c++ - Qt - 如何在 QGraphicsPixmapItem 中显示 gif(动画)图像

Python PyQt 装饰方法触发时出错