Say you have a custom QGraphicsItem that you would like to draw pixel by pixel, and want it to appear pixelated when that item is scaled (or the QGraphicsView it is being displayed on, or whatever). At first, you might try drawing your pixels with QPainter::drawPoint():
void MyItem::paint(
QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget)
{
...
painter->drawPoint(x, y);
...
} |
If you don’t mess with the width of the QPainter’s QPen, that won’t work. Your pixels will always be the size of 1 display pixel, no matter the item’s or the view’s scaling factor. That happens because the default pen width is 0, which guarantees points, outlines, etc. are drawn 1 pixel thick, no matter the scale. Notice the single pixel drawn on the following image, which shows a scaled 16×16 QGraphicsItem:

But guess what? Setting the pen width to 1 won’t do it either, at least not without a little extra effort. Things will start to look weird. A look into QGraphicsItem’s documentation reveals that QPainter will draw things half outside the pen’s outline, and half inside.
There are two options here:
- Set the pen width to 1 and compensate for the way QPainter draws things with its QPen; or
- Find another way to draw single pixel-sized… pixels.
The first option can be achieved like this:
QPen pen;
pen.setWidth(1);
painter->setPen(pen);
painter->drawPoint(QPointF(x + 0.5,y + 0.5)); |
But the results aren’t the best. Take a look at the following screenshot. It shows a QGraphicsView with its background QBrush set to black. There is a single 16×16 QGraphicsItem that draws a 16×16 white rectangle and a single red point at it’s bottom right corner. Notice that the red point is off the rectangle’s right border by one pixel. I’m not sure about this, but I think it might be due to floating-point error.

It seems that the most appropriate way to achieve the desired result is to draw a filled 1×1 rectangle, as in:
painter->fillRect(x, y, 1, 1, Qt::red); |
Notice that you should leave/set the pen width to 0. As you can see below, there is no error like in the previous approach:

In conclusion, you should draw single pixels by drawing filled 1×1 rectangles with a pen width of 0, instead of drawings points with a pen width of 1.
The Qt Graphics View Framework provides a rich set of resources to create applications with interactive graphics scenes that display arbitrary shapes, text and even Qt widgets. While the framework provides almost everything you need regarding interactivity, scene hierarchy management and graphics display, allowing you to concentrate on your application-specific code, some things require doing some extra work.
One of those things is setting the text alignment on QGraphicsTextItem items. Even though the class doesn’t provide a setAlignment() method, you have access to the underlying QTextDocument and QTextCursor objects that manage all the text processing and layout for the item. However, simply setting the text alignment on those objects also doesn’t get the job done.
The text in a QGraphicsTextItem is only displayed with any set alignment if the text width for the item is set. The text width determines the maximum width the text displayed by the item might have. If the text is actually larger than that width, automatic line breaks are inserted so that the text doesn’t extend past it. The text width property is also used by the framework to calculate the text position when the alignment is set to something other than left.
So how can the text width of a QGraphicsTextItem be set so that no automatic line breaks are inserted by the framework, and so that the text alignment can be set and be made to work? The answer is quite simple: just set it to the width of the item’s bounding rectangle:
item->setTextWidth(item->boundingRect().width()); |
Now, to align the text to the right, for example, you can use the item’s QTextCursor to merge it with a QTextBlockFormat with the alignment set to Qt::AlignRight:
QTextBlockFormat format;
format.setAlignment(Qt::AlignRight);
QTextCursor cursor = item->textCursor();
cursor.select(QTextCursor::Document);
cursor.mergeBlockFormat(format);
cursor.clearSelection();
item->setTextCursor(cursor); |
Notice that before setting the alignment, the entire text under the cursor i.e. the text in the QGraphicsTextItem object must be selected, and aftwerwards the selection should be cleared so that the text is not displayed as selected. Failing to select all the text might result in having only part of the text aligned in the desired way.
Here’s a screenshot of a QGraphicsView displaying a scene with a right-aligned QGraphicsTextItem:

So that was easy. Now let’s improve this.
The preceding approach is limited if you are not setting the QGraphicsTextItem’s text and alignment only once in your application. It requires you to set the text width and the text alignment every time the text content changes.
In the remainder of this post I will demonstrate how to create a subclass of QGraphicsTextItem with a setAlignment() method for setting the text alignment and that automatically updates the text width of the item whenever a change in its contents occurs. Also, this subclass will have the interesting characteristic of growing or shriking to the left when the text is right-aligned, thus anchoring it to its top-right corner, which might make sense in some applications.
Let’s start out by the class definition. We must use the Q_OBJECT macro since QGraphicsTextItem is a subclass of QObject (QGraphicsTextItem -> QGraphicsObject -> QObject) and we’re going to define a slot on the new class.
#include <QGraphicsTextItem>
class TextItem : public QGraphicsTextItem
{
Q_OBJECT
public:
enum { Type = UserType + 1 };
TextItem(QGraphicsItem* parent = 0);
TextItem(const QString& text, QGraphicsItem* parent = 0);
void setAlignment(Qt::Alignment alignment);
virtual int type() const;
public slots:
void updateGeometry(int, int, int);
void updateGeometry();
private:
void init();
}; |
The constructors are quite simple: they just initialize the base object and the alignment_ attribute and invoke the private method init() to do the rest of the initialization:
TextItem::TextItem(QGraphicsItem* parent)
: QGraphicsTextItem(parent),
alignment_(Qt::AlignLeft)
{
init();
}
TextItem::TextItem(const QString& text, QGraphicsItem* parent)
: QGraphicsTextItem(text, parent),
alignment_(Qt::AlignLeft)
{
init();
} |
The init() method is responsible for properly initializing the object. It calls updateGeometry() (which will soon be explained) to set the initial item’s text width. It also connects the QTextDocument::contentsChange() signal to the updateGeometry() slot so that the text width is recomputed after any change to the text, thus preventing automatic line breaks:
void TextItem::init()
{
updateGeometry();
connect(document(), SIGNAL(contentsChange(int, int, int)),
this, SLOT(updateGeometry(int, int, int)));
} |
Note that the updateGeometry() slot has two different signatures: one which receives no arguments and one which receives the three int arguments from the QTextDocument::contentsChange() signal. As will be shown later, the one with three int arguments just calls the one that doesn’t take any arguments. QTextDocument has another signal called contentsChanged() that carries no arguments, but unfortunatelt is cannot be used here. This will be explained after the code to updateGeometry() is presented.
The setAlignment() method contains the code for setting the text alignment that was shown at the beginning of this post. It also stores the last set alignment in the alignment_ attribute so that the object “remembers” its last alignment:
void TextItem::setAlignment(Qt::Alignment alignment)
{
alignment_ = alignment;
QTextBlockFormat format;
format.setAlignment(alignment);
QTextCursor cursor = textCursor();
cursor.select(QTextCursor::Document);
cursor.mergeBlockFormat(format);
cursor.clearSelection();
setTextCursor(cursor);
} |
The updateGeometry() method is responsible for setting the item’s text width to a size that removes any automatic line breaks that might have been inserted after a change to the item’s contents:
void TextItem::updateGeometry(int, int, int)
{
updateGeometry();
}
void TextItem::updateGeometry()
{
setTextWidth(-1);
setTextWidth(boundingRect().width());
setAlignment(alignment_);
} |
Note that the text width is first set to -1, then to the item’s bounding rectangle’s width. Setting the item’s text width to -1 “resets” the text width, changing the item’s size so that the text is displayed without any automatic line breaks that might have been inserted to the limit imposed by the previous text width. This effectively recomputes the item’s bounding rectangle, allowing its new width to be used again to set the item’s text width.
Also note that setAlignment() is called after the new text width is set. When the text width is set to -1, any alignment that might have been set before is lost, because a text width value of -1 indicates the item has no text width value. As explained before, the text width value is required by the framework to align the text to any position other than left. Since the alignment was lost, setAlignment() is called to restore the item’s last set alignment.
Remember I said that the QTextDocument::contentsChanged() signal could not be used to directly connect it to updateGeometry()? The problem is that QTextDocument::contentsChanged() is not emitted exactly like contentsChange(). The contentsChanged() signal is also emitted when the text alignment is changed, so that would start an infinite recursion (and eventually a stack overflow would happen) in updateGeometry() because of the call to setAlignment(). It is not actually necessary to have two different signatures for updateGeometry(), but since the int arguments from the QTextDocument::contentsChange() signal are ignored, having an updateGeometry() signature which takes no arguments provides a cleaner interface for TextItem.
The Type constant and the type() method are required by the framework if item type information is necessary. That is not really relevant in the present discussion, but here’s the code for type():
int TextItem::type() const
{
return Type;
} |
Obviously, Type might be set to any other value allowed by Qt.
What about making the item grow or shrink to the left when the text is right-aligned? This requires a slight modification to updateGeometry(). The trick is to save the item’s top right position before recomputing it’s text width and then displacing its position by the difference between the new top right position and the saved one:
void TextItem::updateGeometry()
{
QPointF topRightPrev = boundingRect().topRight();
setTextWidth(-1);
setTextWidth(boundingRect().width());
setAlignment(alignment_);
QPointF topRight = boundingRect().topRight();
if (alignment_ & Qt::AlignRight)
{
setPos(pos() + (topRightPrev - topRight));
}
} |
Another change is necessary for TextItem to work properly. If it is editable i.e. its text interaction flags are set to something like Qt::TextEditorInteraction, the cursor position must be saved and restored whenever the alignment is set:
void TextItem::setAlignment(Qt::Alignment alignment)
{
alignment_ = alignment;
QTextBlockFormat format;
format.setAlignment(alignment);
QTextCursor cursor = textCursor(); // save cursor position
int position = textCursor().position();
cursor.select(QTextCursor::Document);
cursor.mergeBlockFormat(format);
cursor.clearSelection();
cursor.setPosition(position); // restore cursor position
setTextCursor(cursor);
} |
This is necessary because the cursor position is moved to the end of the text when the cursor selects all the text in the item. Failing to save and restore the cursor position completely breaks the interaction when the item is editable, since setAlignment() is called on every key stroke (because QTextDocument::contentsChange() is emitted due to the change in content caused by the keystroke).
Unfortunately, I don’t know if there is a way to detect a font change on a QGraphicsTextItem. So TextItem works neatly when the text itself is changed, but if the font is changed to a larger size, automatic line breaks will be inserted by the framework because updateGeometry() will not get called in that case. Of course, you can work around that by calling updateGeometry() manually on a TextItem whenever its font is changed by the application. Another strategy would be to override setFont(), but then polymorphism will not work because setFont() is not virtual. Also, a different method like changeFont() could be added to TextItem that calls setFont() and then updateGeometry(), but that defines an interface different from QGraphicsTextItem. If you know how to make the item update itself when a font change occurs, please leave a comment!