Qt中QStyledItemDelegate的使用(二)

延续上一篇文章。本文给出了一个QStyledItemDelegate类自定义绘制加自定义编辑框的例子。为方便读者理清思路,我已经尽量简化本文附加的代码了。此程序模拟用户给出星级评价的效果,在编辑状态下用户可以设置0~5个星星的评价,在普通状态下界面显示对应数量的金黄色星星。本文代码在VS2017和Qt5.9环境下测试通过。程序运行界面如下:

头文件。Qt也建议在自绘时同时重写sizeHint()函数给出一个合适的显示空间大小,这里为了简化就不重写了,影响不大:

class MStarDelegate : public QStyledItemDelegate
{
    Q_OBJECT

public:
    explicit MStarDelegate(QObject *parent = 0);
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
    void setEditorData(QWidget *editor, const QModelIndex &index) const override;
    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};

CPP文件。在paint(...)函数中首先生成五角星的五个顶点坐标,然后在for循环中从左到右以一定间隔绘制指定数量的星星:

MStarDelegate::MStarDelegate(QObject *parent) :
    QStyledItemDelegate(parent)
{
}

void MStarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QPointF vertex[5]; /* 五角星 Size=20,20 */
    for (int i = 0; i < 5; i++)
    {
        vertex[i].setX(+10 * sinf(i * 144.0f * (3.1415926535f / 180.0f)));
        vertex[i].setY(-10 * cosf(i * 144.0f * (3.1415926535f / 180.0f)));
    }

    int many = index.data(Qt::DisplayRole).toInt();
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor(255, 170, 0));
    QSize iconSize = option.decorationSize;
    QRect thisRect = option.rect;
    int y = thisRect.y() + thisRect.height() / 2;
    for (int i = 0; i < many; i++)
    {
        painter->save();
        painter->setRenderHint(QPainter::Antialiasing);
        qreal left = 2 + iconSize.width() * 0.5 + (2 + iconSize.width()) * i;
        painter->translate(left, y);
        painter->scale(iconSize.width() / 20.0, iconSize.height() / 20.0);
        painter->drawPolygon(vertex, 5, Qt::WindingFill);
        painter->restore();
    }
}

QWidget *MStarDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QSpinBox* cbBox = new QSpinBox(parent);
    cbBox->setRange(0, 5);
    cbBox->setSuffix(u8"");
    return cbBox;
}

void MStarDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    QSpinBox* cbWidget = dynamic_cast<QSpinBox*>(editor);
    cbWidget->setValue(index.data(Qt::DisplayRole).toInt());
}

void MStarDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    int level = dynamic_cast<QSpinBox*>(editor)->value();
    model->setData(index, level, Qt::DisplayRole);
}

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

主窗口的构造函数代码如下。其中QtTest是主窗口类,ui.tvHost是QTableView控件。

QtTest::QtTest(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    ui.tvHost->setItemDelegateForColumn(0, new MStarDelegate(ui.tvHost));
    QStandardItemModel* model = new QStandardItemModel(ui.tvHost);
    model->setHorizontalHeaderLabels({ u8"状态", u8"说明" });
    model->setVerticalHeaderLabels({ u8"设备1", u8"设备2", u8"设备3", u8"设备4" });
    model->setColumnCount(2);
    model->setRowCount(4);
    for (int i = 0; i < 4; i++)
    {
        model->setItem(i, 0, new QStandardItem(u8"3"));
        model->setItem(i, 1, new QStandardItem(u8"示例文字"));
    }
    ui.tvHost->setModel(model);
}

附:上述代码在测试时候会发现,当鼠标选中星星所在单元格后,星星的背景仍是白色,而不是系统默认的蓝色背景,仿佛没有被选择一样。这个问题需要在paint(...)函数中自己绘制单元格选中时的样式。可在paint(...)函数中添加下述代码绘制蓝色背景:

void MStarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    ...
    if (option.state & QStyle::State_Selected)
    {
        painter->fillRect(option.rect, option.palette.highlight());
    }
    ...
}

代码中option.state代表本单元格的状态。常见的有State_Enabled表示没有被禁用;State_Selected表示被选中;State_HasFocus表示拥有键盘输入焦点,系统默认是在单元格边缘绘制虚线矩形。还有很多其它的我也不太明白是什么意思。

posted @ 2023-12-03 11:37  兜尼完  阅读(812)  评论(0编辑  收藏  举报