I have a custom class derived from the QGraphicsRectItem. All I need is to draw a frame over this item and some block on the bottom right. The width of the frame and size of the block are fixed, but the item can be scaled using QGraphicsItem::setTransform function. The problem is that when I try to map the bounding rect of the item to the view, I get an inaccurate output rect and this rect gets out of the bounds of the item. Please, look at the code below:
#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);
}
The solution is to set the null pen for the item, and also to adjust the output rect when drawing the frame. So, finally, my code looks like this:
#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);
}