I want to draw outlined texts with Qt4.8, but I also want to keep the original shape and visibility of the font. Currently, the outlines hide the text characters and have them look "thinner" than the originals.
Qt draws outline of text characters (and other shapes) with QPen. QPen moves on the actual edge of a character and paints outside and inside of the edge line (See "Join Style" in QPen reference).
If you use a thicker pen, a text character looks thinner, while the total area taken by the character increases for the outline. In other words, the outline erodes into the text character.
I want to have text characters keep their original shape and visibility while having "halo effect" from outlining. I.e., I want to paint only the outside of edge lines.
What is the easiest way to implement such effect with Qt? I came up with a few ideas, but I wonder if any of them is possible.
Plan A.
Draw texts with outline, then draw the same texts without outline over the outlined ones.
Unfortunately, QTextCursor doesn't support "overdrawing" or "overtyping", which you can do with classic typewriters. There would be performance penalty, too.
Plan B.
Modify the Qt library so that it draws outline with QPen first, then fill inside with QBrush. QBrush would paint over the inside part of the outline and leaves only the outside intact.
I'm not sure if it works and I want to avoid modifying the Qt library if possible.
Plan C.
Switch the "CompositionMode" of the QPainter used for drawing text to "QPainter::CompositionMode_DestinationOver" temporarily.
To do this, I think I need to control the private and temporary QPainter created and used by Qt's text-manipulation widgets like QTextBrowser, but I don't know how it can be done.
I'm new to Qt programming and I use Qt 4.8.2 on X window.
You can see my problem by adding the following code lines (line 156-164) to /usr/lib64/qt4/examples/richtext/calendar/mainwindow.cpp, compiling and running it, and increasing the font size to 40 or larger.
QTextCharFormat format = cursor.charFormat();
format.setFontPointSize(fontSize);
QTextCharFormat boldFormat = format;
boldFormat.setFontWeight(QFont::Bold);
// Additional code lines for green outline : line 156
QPen pen;
pen.setStyle(Qt::SolidLine);
pen.setWidthF(4);
pen.setBrush(Qt::green);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
boldFormat.setTextOutline(pen);
// The end of the additional code : line 164
If you can tell me the way to go and give me the initial clues, I'll appreciate your help very much.
I've found a way, how to do such outlining for QGraphicsView
text objects. I think, you can use it for any class based on QTextDocument
(QTextEdit
, for example). I've created a class based on QGraphicsTextItem
and reimplemented its paint
function:
void paint (QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
{ QTextCharFormat format;
format.setTextOutline (QPen (Qt::white, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); // Color and width of outline
QTextCursor cursor (this->document());
cursor.select (QTextCursor::Document);
cursor.mergeCharFormat (format);
QGraphicsTextItem::paint (painter, option, widget);
format.setTextOutline (QPen (Qt::transparent));
cursor.mergeCharFormat (format);
QGraphicsTextItem::paint (painter, option, widget);
}
The only bug I've noticed for this solution - when you edit text and start selecting some letters, clipping occurs. But it's almost unnoticeable. For non-editable items I can't find any bugs.
But if you want to outline QPushButton
text (for example), then it is trivial (this problem has been discussed many times) - inside reimplemented paintEvent
create QPainterPath
, call path.addText
, then use painter.strokePath
, painter.fillPath
- strokePath
creates outline, and fillPath
fills foreground.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With