问题
In one of my projects I'm using a QTableWidget
in order to display some complex computational results. In order to increase the readability of the table I'm in need to display two aligned values inside of a single table cell.
Later on I want to customize the widget even more by using colors or arrows etc..
For this I derived from QStyledItemDelegate
and I called table ->setItemDelegate(new TwoNumbersDelegate)
on my QTableWidget
instance.
For some reasons the QFrame
is never display. I really tried everything. Strangely, a call to drawLine
gives some result, but only in the left cell on the top.
My idea is, that calling mFrame->render(...)
is not the correct way to do it, but what is the correct way?
My include file is:
#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;
};
My cpp
-File is:
#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:
A few potential issues here:
Layout
Since the widget is invisible, the layout isn't being calculated, so things might be drawn out of place, calls to resize ignored, etc.
To ensure the layout is updated, in the constructor, add
mFrame->setAttribute(Qt::WA_DontShowOnScreen, true);
mFrame->show();
This makes the widget behave as if it is visible (which we want), but doesnt draw anything to the screen directly.
Paint location
Drawing with a delegate is clipped to the cell, so if you draw in the wrong place, you won't see anything at all.
The bounds of the cell are given by options.rect
, and these coordinates are in terms of the qtableview. So your drawline command only draws in the top-left cell.
This clipping also means you don't need to worry about what region of the widget to render, just translate the painter to use the cell's coordinates, and paint the whole widget.
painter->save();
painter->translate(option.rect.topLeft());
mFrame->render(painter, QPoint(), QRegion(), QWidget::DrawChildren );
painter->restore();
All together, here is an updated .cpp file:
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();
}
Let me know if you need any more help. Also, a warning: I haven't so much as run this through a compiler, so let me know if you still need help, or if there are any little errors to correct.
来源:https://stackoverflow.com/questions/43112644/qstyleditemdelegate-drawing-custom-widget-failed