QStyledItemDelegate 绘图自定义小部件失败
QStyledItemDelegate drawing custom widget failed
在我的一个项目中,我使用 QTableWidget
来显示一些复杂的计算结果。为了提高 table 的可读性,我需要在单个 table 单元格内显示两个对齐的值。
稍后我想通过使用颜色或箭头等进一步自定义小部件。
为此,我从 QStyledItemDelegate
派生,并在我的 QTableWidget
实例上调用了 table ->setItemDelegate(new TwoNumbersDelegate)
。
由于某些原因,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();
}
这里有一些潜在的问题:
布局
由于小部件不可见,因此不会计算布局,因此可能会绘制错位、忽略调整大小的调用等。
为确保布局更新,在构造函数中添加
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();
}
如果您需要更多帮助,请告诉我。另外,一个警告:我还没有通过编译器 运行 这个,所以如果您仍然需要帮助,或者是否有任何小错误需要更正,请告诉我。
在我的一个项目中,我使用 QTableWidget
来显示一些复杂的计算结果。为了提高 table 的可读性,我需要在单个 table 单元格内显示两个对齐的值。
稍后我想通过使用颜色或箭头等进一步自定义小部件。
为此,我从 QStyledItemDelegate
派生,并在我的 QTableWidget
实例上调用了 table ->setItemDelegate(new TwoNumbersDelegate)
。
由于某些原因,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();
}
这里有一些潜在的问题:
布局
由于小部件不可见,因此不会计算布局,因此可能会绘制错位、忽略调整大小的调用等。
为确保布局更新,在构造函数中添加
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();
}
如果您需要更多帮助,请告诉我。另外,一个警告:我还没有通过编译器 运行 这个,所以如果您仍然需要帮助,或者是否有任何小错误需要更正,请告诉我。