Qt: Draw text with different fonts - c++

I'm using void QPainter::drawText(const QRectF &rectangle, const QString &text, const QTextOption &option = QTextOption() method to draw some text.
It lets me to align text as i wish (in the center of rectangle, for example).
Now, i need to do the same thing, except i need to draw one part of text with
some font and the other part with another.
For example, if text is "Hello world", i want "Hello" to be drawn with Arial and "World" with Times New Roman, but it should still be aligned with the center of rectangle.
What is the best way to achieve that?

you can try with this :
QPainter painter(this);
painter.setFont(QFont("Arial", 12));
painter.drawText(rect(), Qt::AlignCenter, "Hello");

Related

align right-to-left text with QPainter::drawText

I am trying to paint a right-to-left text with QPainter. It however still aligns the text to left despite the fact that it should be right-aligned. Or at least it is right-aligned when displayed in QTextEdit. That am I doing wrong? See the example:
QTextOption option;
option.setTextDirection(Qt::LayoutDirectionAuto);
painter->drawText(rect, "خامل\nخاملخامل", option); // this is just testing text, I have no idea what it means, hopefully it is not something offensive :)
This is what I get. The red arrow shows where it should be aligned.
Of course I cannot use fixed right alignment because I do not whether the text in question is left-to-right or right-to-left text. So it must work for both directions automatically depending on the text.
UPDATE: I want to emphasize that I need a solution which automatically recognizes the language/writing system of the text (left-to-right, such as English, versus right-to-left, such as Arabic) and aligns the text automatically.
you should check your text with isRightToLeft() function.
QString isRightToLeft():
Returns true if the string is read right to left.
This will help you to understand your text language.
I checked the QTextEdit source and understand it uses this function.
void MainWindow::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QRect rect = QRect(0, 0, width(), height());
QString txt = tr("خامل\nخاملخامل");
// QString txt = tr("ABCD\nABCD");
QTextOption option;
if (txt.isRightToLeft())
{
option.setTextDirection(Qt::RightToLeft);
}
else
{
option.setTextDirection(Qt::LeftToRight);
}
painter.drawText(rect, txt, option);
}

How to correctly subscribe the pixel value over the pixmap in the QGraphicsScene (as it is in OpenCV namedWindow)?

I am trying to implement the same functionality in my widget as it is in cv:: namedWindow.
The goal is to enable zooming and to make the overlay with the grid and the values of pixel's colors directly over the original pixmap. Here is the example: сv picture zoomed:
I inherited the QGraphicsView widget, added to QGraphicsScene the QGraphicsPixmapItem and reimplemented the QWheelEvent so that zooming in and out works correctly now. The problem starts with creating an overlay.
Instead of creating a pack of QGraphicsLineItems and adding them to the scene in order to make the grid, I inherit the QGraphicsRectItem and draw the whole grid on it.
void QGraphicsOverlayItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QPen pen(Qt::black);
pen.setWidthF(0.02);
painter->setPen(pen);
painter->setBrush(Qt::BrushStyle::NoBrush);
QVector<QLineF> crossLines = createCrossLines();
painter->drawLines(crossLines);
}
This works very fast. But when I try to drawText with the QPainter and set the QFont:: pointSizeF() as small as possible, it works incorrectly (symbols change their size from small to huge during zooming or even disappear at all). Nevertheless, the best result that I get this way is the following:
the QPainter's drawText() result:
QFont font(painter->font());
font.setPointSizeF(0.1);
font.setLetterSpacing(QFont::SpacingType::AbsoluteSpacing,0.01);
painter->setFont(font);
painter->drawText(432,195,"123");
The easiest way is to add to scene a lot of QGraphicsTextItems and scale them to correct size, but it is too slow.
So the question is how can I subscribe the pixel's color value in the QGraphicsScene directly over the QPixmapItem?
I finally watched through the openCV source code and found what I looked for.
The answer for me was the QTransform matrix. OpenCV developers show the image not by using the scene in the QGraphicsView, but actually painting the image directly on the viewport in the paintEvent.
The QTransform matrix is stored in the class and is passed to QPainter in the beginning of the paintEvent.
void DefaultViewPort::paintEvent(QPaintEvent *event)
{
QPainter painter(viewport());
painter.setWorldTransform(param_matrixWorld);
painter.drawImage(QRect(0,0,viewport()->width(),viewport()->height()),image2Draw,QRect(0,0,image2Draw.width(),image2Draw.height()));
If you know the ratio of the image's size to the widget's size, and you also know the scale of QTransform matrix used to paint the image, it is easy to calculate how much area does the single source pixel take on the screen:
qreal ratioX = width() / float(image2Draw.width());
qreal ratioY = height() / float(image2Draw.height());
double pixel_width = qtransform_matrixWorld.m11()*ratioX;
double pixel_height = qtransform_matrixWorld.m11()*ratioY;
If we know the pixel_height, we can just set the QFont::pixelSize like this:
QFont font = painter->font();
font.setPixelSize(pixel_height/5);
painter->setFont(font);

How do I rotate photos in QPixmap?

Marked a needle on the speedometer.
// 이미지 출력
QPixmap pix("C:\\Users\\WORK002\\Desktop\\speedmeter.png");
QPixmap pix2("C:\\Users\\WORK002\\Desktop\\pointer.png");
QPixmap pointer = pix2.scaled(300, 300);
scene.addPixmap(pix);
scene.addPixmap(pointer);
ui-> graphicsView ->setScene(&scene);
ui-> graphicsView ->show();
I want rotate and reposition.
How can i do this?
You don't have to mess with the QPixmap, you can manipulate the QGraphicsPixmapItem returned by QGraphicsScene::addPixmap:
QGraphicsPixmapItem *pixmap_item = scene.addPixmap(pix);
To set the position, you can use QGraphicsItem::setPos.
To set the rotation, first set the transform origin point with QGraphicsItem::setTransformOriginPoint,(this will set the point around which your item will be rotated) and then set the rotation with QGraphicsItem::setRotation:
pixmap_item->setPos(50, 0);
pixmap_item->setTransformOriginPoint(pixmap_item->boundingRect().center());
pixmap_item->setRotation(90);
You will have to set the correct values yourself, but this should lead you in the right way.
You can look into QPixmap::transformed()
QPixmap QPixmap::transformed(const QTransform &transform, Qt::TransformationMode mode = Qt::FastTransformation) const
The specification can be given through the QTransform object:
rotate() for rotation
translate() for reposition
may this one can help:
//Please note this method takes 2 mseg to finish for a 20x20 pixmap.
QPixmap rotatedPixmap(m_pixOriginal.size());
rotatedPixmap.fill(QColor::fromRgb(0, 0, 0, 0)); //the new pixmap must be transparent.
QPainter* p = new QPainter(&rotatedPixmap);
QSize size = m_pxOriginal.size();
p->translate(size.height()/2,size.height()/2);
p->rotate(m_iAngle);
p->translate(-size.height()/2,-size.height()/2);
p->drawPixmap(0, 0, m_pxOriginal);
p->end();
delete p;
m_pxItem->setPixmap(rotatedPixmap);
copied from:
Read this forum thread

Qt - Pop up a bubble when mouse is over QRect object

My QRect object is a fixed-sized containter of plain text, when there is too much text I would truncate the text and trail ... at the end. For example, Longlonglonglong is truncated to Longlong.... But I want to display the full-length text in a bubble when mouse pointer is over the rect.
The bubble is like the Go to Google Home:
Is this possible ?
Unfortunately QPainter can't do that for you, the drawText(..) flags don't support it. Thankfully, you can pre-elide the text for it ("eliding" is where you truncate with an elipsis) using QFontMetrics:
QFontMetrics fontM( QApplication::font() );
QRect r( 0, 0, 30, 10 );
QString text = "Longlonglonglong";
QString elidedText = fontM.elidedText( text, Qt::ElideRight, r.width() );
painter->drawText( r, Qt::AlignLeft, elidedText );
When you say "text in a bubble when mouse pointer is over", I presume you mean a tooltip - in which case implement it for the widget as normal and give the full text rather than the elided.

Qt: heightForWidth for word-wrapped text

I have a box with a varying width and a word-wrapped text. I need to set new height every time user changes box's width. The box is displayed by QPainter inside paintEvent(QPaintEvent *) function. There is several solutions, for example current (not very smart, i do this in resizeEvent(QResizeEvent *)):
unsigned new_height = 0; // the height i want to find out.
unsigned given_width = width();
QPainter painter (this); // i need painter, because i want to ask it's default font.
QLabel lab; // the widget that can do word-wrap.
lab.setText( "A word wrapped text" ); // the text
lab.setFont( painter.font() ); // set QPainter's default font.
lab.setWordWrap( true ); // enable word-wrap
new_height = lab.heightForWidth( given_width ); // tada! :)
But the code is overkill:
1) Creading QPainter is not good outside paintEvent(QPaintEvent *);
2) BUT i need QPainter to request what font is default for it to ask metrics for that font.
Should i change my code and do this operation with help of QPainter::boundingRect() inside the paintEvent(QPaintEvent *) function? But i'd like to reduce CPU consumption inside the paintEvent(QPaintEvent *) and calculate new height only when width changed, but not every time it displayed.
What is other solutions for the purpose of subject? QFontMectircs?
I think you have the right idea of using QFontMetrics. The whole idea of the class is to assist the situations like you have here. Take a look at QFontMetricsF::boundingRect()
Use your target paint rectangle as the input rect, but set the height to the max that your widget height. I'd just put something like INT_MAX in it just to be sure. :)