Search code examples
qtrotationqgraphicsitem

Rotate QGraphicsCustomItem into a QGraphicsScene


i'm a newbie with c++ and QT, but i've trying to learn as much as i can

i've created a simple class (called MainWindow) and with Qt Creator (Qt 5.10.0) i set a QGraphicsView into the Mainwindows.ui

inside the Mainwindow costructor i've created a QGraphicScene (linked to the QGraphicsView item) that i would like to populate with some QGraphicsRecItems.

This RecItems must to be rotated with their center point, with a given "Alpha".

I've read tons of docs, tryed lots of example, but they still rotate with the painter origin e not their center point.

Can someone give me a simple example to achive this?

Also, i would like to set the origin on the lower left point for the QGraphicView.

Thanks

i've created a custom Graphic item because i want to create a rectangle with a text inside of it.

So: this is the header called "areagrafica.h":

#ifndef AREAGRAFICA_H
#define AREAGRAFICA_H

#include <QGraphicsItem>
#include <QGraphicsTextItem>
#include <QPainter>
#include <QPen>
#include <moduledata.h>


class Grafica_PPU : public QGraphicsItem
{
  public:
    Grafica_PPU(QString ModuleName, GraphicModuleData tmpInfoGrafiche, QPen Pen, qreal tmpAlpha);


    QRectF boundingRect() const;

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget);

    private:
        GraphicModuleData infoGrafiche;
        qreal Alpha,xc,yc;

        QString Testo;

        QPen Penna;

};
#endif // AREAGRAFICA_H

and this is the "areagrafica.cpp"

#include "areagrafica.h"


Grafica_PPU::Grafica_PPU(QString ModuleName, GraphicModuleData tmpInfoGrafiche, QPen Pen, qreal tmpAlpha)
{
    infoGrafiche = tmpInfoGrafiche;
    Penna = Pen;
    Testo = ModuleName;
    Alpha = tmpAlpha;
}

QRectF Grafica_PPU::boundingRect() const
{
    return QRectF(infoGrafiche.posX,infoGrafiche.posY,infoGrafiche.Width,infoGrafiche.Height);
}

void Grafica_PPU::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
           QWidget *widget)
{
    //Penna.setWidth(5);

    painter->setPen(Penna);


    painter->setRenderHint(QPainter::Antialiasing); //Ottengo bordi senza spingoli
    painter->setRenderHint(QPainter::TextAntialiasing); //Miglioro la lettura del testo ruotato

    painter->translate(QPoint(infoGrafiche.xC,infoGrafiche.yC));
    //painter->scale(1.0, -1.0);
    painter->rotate(Alpha);

    painter->drawRect(boundingRect()); //Disegno il bordo di dimensioni scelte
    painter->drawPoint(boundingRect().center());
    painter->drawText(boundingRect(),Qt::AlignCenter,Testo); //Creo un testo avente dimensione uguale alla dimensione del modulo, con il testo allineato al centro


   // update();
}

Inside the main class i use this:

 Grafica_PPU *test,*test2;
    GraphicModuleData tmp;
    tmp.posX = 45;
    tmp.posY = -100;
    tmp.Height = 22;
    tmp.Width = 54;


    test = new Grafica_PPU("PP55103",tmp,*Grafico_Matita_Nera,0.0);
    test2 = new Grafica_PPU("PP55103",tmp,*Grafico_Matita_Nera,0.0);

    Grafico_Scena->addItem(test);
    Grafico_Scena->addItem(test2);

where "Grafico_Matita_Nera" is a Pen and "Grafico_Scena" is the scene


Solution

  • You have to establish the origin of the transformations in the center of the rectangle as shown below:

    QGraphicsRectItem *r = {...}
    r->setTransformOriginPoint(r->rect().center());
    r->setRotation(some_value)
    

    Example:

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        ui->graphicsView->setScene(new QGraphicsScene(-100, -100, 200, 200));
    
        QGraphicsRectItem *r = ui->graphicsView->scene()->addRect(0, 0, 60, 60, QPen(Qt::blue), QBrush(Qt::red));
        r->setTransformOriginPoint(r->rect().center());
    
        QVariantAnimation *animation = new QVariantAnimation(this);
        connect(animation, &QVariantAnimation::valueChanged, [r](QVariant value){
            r->setRotation(value.toReal());
        });
        animation->setStartValue(0);
        animation->setEndValue(360);
        animation->setDuration(1000);
        animation->setLoopCount(-1);
        animation->start();
    }
    

    The complete example can be found in the following link.


    You do not have to rotate the QPainter, if you do not have to rotate the item for it you must use the center of boundingRect()

    Grafica_PPU::Grafica_PPU(const QString &ModuleName, GraphicModuleData tmpInfoGrafiche, QPen Pen, qreal tmpAlpha)
    {
        infoGrafiche = tmpInfoGrafiche;
        Penna = Pen;
        Testo = ModuleName;
        Alpha = tmpAlpha;
        setTransformOriginPoint(boundingRect().center());
        setRotation(Alpha);
    }
    
    QRectF Grafica_PPU::boundingRect() const
    {
        return QRectF(infoGrafiche.XC, infoGrafiche.YC,infoGrafiche.Width,infoGrafiche.Height);
    }
    
    void Grafica_PPU::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
               QWidget *)
    {
        painter->setPen(Penna);
        painter->setRenderHint(QPainter::Antialiasing); //Ottengo bordi senza spingoli
        painter->setRenderHint(QPainter::TextAntialiasing); //Miglioro la lettura del testo ruotato
        painter->drawRect(boundingRect()); //Disegno il bordo di dimensioni scelte
        painter->drawPoint(boundingRect().center());
        painter->drawText(boundingRect(),Qt::AlignCenter,Testo); //Creo un testo avente dimensione uguale alla dimensione del modulo, con il testo allineato al centro
    
    }
    

    Example:

    GraphicModuleData tmp{0, 0, 40, 40};
    Grafica_PPU *item = new Grafica_PPU("test", tmp, QPen(Qt::red), 100);
    
    GraphicModuleData tmp2{-50, 50, 60, 40};
    Grafica_PPU *item2 = new Grafica_PPU("test", tmp2, QPen(Qt::red), 90);
    
    ui->graphicsView->scene()->addItem(item);
    ui->graphicsView->scene()->addItem(item2);
    

    Output:

    enter image description here

    Plus:

    comment: is it possible to rotate the rectangle, but leave out the text?

    void Grafica_PPU::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
               QWidget *)
    {
        painter->setPen(Penna);
        painter->setRenderHint(QPainter::Antialiasing); //Ottengo bordi senza spingoli
        painter->setRenderHint(QPainter::TextAntialiasing); //Miglioro la lettura del testo ruotato
        painter->drawRect(boundingRect()); //Disegno il bordo di dimensioni scelte
        painter->translate(boundingRect().center());
        painter->rotate(-rotation());
        painter->translate(-boundingRect().center());
        painter->drawText(boundingRect(),Qt::AlignCenter,Testo); //Creo un testo avente dimensione uguale alla dimensione del modulo, con il testo allineato al centro
    
    }
    

    enter image description here