Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt outlined text without thinning font

Tags:

text

qt

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.

like image 770
Masaki Nishikawa Avatar asked Dec 20 '12 07:12

Masaki Nishikawa


1 Answers

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.

like image 145
Tapa Avatar answered Oct 16 '22 15:10

Tapa