Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Can't get QGraphicsSimpleTextItems placed where I want them in QGraphicsScene.



  • I am baffled as to how to place a text label properly in a QGraphicsScene. I can create a rect and place it where I want to. I can create lines, ellipses, etc., and place them where I want to. I can't get control over QGraphicsSimpleTextItem's position. To place correctly, I need to find the width and height of the string and transform them to scene coordinates. I can't seem to get that done! Help!

    This is basically what I want to do:
    alt text

    GrTestMain::GrTestMain(QWidget *parent)
        : QMainWindow(parent)
    {
        scene = new QGraphicsScene();
    
        // Scene with coordinate system about the center
        scene->setSceneRect(-50.0, -50.0, 100.0, 100.0);
    
        view = new QGraphicsView(this);
        view->setScene(scene);
    
        setCentralWidget(view);
    
    }
    
    void GrTestMain::updateScene()
    {
        QPen outlinePen(Qt::black);
        outlinePen.setCosmetic(true);
    
        // Box
        QGraphicsRectItem *rect = scene->addRect(-20, -20, 40, 40, outlinePen, QBrush(QColor(Qt::cyan)));
    
        // Line through the center
        scene->addLine(-20, 0, 20, 0, outlinePen);
    
        // Make a label to place to the left of the box, centered vertically at 0.0
        QGraphicsSimpleTextItem *text = new QGraphicsSimpleTextItem("A Label");
        text->setFlag(QGraphicsItem::ItemIgnoresTransformations);
        scene->addItem(text);
    
        // Get the bounding rect as a "measurement" of the text string item
        // and so we can look at them in the debugger
        QRectF br = text->sceneBoundingRect();
        QRectF brScene = text->mapRectToScene(br); // Shouldn't this be "transformed"?
    
        qreal xOff = 0.0;
        qreal yOff = 0.0;
    
        // Want to be able to position the text to the left of the box and centered vertically!
        // br and brScene are apparently in pixels (w=53 h=18)
        // How can I transform text width/height to scene coordinates so I can:
        // xOff = br->width();
        // yOff = br->height()/2.0;
        // ?
        //
    
        text->setPos(-20.0 - xOff, 0.0 - yOff);
    
        view->fitInView(scene->itemsBoundingRect(), Qt::KeepAspectRatio);
    }
    
    #include "grtestmain.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        GrTestMain w;
        w.show();
        w.updateScene();
        return a.exec();
    }
    #ifndef GRTESTMAIN_H
    #define GRTESTMAIN_H
    
    #include <QMainWindow>
    #include <QGraphicsView>
    #include <QGraphicsScene>
    #include <QGraphicsRectItem>
    #include <QGraphicsSimpleTextItem>
    #include <QGraphicsLineItem>
    
    class GrTestMain : public QMainWindow
    {
        Q_OBJECT
    
    public:
        GrTestMain(QWidget *parent = 0);
        void updateScene();
    
    private:
        QGraphicsScene *scene;
        QGraphicsView *view;
    };
    
    #endif // GRTESTMAIN_H
    
    
    


  • I don't really care for my solution, since I think it should be easier, but what I've found in order to exactly place text items where I want them in the scene is to measure them (boundingRect() or sceneBoundingRect() of the QGraphicsTextItem is always in pixels as far as I can tell), then convert the width and height to scene coordinates by using the View's viewportTransform's m11() and m22() (horizontal and vertical scale factors). If these factors have been established (like by using view's fitInView() method), it seems to work.

    Here's my updated code:

    #include "grtestmain.h"
    
    GrTestMain::GrTestMain(QWidget *parent)
        : QMainWindow(parent)
    {
        scene = new QGraphicsScene();
    
        // Scene with coordinate system about the center
        scene->setSceneRect(-50.0, -50.0, 100.0, 100.0);
    
        view = new QGraphicsView(this);
        view->setScene(scene);
    
        setCentralWidget(view);
    
    }
    
    void GrTestMain::updateScene()
    {
        view->fitInView(scene->sceneRect(), Qt::KeepAspectRatio);
    
        QPen outlinePen(Qt::black);
        outlinePen.setCosmetic(true);
    
        // Box
        scene->addRect(-20, -20, 40, 40, outlinePen, QBrush(QColor(Qt::cyan)));
    
        // Line through the center
        scene->addLine(-20, 0, 20, 0, outlinePen);
    
        // Make a label to place to the left of the box, centered vertically at 0.0
        QGraphicsSimpleTextItem *text = new QGraphicsSimpleTextItem("A Label");
        text->setFlag(QGraphicsItem::ItemIgnoresTransformations);
        scene->addItem(text);
    
        // Get the bounding rect as a "measurement" of the text string item
        // and so we can look at them in the debugger
        QRectF br = text->sceneBoundingRect();
    
        // Want to be able to position the text to the left of the box and centered vertically...
    
        // text item width + 10 pixels in scene coordinates
        qreal xOff = scaleFromPixels(view, (int)(br.width() + 10),   true); 
    
        // get the text item height in scene coordinates
        qreal yOff = scaleFromPixels(view, br.height(),  false); 
    
        text->setPos(-20 - xOff, 0.0 - yOff / 2.0);
    
    }
    
    double GrTestMain::scaleFromPixels(QGraphicsView *theView, int pixelDimension, bool isHorizontal)
    {
        double length = 0.0;
    
        if(isHorizontal)
        {
            length = pixelDimension / qAbs(theView->viewportTransform().m11());
        }
        else
        {
            length = pixelDimension / qAbs(theView->viewportTransform().m22());
        }
    
        return length;
    }
    
    #include "grtestmain.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        GrTestMain w;
    
        w.show();
        w.updateScene();
        return a.exec();
    }
    
    #ifndef GRTESTMAIN_H
    #define GRTESTMAIN_H
    
    #include <QMainWindow>
    #include <QGraphicsView>
    #include <QGraphicsScene>
    #include <QGraphicsRectItem>
    #include <QGraphicsSimpleTextItem>
    #include <QGraphicsLineItem>
    
    class GrTestMain : public QMainWindow
    {
        Q_OBJECT
    
    public:
        GrTestMain(QWidget *parent = 0);
        void updateScene();
    
    private:
        QGraphicsScene *scene;
        QGraphicsView *view;
        double scaleFromPixels(QGraphicsView *theView, int pixelDimension, bool isHorizontal);
    };
    
    #endif // GRTESTMAIN_H
    
    
    

Log in to reply