Does QGraphicsTextItem support vertical-center alignment? - c++

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.

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();
}

Related

Center QLabel derived widget inside a QScrollArea

How should I center my QLabel derived widget papyrus inside a QScrollArea?
QScrollArea *scroll_area = new QScrollArea(this);
scroll_area->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
scroll_area->setWidgetResizable(true);
scroll_area->setBackgroundRole(QPalette::Dark);
papyrus = new Papyrus(scroll_area);
scroll_area->setWidget(papyrus);
setCentralWidget(scroll_area);
resize(800, 600);
This is the snippet I am using but my widget sticks to the top left...
(main.cpp example):
#include <QApplication>
#include "MainWindow.h"
#include <QScrollArea>
#include <QLabel>
#include <QHBoxLayout>
int main(int argc, char** argv)
{
QApplication a(argc, argv);
QLabel label("Label");
label.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
QScrollArea area;
area.setWidgetResizable(true);
area.setWidget(&label);
area.show();
return a.exec();
}

Qt: cursor blinking cause repaint of parent widget?

Bellow you can see minimal example code to demonstrate problem.
If you run it and give focus to QLineEdit, you get output every second: paintEvent, paintEvent and so on.
I can not understand why MyW::paintEvent called on every
cursor blinking in child widget? As you see I do not configure QLineEdit,
by default on my linux box it have no transparent elements,
but still for some reason cursor cause all widgets to redraw their content?
#include <QApplication>
#include <QWidget>
#include <QPaintEvent>
#include <QPainter>
#include <QLineEdit>
class MyW final : public QWidget {
public:
MyW() {
//setAutoFillBackground(false);
}
void paintEvent(QPaintEvent *e) {
e->accept();
qDebug("paintEvent");
QPainter painter{this};
painter.fillRect(rect(), Qt::green);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyW w;
w.resize(600, 600);
w.show();
auto le = new QLineEdit{&w};
le->show();
return app.exec();
}

QT zoom to Polygon

i have a fixed size QGraphicsview and my own class QGraphWidget class
GraphWidget::GraphWidget(QWidget *parent)
:QGraphicsView(parent)
{
QGraphicsScene *scene = new QGraphicsScene(this);
setScene(scene);
scale(1,-1);
setWindowTitle(tr("Poly"));
}
void GraphWidget::showPoly(){
scene()->clear();
scene()->setSceneRect(QRectF());
QPolygonF polygon;
QPen pen(Qt::black,1);
QBrush brush(Qt::black);
brush.setStyle(Qt::SolidPattern);
polygon<< QPointF(0,0)<< QPointF(10,0)<< QPointF(15,20)<<QPointF(5,10);
;
QGraphicsPolygonItem *polyItem=scene()->addPolygon(polygon,pen);
fitInView(polyItem);
}
It is possible that the scene focus the polygon and zoom it ?
I tried fitinView() or setSceneRect() but nothing worked, the polygon is still very small.
EDIT
with fitInView(polyItem->boundingRect());
The problem is that my QGraphicsview is fixed, so the fit in view has to zoom in. It can't change the size of the Qgraphicsview
So i got the answer.
The problem was that i called showPoly() inside of the constructor. But on this moment the size of the Qgraphicsview was not fixed.
I use a work around with QSingleShot
#include "mainwindow.h"
#include <QApplication>
#include <QTimer>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
QTimer::singleShot(1, &w,SLOT(callShowPoly()));
return a.exec();
}

QWidget::heightForWidth() is not called

I want to make my widget always have square size. Following this answer, I have overridden QWidget::heightForWidth(), and I also call setHeightForWidth(true) in the constructor, as suggested by #peppe. The size policy is set to Preferred,Preferred (for both horizontal size and vertical size).
However, heightForWidth() is not being called. Is there anything I am doing wrong?
This is the declaration of heightForWidth() in my Widget class:
virtual int heightForWidth(int) const;
This happens on Linux and Windows.
Your widget needs to be in a layout. The below works on both Qt 4 and 5.
In Qt 4, it will only force the toplevel window's minimum size if it's in a layout.
In Qt 5, it doesn't force the toplevel window size. There may be a flag for that or it's a bug but I don't recall at the moment.
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QDebug>
#include <QVBoxLayout>
#include <QFrame>
class Widget : public QWidget {
mutable int m_ctr;
public:
Widget(QWidget *parent = 0) : QWidget(parent), m_ctr(0) {
QSizePolicy p(sizePolicy());
p.setHeightForWidth(true);
setSizePolicy(p);
}
int heightForWidth(int width) const {
m_ctr ++;
QApplication::postEvent(const_cast<Widget*>(this), new QEvent(QEvent::UpdateRequest));
return qMax(width*2, 100);
}
QSize sizeHint() const {
return QSize(300, heightForWidth(300));
}
void paintEvent(QPaintEvent *) {
QPainter p(this);
p.drawRect(rect().adjusted(0, 0, -1, -1));
p.drawText(rect(), QString("h4w called %1 times").arg(m_ctr));
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QVBoxLayout * l = new QVBoxLayout(&w);
l->addWidget(new Widget);
QFrame * btm = new QFrame;
btm->setFrameShape(QFrame::Panel);
btm->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
l->addWidget(btm);
w.show();
return a.exec();
}
To stay square if the widget is in a layout you must reimplement
bool hasHeightForWidth() const{ return true; }
int heightForWidth(int w) const { return w; }
functions of the layout class.

adding QGraphicsView to QBoxLayout

I am a QT newbie and trying to play around with Apps. I have just coded a very trivial App with some buttons. The main idea is to have a small "logo" in my App. LAter I would like to add some background image as well.
I have coded from an example App with a grid layout within which is a QBoxLayout which groups my buttons.
As you can see in my code, I have tried adding the Logo everywhere. When I added it in main.cpp, I have two views one showing buttons and the other my logo. Of course I do not want this. So I tried adding it in mainwindow.cpp but in this case, I don't see my Logo appearing anywhere at all :(
Please advise.
Here is the code:
main.cpp:
#include <QtGui/QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window window;
window.show();
/*
QGraphicsScene scene;
QGraphicsView view(&scene);
QGraphicsPixmapItem item(QPixmap("/home/marc/Desktop/Niranjana/Images/logo.9.png"));
scene.addItem(&item);
view.show();
*/
return a.exec();
}
mainwindow.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <QRadioButton>
class QGroupBox;
class Window : public QWidget
{
Q_OBJECT
public:
Window(QWidget *parent = 0);
void onCheck_remote(int flag);
void onCheck_local(int flag);
private:
QRadioButton *button_local;
QRadioButton *button_remote;
QGroupBox *createPushButtonGroup();
};
#endif
mainwindow.cpp
#include <QtGui>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
#include "mainwindow.h"
Window::Window(QWidget *parent)
: QWidget(parent)
{
QGridLayout *grid = new QGridLayout;
QGraphicsScene scene;
QGraphicsPixmapItem item(QPixmap("/home/test/logo.png"));
QGraphicsView view(&scene);
scene.addItem(&item);
view.show();
grid->addWidget(view.viewport(), 1, 1);
grid->addWidget(createPushButtonGroup(), 2, 1);
setLayout(grid);
setWindowTitle(tr("My App"));
resize(480, 420);
}
QGroupBox *Window::createPushButtonGroup()
{
QGroupBox *groupBox = new QGroupBox();
/*
QGraphicsScene scene;
QGraphicsPixmapItem item(QPixmap("/home/marc/Desktop/Niranjana/Images/logo.9.png"));
QGraphicsView view(&scene);
scene.addItem(&item);
scene.setBackgroundBrush(Qt::white);
view.show();
*/
QPushButton *button1 = new QPushButton(tr("&Start"));
QPushButton *button2 = new QPushButton(tr("&Stop"));
button_local = new QRadioButton(tr("&with power"));
button_remote = new QRadioButton(tr("without power"));
button_local->setChecked(1);
QVBoxLayout *vbox = new QVBoxLayout;
// vbox->addSpacing(10);
// vbox->addWidget(view.viewport());
//vbox->addSpacing(10);
vbox->addWidget(button1);
vbox->addSpacing(10);
vbox->addWidget(button2);
vbox->addSpacing(50);
vbox->addWidget(button_local);
vbox->addWidget(button_remote);
vbox->addStretch(1);
groupBox->setLayout(vbox);
return groupBox;
}
You should
Make your scene, view, item pointer members of your window class
Instantiate them in your Window ctor
do grid->addWidget(view, 1, 1);
Otherwise, all the items instantiated on the stack in the ctor will get deleted when exiting.