Search code examples
c++qtqtguiqt4.7

Does QGraphicsTextItem support vertical-center alignment?


Basically, I want to know why the combination of text alignment flags and setPageSize doesn't end up with text centered in the display.

The following program does nearly exactly what I want, except that the text ends up centered only horizontally.

#include <QApplication>
#include <QMainWindow>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsTextItem>
#include <QTextDocument>
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   QMainWindow *mainWindow = new QMainWindow(0, Qt::FramelessWindowHint);
   QGraphicsView view;
   view.setAlignment(Qt::AlignLeft | Qt::AlignBottom);
   view.setFrameStyle(0);
   view.setBackgroundBrush(QBrush(QColor(Qt::black)));
   mainWindow->setCentralWidget(&view);

   QGraphicsScene scene(0, 0, 640, 480);
   QGraphicsTextItem textItem;
   textItem.setTextWidth(640);
   textItem.document()->setPageSize(QSizeF(640, 480));
   textItem.document()->setDocumentMargin(0);
   textItem.document()->setDefaultTextOption(QTextOption(Qt::AlignCenter | Qt::AlignVCenter));
   textItem.setDefaultTextColor(QColor(Qt::white));
   textItem.setFont(QFont("monospace", 18, 63));
   textItem.setHtml("Center me!");
   scene.addItem(&textItem);
   textItem.setVisible(true);

   view.setScene(&scene);
   mainWindow->show();

   return a.exec();
}

I should also note that this project is constrained to Qt 4.7.1.

How do I align text both horizontally and vertically in the center of a QGraphicsView using a QGraphicsTextItem? I'm fine with a stylesheet-based solution as well.


Solution

  • No, it doesn't.

    This bug indicates that the QTextDocument (the underlying text rendering object) specifically does not attempt to vertical alignment. After looking about, most workarounds fall into two categories. For simple (i.e. single-line plain-text) applications, implement a proxy item that renders the text in its overloaded paint method as so:

    class MyProxyGraphicsItem: public QGraphicsItem {
    public:
        explicit MyProxyGraphicsItem(QString text, QRectF geometry, QGraphicsItem *parent=0) :
            QGraphicsItem(parent), text(text), geometry(geometry)
            {}
        virtual ~MyProxyGraphicsItem() {}
        QRectF boundingRect() const { return geometry; }
        void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
        {
             painter->drawText(geometry, text, Qt::AlignCenter | Qt::AlignVCenter);
        }
    private:
        QRectF geometry;
        QString text;
    }
    

    For multi-line plain-text or rich-text (HTML), use a QLabel in stead as follows:

    #include <QApplication>
    #include <QMainWindow>
    #include <QGraphicsView>
    #include <QGraphicsScene>
    #include <QGraphicsTextItem>
    #include <QLabel>
    int main(int argc, char *argv[])
    {
       QApplication a(argc, argv);
       QMainWindow *mainWindow = new QMainWindow(0, Qt::FramelessWindowHint);
       QGraphicsView view;
       view.setAlignment(Qt::AlignLeft | Qt::AlignBottom);
       view.setFrameStyle(0);
       view.setBackgroundBrush(QBrush(QColor(Qt::black)));
       mainWindow->setCentralWidget(&view);
    
       QGraphicsScene scene(0, 0, 640, 480);
       QLabel label("<div style=\"color:white;\">Center me!</div>");
       label.setWordWrap(true);
       label.setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
       label.setFont(QFont("monospace", 18, 63));
       scene.addWidget(&label)->setGeometry(QRectF(0,0,480,640));
    
       view.setScene(&scene);
       mainWindow->show();
    
       return a.exec();
    }