在不缩放的情况下绘制 QGraphicsItem
Painting over QGraphicsItem without scaling
我有一个从 QGraphicsRectItem 派生的自定义 class。我所需要的只是在这个项目上画一个框架,并在右下角画一些方块。框架的宽度和块的大小是固定的,但项目可以使用 QGraphicsItem::setTransform 函数进行缩放。问题是,当我尝试将项目的边界矩形映射到视图时,我得到一个不准确的输出矩形,并且该矩形超出了项目的边界。请看下面的代码:
#ifndef TEST_H
#define TEST_H
#include "ui_Test.h"
#include <QGraphicsRectItem>
class MyItem : public QGraphicsRectItem
{
public:
explicit MyItem(QGraphicsItem *parent = Q_NULLPTR);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR) Q_DECL_OVERRIDE;
private:
void drawVolumeIndicator(QPainter *painter);
};
class Test : public QMainWindow, private Ui::TestClass
{
Q_OBJECT
public:
explicit Test(QWidget *parent = Q_NULLPTR);
};
#endif // TEST_H
#include "Test.h"
#include <QGraphicsScene>
#include <QGraphicsView>
MyItem::MyItem(QGraphicsItem *parent)
: QGraphicsRectItem(parent)
{}
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QGraphicsRectItem::paint(painter, option, widget);
drawVolumeIndicator(painter);
}
void MyItem::drawVolumeIndicator(QPainter *painter)
{
static const auto blockColor = QColor(QStringLiteral("#0097a7"));
static const auto frameColor = QColor(QStringLiteral("#660097a7"));
static Q_CONSTEXPR auto blockSize = QSize(12, 40);
static Q_CONSTEXPR auto blockMargin = 2;
static Q_CONSTEXPR auto frameWidth = 4;
const auto outputRect = painter->transform().mapRect(boundingRect());
painter->save();
painter->resetTransform();
// draw block
const auto x = outputRect.right() - frameWidth - blockMargin - blockSize.width();
const auto y = outputRect.bottom() - frameWidth - blockMargin - blockSize.height();
painter->fillRect(QRect(QPoint(x, y), blockSize), blockColor);
// draw frame
painter->setBrush(Qt::transparent);
painter->setPen(QPen(frameColor, frameWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
painter->drawRect(outputRect);
painter->restore();
}
Test::Test(QWidget *parent)
: QMainWindow(parent)
{
setupUi(this);
resize(200, 400);
auto item = new MyItem;
item->setBrush(Qt::lightGray);
item->setPen(QPen(Qt::transparent));
item->setRect(0, 0, 100, 100);
// set scale for the item
QTransform transform;
transform.scale(1, 3);
item->setTransform(transform);
auto scene = new QGraphicsScene;
scene->addItem(item);
auto view = new QGraphicsView;
view->setScene(scene);
QMainWindow::setCentralWidget(view);
}
这是没有缩放的样子:
这是缩放后的样子:
解决方法是给item设置null pen,画框的时候也调整一下output rect。所以,最后,我的代码如下所示:
#include "Test.h"
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
MyItem::MyItem(QGraphicsItem *parent)
: QGraphicsRectItem(parent)
{}
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QGraphicsRectItem::paint(painter, option, widget);
drawVolumeIndicator(painter);
}
void MyItem::drawVolumeIndicator(QPainter *painter)
{
static const auto blockColor = QColor(QStringLiteral("#0097a7"));
static const auto frameColor = QColor(QStringLiteral("#660097a7"));
static Q_CONSTEXPR auto blockSize = QSize(12, 40);
static Q_CONSTEXPR auto blockMargin = 2;
static Q_CONSTEXPR auto frameWidth = 4;
static Q_CONSTEXPR auto halfFrameWidth = frameWidth / 2;
const auto outputRect = painter->transform().mapRect(boundingRect());
painter->save();
painter->resetTransform();
// draw block
const auto x = outputRect.right() - frameWidth - blockMargin - blockSize.width();
const auto y = outputRect.bottom() - frameWidth - blockMargin - blockSize.height();
painter->fillRect(QRect(QPoint(x, y), blockSize), blockColor);
// draw frame
painter->setBrush(Qt::transparent);
painter->setPen(QPen(frameColor, frameWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
painter->drawRect(outputRect.adjusted(halfFrameWidth, halfFrameWidth, -halfFrameWidth, -halfFrameWidth));
painter->restore();
}
Test::Test(QWidget *parent)
: QMainWindow(parent)
{
setupUi(this);
resize(200, 400);
auto item = new MyItem;
item->setBrush(Qt::lightGray);
item->setPen(Qt::NoPen);
item->setRect(0, 0, 100, 100);
// set scale for the item
QTransform transform;
transform.scale(1, 3);
item->setTransform(transform);
auto scene = new QGraphicsScene;
scene->addItem(item);
auto view = new QGraphicsView;
view->setScene(scene);
QMainWindow::setCentralWidget(view);
}
我有一个从 QGraphicsRectItem 派生的自定义 class。我所需要的只是在这个项目上画一个框架,并在右下角画一些方块。框架的宽度和块的大小是固定的,但项目可以使用 QGraphicsItem::setTransform 函数进行缩放。问题是,当我尝试将项目的边界矩形映射到视图时,我得到一个不准确的输出矩形,并且该矩形超出了项目的边界。请看下面的代码:
#ifndef TEST_H
#define TEST_H
#include "ui_Test.h"
#include <QGraphicsRectItem>
class MyItem : public QGraphicsRectItem
{
public:
explicit MyItem(QGraphicsItem *parent = Q_NULLPTR);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR) Q_DECL_OVERRIDE;
private:
void drawVolumeIndicator(QPainter *painter);
};
class Test : public QMainWindow, private Ui::TestClass
{
Q_OBJECT
public:
explicit Test(QWidget *parent = Q_NULLPTR);
};
#endif // TEST_H
#include "Test.h"
#include <QGraphicsScene>
#include <QGraphicsView>
MyItem::MyItem(QGraphicsItem *parent)
: QGraphicsRectItem(parent)
{}
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QGraphicsRectItem::paint(painter, option, widget);
drawVolumeIndicator(painter);
}
void MyItem::drawVolumeIndicator(QPainter *painter)
{
static const auto blockColor = QColor(QStringLiteral("#0097a7"));
static const auto frameColor = QColor(QStringLiteral("#660097a7"));
static Q_CONSTEXPR auto blockSize = QSize(12, 40);
static Q_CONSTEXPR auto blockMargin = 2;
static Q_CONSTEXPR auto frameWidth = 4;
const auto outputRect = painter->transform().mapRect(boundingRect());
painter->save();
painter->resetTransform();
// draw block
const auto x = outputRect.right() - frameWidth - blockMargin - blockSize.width();
const auto y = outputRect.bottom() - frameWidth - blockMargin - blockSize.height();
painter->fillRect(QRect(QPoint(x, y), blockSize), blockColor);
// draw frame
painter->setBrush(Qt::transparent);
painter->setPen(QPen(frameColor, frameWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
painter->drawRect(outputRect);
painter->restore();
}
Test::Test(QWidget *parent)
: QMainWindow(parent)
{
setupUi(this);
resize(200, 400);
auto item = new MyItem;
item->setBrush(Qt::lightGray);
item->setPen(QPen(Qt::transparent));
item->setRect(0, 0, 100, 100);
// set scale for the item
QTransform transform;
transform.scale(1, 3);
item->setTransform(transform);
auto scene = new QGraphicsScene;
scene->addItem(item);
auto view = new QGraphicsView;
view->setScene(scene);
QMainWindow::setCentralWidget(view);
}
这是没有缩放的样子:
这是缩放后的样子:
解决方法是给item设置null pen,画框的时候也调整一下output rect。所以,最后,我的代码如下所示:
#include "Test.h"
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
MyItem::MyItem(QGraphicsItem *parent)
: QGraphicsRectItem(parent)
{}
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QGraphicsRectItem::paint(painter, option, widget);
drawVolumeIndicator(painter);
}
void MyItem::drawVolumeIndicator(QPainter *painter)
{
static const auto blockColor = QColor(QStringLiteral("#0097a7"));
static const auto frameColor = QColor(QStringLiteral("#660097a7"));
static Q_CONSTEXPR auto blockSize = QSize(12, 40);
static Q_CONSTEXPR auto blockMargin = 2;
static Q_CONSTEXPR auto frameWidth = 4;
static Q_CONSTEXPR auto halfFrameWidth = frameWidth / 2;
const auto outputRect = painter->transform().mapRect(boundingRect());
painter->save();
painter->resetTransform();
// draw block
const auto x = outputRect.right() - frameWidth - blockMargin - blockSize.width();
const auto y = outputRect.bottom() - frameWidth - blockMargin - blockSize.height();
painter->fillRect(QRect(QPoint(x, y), blockSize), blockColor);
// draw frame
painter->setBrush(Qt::transparent);
painter->setPen(QPen(frameColor, frameWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
painter->drawRect(outputRect.adjusted(halfFrameWidth, halfFrameWidth, -halfFrameWidth, -halfFrameWidth));
painter->restore();
}
Test::Test(QWidget *parent)
: QMainWindow(parent)
{
setupUi(this);
resize(200, 400);
auto item = new MyItem;
item->setBrush(Qt::lightGray);
item->setPen(Qt::NoPen);
item->setRect(0, 0, 100, 100);
// set scale for the item
QTransform transform;
transform.scale(1, 3);
item->setTransform(transform);
auto scene = new QGraphicsScene;
scene->addItem(item);
auto view = new QGraphicsView;
view->setScene(scene);
QMainWindow::setCentralWidget(view);
}