PDA

View Full Version : How to mirror-image text?



WinchellChung
25th July 2007, 23:25
My Qt application is to allow a doctor to display tutorials to patents. It shows graphic images and blocks of text. I am currently displaying the text in a QLabel.

Now the doctors have a request. Apparently sometimes the patient will be viewing the computer monitor in a mirror. So they asked if there was a way to display the information in mirror image.

The graphics are easy to transform into mirror images. But so far the text has stumped me. Am I going to have to draw the text as a graphic object in order to transform it into a mirror image, or is there an easier way?

marcel
26th July 2007, 22:00
scale(-1, 1).This is if you use a QGraphicsView.

Regards

Gopala Krishna
27th July 2007, 08:03
scale(-1, 1).This is if you use a QGraphicsView.

Regards

Its pretty clear from his post that he is not using graphics view framework.
I thought of using the scale trick in the paintEvent method but QLabel does some pretty nifty stuff which can't be done while overriding since we don't have access to private members.
May be we can use a new style to do this and set this as style when mirrored.
I sometimes feel stylesheet might help too, but i seriously don't have clue here. :)

marcel
27th July 2007, 08:11
Its pretty clear from his post that he is not using graphics view framework.

OK, I missed that. :)

If you subclass QLabel and override it's paint event you can paint the text yourself and map it as you want, since you have access to the label's text. Just adjust the mapping of the painter before painting the text.

Or the text can be painted separately, in a pixmap, only when the label text is changed. This way you save some time.

EDIT: actually you can use scale(-1,1) on a QPainter too ( what was I thinking? ).
If you do it all in the paint event, then you might want to save/restore the painter state between mapping changes.

Regards

Gopala Krishna
27th July 2007, 08:21
actually you can use scale(-1,1) on a QPainter too ( what was I thinking? ).
If you do it all in the paint event, then you might want to save/restore the painter state between mapping changes.

Regards

Correct :) Thats what i meant actually. But i had a look at the code of QLabel::paintEvent and it handles bidirectionality, rich text and many more. Reflecting these in the overriden handler is painful.
But if he just wants the plain text to appear and is ready to sacrifice some special functionality then he can easily go for it.
But do you think , this can also be done using QStyle ? I have no idea about this

marcel
27th July 2007, 08:45
Yes, I think it can be done, but it will be more painful than overriding the paint event.

If he isn't interested in the other functionalities, then he could go ahead and override it.

Regards

WinchellChung
30th July 2007, 17:00
Thanks! I'll try over riding the paint event and see how it works.

WinchellChung
31st July 2007, 17:29
So close yet so far.
I over-rode the paintEvent thusly:



void MirrorLabel::paintEvent(QPaintEvent *)
{
QStyle *style = QWidget::style();
QPainter painter(this);
drawFrame(&painter);
int flags = QStyle::visualAlignment(layoutDirection(), QFlag(alignment()));
QRect theFrameRect = frameRect();
painter.save();
painter.scale(-1.0, 1.0);
style->drawItemText(&painter, theFrameRect, flags, palette(), isEnabled(), text(), foregroundRole());
painter.restore();
}

and alas, the text does not appear. If I change it to painter.scale(1.0, 1.0) the text draws just fine. I have a feeling that the scaling is putting the text outside of the frame rect so it is not drawing.

I tried setting the style with an explicit Qt::AlignRight, but it had no apparent effect (that is, it right justifies perfectly with a 1,1 scaling, but the text is still invisible with a -1,1 scaling).

Any ideas as to what I am doing wrong?

Michiel
31st July 2007, 17:48
Yes, scale(-1, 1) would make the y-axis a mirror, and the text would be placed to the left of it. So the solution is to either:

* translate() half-length to the left, then scale(), then translate() back (the default matrix-manipulation way, easy to understand)
* scale(), then translate() full length to the right

WinchellChung
31st July 2007, 17:58
Thanks Michiel! That did the trick.
The final code looked like this:


class MirrorLabel : public QLabel
....

bool isMirrored = true;

void MirrorLabel::paintEvent(QPaintEvent *)
{
QStyle *style = QWidget::style();
QPainter painter(this);
drawFrame(&painter);
int flags = QStyle::visualAlignment(layoutDirection(), QFlag(alignment()));
QRect theFrameRect = frameRect();
painter.save();
if (isMirrored) {
painter.scale(-1.0, 1.0);
QPointF translationOffset;
translationOffset.setX(qreal(-theFrameRect.width()));
translationOffset.setY(0.0);
painter.translate(translationOffset);
}
style->drawItemText(&painter, theFrameRect, flags, palette(), isEnabled(), text(), foregroundRole());
painter.restore();
}

Michiel
31st July 2007, 18:01
Small detail: The translate() function is overloaded so you can also use translate(qreal dx, qreal dy). Would save three lines of code. :-)

WinchellChung
31st July 2007, 18:13
thanks! Will do.