Dimensions of text in QGraphicsItem
-
Hi!
I'm playing with the DiagramScene example included with Qt in order to better understand how the QGraphicsView - QGraphicsScene - QGraphicsItem works.
Everything is pretty clear; I have modified a copy of the example to work freely. The problem comes when I try to write a single text inside one of the graphicitems that may be inserted in the graphisscene.
I want to draw a box divided into 3 horizontal areas. The upper one will contain a series of t_input small squares whose side measures "d". The lower one will include another series of t_output squares whose side measures again d. The height of the first and last stripe is always 2 * d. The height of the central stripe is d + the height of the text to write.
In the central stripe I just want to draw a single line of centered text.
Therefore, I modified the constructor as follows (please, look specially at the "Step" part of the switch sentence):
DiagramItem:: DiagramItem (DiagramType diagramType, QMenu* contextMenu, QGraphicsItem* parent) : QGraphicsPolygonItem(parent), context_menu_(contextMenu), diagram_type_(diagramType) { { QString task_name; QFont font("Monospace", 16); font.setStyleHint(QFont::TypeWriter); QFontMetrics fm(font); switch (diagram_type_) { case Conditional: polygon_ << QPointF(-100, 0) << QPointF(0, 100) << QPointF(100, 0) << QPointF(0, -100) << QPointF(-100, 0); break; case Step: qreal w1, w2, w3, width, h_top_bottom, h_text, height, d, half_width, half_height; int t_inputs, t_outputs; t_inputs = 4; t_outputs= 3; task_name = "PRETTY_TASK"; d = 20; // Compute the width of the several elements making the step. w1 = 2 * t_inputs * d; // The input bullets. w2 = fm.boundingRect(task_name).width(); // The text box. w3 = 2 * t_outputs * d; // The output bullets. // // The actual width of the step is determined by the width of // its widest element. // width = w1; if (w2 > width) width = w2; if (w3 > width) width = w3; // Now, compute the height. h_top_bottom = 4 * d; h_text = fm.boundingRect(task_name).height() + d; height = h_top_bottom + h_text; qDebug() << "Anchura y altura de la caja: " << width << height; qDebug() << "Anchura y altura del texto: " << w2 << h_text; // Convenient auxiliary values. half_width = width / 2.0; half_height = height / 2.0; // Define the outer frame. polygon_ << QPointF(-half_width, -half_height) << QPointF( half_width, -half_height) << QPointF( half_width, half_height) << QPointF(-half_width, half_height) << QPointF(-half_width, -half_height); break; case Io: polygon_ << QPointF(-120, -80) << QPointF(-70, 80) << QPointF(120, 80) << QPointF(70, -80) << QPointF(-120, -80); break; default: return; } setPolygon(polygon_); setFlag(QGraphicsItem::ItemIsMovable, true); setFlag(QGraphicsItem::ItemIsSelectable, true); setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); } }
and this is the paint method:
void DiagramItem:: paint ( QPainter* painter, const QStyleOptionGraphicsItem* option , QWidget* widget) { { QGraphicsPolygonItem::paint(painter, option, widget); if (diagram_type_== Step) { QString task_name; QFont font("Monospace", 16); font.setStyleHint(QFont::TypeWriter); QFontMetrics fm(font); // Draw the internal elements of the step item. qreal w1, w2, w3, width, height, h_top_bottom, h_text, d, half_width, half_height; int t_inputs, t_outputs; t_inputs = 4; t_outputs = 3; task_name = "PRETTY_TASK"; d = 20; // Compute the width of the several elements making the step. w1 = 2 * t_inputs * d; // The input bullets. w2 = fm.boundingRect(task_name).width(); // The text box. w3 = 2 * t_outputs * d; // The output bullets. // // The actual width of the step is determined by the width of // its widest element. // width = w1; if (w2 > width) width = w2; if (w3 > width) width = w3; // Now, compute the height. h_top_bottom = 4 * d; h_text = fm.boundingRect(task_name).height() + d; height = h_top_bottom + h_text; // Convenient auxilary values. half_width = width / 2.0; half_height = height / 2.0; // The two lines dividing the step. QPen pen(Qt::black, 1, Qt::SolidLine); painter->setPen(pen); painter->drawLine(-half_width, -d, half_width, -d); painter->drawLine(-half_width, d, half_width, d); // The upper & lower row of circles (inputs). qreal x, y; x = -half_width + ((width - w1) / 2) - d; y = -half_height + d; for (int i = 0; i < t_inputs; i++) { x += (2 * d); QBrush brush(Qt::red); painter->setBrush(brush); painter->drawEllipse(QPointF(x,y), d/2, d/2); } x = -half_width + ((width - w3) / 2) - d; y = half_height - d; for (int i = 0; i < t_outputs; i++) { x += (2 * d); QBrush brush(Qt::red); painter->setBrush(brush); painter->drawEllipse(QPointF(x,y), d/2, d/2); } // The task name. x = - (fm.boundingRect(task_name).width()/2); y = (fm.boundingRect(task_name).height()/2); painter->setPen(Qt::red); painter->drawText(x, y, task_name); } } }
when the item is inserted in the scene, everything is drawn correctly but the text. The dimensions obtained for the text seem not to be correct, that is, using a different set of units of that of my graphicsview / graphicscene.
I found somewhere in Google that passing the graphicsview to the constructor of the qfontmetrics object would make this object to use the right transform, but I can't do this, since the constructor of the qfontmetrics object accepts no qgraphicsview as a parameter, but a qpaintdevice.
How can I solve this?
Note that I do not want to use a QGraphicsTextItem to display the text to avoid having to group items and then deal with how events are processed.
By the way, this image shows what I'm getting now. Look at the text: it is not centered.
Thanks!!
-
@bleriot13 said in Dimensions of text in QGraphicsItem:
painter->drawText(x, y, task_name);
use: drawText(const QRect &rectangle, int flags, const QString &text, QRect *boundingRect = nullptr)
and set the alignments you want. -
@mpergand said in Dimensions of text in QGraphicsItem:
use: drawText(const QRect &rectangle, int flags, const QString &text, QRect *boundingRect = nullptr)
and set the alignments you want.Hi, thanks for your suggestion.
However, I need the outer box to be adapted to the maximum of three widths: that of the upper and lower row of small circles and the length of the text. This is the reason why I need to compute (correctly) the dimensions of the string to write. Imagine that the number of upper and lower bullets is one in both cases; then, the box would be too narrow to hold event the shortest word.
So this is why I computed the width (and also the height, of course) of the text to draw using the font metrics object. However, the results seems to be given in a coordinate system which is not the same than the one used by the rectangle and the circles - or at least this is what I think: the width of the box you see in the picture above is 160, while the width of the text (as reported by the font metrics object) is 143. Since the text is clearly much narrower than the box and 160 and 143 are pretty close lengths, I assume that these figures are given in different coordinate systems.
So I assume that, somehow, I should transform the measurements given by the font metrics object to make these compatible with the item's coordinate system.
Any ideas?
THANKS!
-
Hi.
I found the problem.
Even I was creating a font and the corresponding font metrics object... I never set the painter's font to be this one. So, obviously, the painter was drawing my text using some font, and I was measuring the text using a different one. Of course, the width and height of the text never matched the invalid measurements I made.
Just setting the font in the paint method does the trick.
if (diagram_type_== Step) { QString task_name; QFont font("Monospace", 16); painter->setFont(font) // <---- This does the trick. Forgot to do it in my former example!!! font.setStyleHint(QFont::TypeWriter); QFontMetrics fm(font);