QStyledItemDelegate绘制自定义窗口小部件失败

时间:2017-03-30 08:40:38

标签: c++ qt qwidget qitemdelegate qstyleditemdelegate

在我的一个项目中,我使用QTableWidget来显示一些复杂的计算结果。为了增加表的可读性,我需要在单个表格单元内显示两个对齐的值。

稍后我想通过使用颜色或箭头等来更自定义小部件。

为此,我从QStyledItemDelegate派生,并在table ->setItemDelegate(new TwoNumbersDelegate)个实例上调用了QTableWidget

由于某些原因,永远不会显示QFrame。我真的尝试了一切。奇怪的是,对drawLine的调用给出了一些结果,但仅限于顶部的左侧单元格。

我的想法是,调用mFrame->render(...)不是正确的方法,但正确的方法是什么?

我的包含文件是:

#pragma once

#include <QStyledItemDelegate>
class QLabel;

    class TwoNumbersDelegate : public QStyledItemDelegate {
    public:
        TwoNumbersDelegate(QObject* parent = nullptr);

        virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;

        virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;

    private:
        QLabel* mLeft;
        QLabel* mRight;
        QFrame* mFrame;
    };

我的cpp - 文件是:

#include "TwoNumbersDelegate.h"
#include <QLabel>
#include <QPainter>
#include <QHBoxLayout>

TwoNumbersDelegate::TwoNumbersDelegate(QObject* parent /*= nullptr*/) : QStyledItemDelegate(parent)
{
    mLeft = new QLabel("%1");
    mRight = new QLabel("%2");
    mFrame = new QFrame;
    mFrame->setLayout(new QHBoxLayout);
    mFrame->layout()->addWidget(mLeft);
    mFrame->layout()->addWidget(mRight);
}

void TwoNumbersDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    auto data=index.data(Qt::EditRole);
    auto list=data.toList();
    if (list.size() != 2) {
        QStyledItemDelegate::paint(painter, option, index);
    }
    auto leftValue=list.at(0).toDouble();
    auto rightValue=list.at(1).toDouble();
    mLeft->setText(QString("%1").arg(leftValue));
    mRight->setText(QString("%2").arg(rightValue));
    mLeft->render(painter, QPoint(), option.rect);
    painter->drawLine(4, 4, 7, 7); // Draws Line, but not in every cell of my table?
}

QSize TwoNumbersDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    return mFrame->minimumSizeHint();
}

1 个答案:

答案 0 :(得分:4)

这里有一些潜在的问题:

布局

由于窗口小部件是不可见的,因此不会计算布局,因此可能会出现不合适的事情,忽略调整大小的调用等等。

为确保更新布局,请在构造函数中添加

mFrame->setAttribute(Qt::WA_DontShowOnScreen, true);
mFrame->show();

这使得窗口小部件的行为就像它是可见的(我们想要的),但不会直接在屏幕上绘制任何东西。

绘制位置

使用委托的绘图被剪切到单元格,因此如果您在错误的位置绘制,则根本不会看到任何内容。 单元格的边界由options.rect给出,这些坐标是qtableview。因此,您的drawline命令仅绘制在左上角的单元格中。

此裁剪还意味着您无需担心渲染窗口小部件的哪个区域,只需将画家翻译为使用单元格的坐标,然后绘制整个窗口小部件。

painter->save();
painter->translate(option.rect.topLeft());
mFrame->render(painter, QPoint(), QRegion(), QWidget::DrawChildren );
painter->restore();

总之,这是一个更新的.cpp文件:

TwoNumbersDelegate::TwoNumbersDelegate(QObject* parent /*= nullptr*/) : QStyledItemDelegate(parent)
{
    mLeft = new QLabel("%1");
    mRight = new QLabel("%2");
    mFrame = new QFrame;
    mFrame->setLayout(new QHBoxLayout);
    mFrame->layout()->addWidget(mLeft);
// you could add a spacer here maybe
    mFrame->layout()->addWidget(mRight);

    mFrame->setAttribute(Qt::WA_DontShowOnScreen, true);
    mFrame->show();
}

void TwoNumbersDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    auto data=index.data(Qt::EditRole);
    auto list=data.toList();
    if (list.size() != 2) {
        QStyledItemDelegate::paint(painter, option, index);
    }

    mLeft->setText(list.at(0).toString());
    mRight->setText(list.at(1).toString());
    mFrame->resize(opt.rect.size());

    // if there are still layout problems maybe try adding:
    // mFrame->layout()->invalidate();
    // mFrame->layout()->activate();

    painter->save();
    painter->translate(option.rect.topLeft());
    mFrame->render(painter, QPoint(), QRegion(), QWidget::DrawChildren );
    // painter->drawLine(4, 4, 7, 7); // Draws Line in every cell now
    painter->restore();
}

QSize TwoNumbersDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    return mFrame->minimumSizeHint();
}

如果您需要更多帮助,请与我们联系。另外,警告:我没有通过编译器运行它,所以如果你仍然需要帮助,或者如果有任何小错误要纠正,请告诉我。