Unsolved 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:
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