Vertical size of a QLabel with wordWrap enabled - c++

I have a QLabel in a QVBoxLayout. Most of the times, it only has one line of text, but sometimes, the text can be too long to fit in one line. So I have to enable wordWrap.
I want the label to be as (vertically) small as possible, thus I set setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum).
Now, if there's enough vertical space, the label is higher as it would have to be with only one line:
At the same window size and without wordWrap being enabled, the label only takes the minimum space I would like it to take:
Can this also be achieved with wordWrap being enabled and independent of the window height?

I tried to reproduce the behavior with a small example. Maybe this might help you to solve your issue. Just enlarge the widget and type some random text having several words separated by white spaces.
The idea is to use the correct combination of QSizePolicys not just for the QLabel, but also for the other GUI elements.
#include <QFrame>
#include <QLabel>
#include <QGroupBox>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QPushButton>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto frame = new QFrame;
frame->setLayout(new QVBoxLayout);
auto groupEdit = new QGroupBox;
groupEdit->setLayout(new QHBoxLayout);
auto edit = new QLineEdit;
groupEdit->layout()->addWidget(edit);
frame->layout()->addWidget(groupEdit);
auto group = new QGroupBox;
frame->layout()->addWidget(group);
group->setLayout(new QHBoxLayout);
auto label = new QLabel;
groupEdit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
group->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
group->layout()->addWidget(label);
group->layout()->addWidget(new QPushButton);
QObject::connect(edit, &QLineEdit::textEdited, [&](const QString& text) {
label->setText(text);
label->setWordWrap(true);
});
frame->show();
return a.exec();
}

Related

Draw inside a QGraphicsScene inside a QWidget

I am trying to have a window (in the form of a QWidget) consisting of both a menu on the right and a graphics area on the left.
Despite the numerous websites explaining the many ways to use QGraphicsScene and QGraphicsView, I just couldn't figure out how to do it.
Here's main.cpp modified to work on its own :
#include <QApplication>
#include <QRectF>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QPushButton>
#include <QVBoxLayout>
#include <QGraphicsRectItem>
#include <QPalette>
int main (int argc, char * argv []) {
QApplication app (argc, argv) ;
// Main window
QWidget frame ;
frame.setFixedSize(750, 550) ;
frame.show() ;
// Right side, works ok
QWidget menu (&frame) ;
menu.setFixedSize(200, 500) ;
menu.move(550, 10) ;
QPalette pal = menu.palette() ;
pal.setColor(QPalette::Background, Qt::red) ;
menu.setPalette(pal) ; // I expected this to color the whole area
// to show the extent of the zone devoted to the menu,
// but it only outlines the button
menu.show() ;
QPushButton button ("Menu", &menu) ;
button.show() ; // I didn't think this was necessary,
// but the button didn't appear without this line
// Left side, nothing displayed
QVBoxLayout layout ;
QGraphicsScene * scene = new QGraphicsScene () ;
QGraphicsView view (scene) ;
layout.addWidget(&view) ;
QWidget canvas (&frame) ;
canvas.setLayout(&layout) ;
// I found this trick to include a QGraphicsScene inside a QWidget,
// I haven't had the opportunity to see whether it really works.
scene->addItem(new QGraphicsRectItem(10, 10, 20, 20)) ;
// The above line has no visible effect
view.show() ;
return app.exec() ;
}
I would expect this to create a window, put a bunch of buttons on the right side (or in the case of the rediced code I provided, just a single button), and draw a rectangle on the left, but it leaves the whole left area blank.
Does the problem come from how I put the QGraphicsView inside the QWidget ? Or is it failing to draw because of something else ? Do I have to update the QGraphicsView to reflect the change ? Is it just out of visible range ?
Finally, is the failure to draw in any way related to the fact that the whole application crashes on line QWidget canvas (&frame) ; when closed ?
I just repaired you program a bit, so that it illustrates, what you can do with Qt and how you should likely use the framework.
I just moved the QPushButton to a QAction residing in a QMenuBar. The QMenuBar can be added to a QMainWindow, which is reasonable for a normal app.
The central widget of the QMainWindow contains the QGraphicsView. Now, you just forgot to connect the QGraphicsScene with the QGraphicsView. That was the reasons for not seeeing anything in your view.
QGraphicsView and QGraphicsScene are just a typical example for a MVC pattern. You can also add another QGraphicsView and connect it to the same QGraphicsScene.
You should also create all you objects with new, as Qt automatically disposes all its children of a QObject, if it is either deleted or leaves scope.
If you are realyl interesting into seriously learning Qt I suggest, that you are creating plenty small example programs like these. It really helped me a lot.
#include <QApplication>
#include <QMenuBar>
#include <QGraphicsView>
#include <QVBoxLayout>
#include <QGraphicsRectItem>
#include <QMainWindow>
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
auto mainWindow = new QMainWindow;
auto menuBar = new QMenuBar;
auto menu = new QMenu("Menu");
auto action = new QAction("Action");
menu->addAction(action);
menuBar->addMenu(menu);
mainWindow->setMenuBar(menuBar);
auto frame = new QFrame;
frame->setLayout(new QVBoxLayout);
mainWindow->setCentralWidget(frame);
auto scene = new QGraphicsScene();
auto view=new QGraphicsView(scene);
view->setScene(scene); // That connects the view with the scene
frame->layout()->addWidget(view);
QObject::connect(action, &QAction::triggered, [&]() {
scene->addItem(new QGraphicsRectItem(10, 10, 20, 20));
});
mainWindow->show();
return app.exec();
}

Qt QScrollArea leftover graphic artifacts when scrolling with TranslucentBackground flag

I get graphic artifacts when scrolling a qscrollarea that is not a seperate window and both the scroll area and the target widget's TranslucentBackground flag is set to true. The problem doesn't happen when the scrollarea is opened as a seperate window with null parent or Qt::Window flag.
Was this behavior intended or is this a bug?
If it is a bug, is
there a fix you know of?
I've tried many other window flags but all the ones that don't open a separate window have the same issue.
#include <QApplication>
#include <QWidget>
#include <QHBoxLayout>
#include <QPushButton>
#include <QScrollArea>
#include <QScrollerProperties>
#include <QScroller>
#include <QTouchDevice>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *mainWindow = new QWidget;
QHBoxLayout *buttonsLayout = new QHBoxLayout;
QWidget *buttonsWidget = new QWidget();
buttonsWidget->setLayout(buttonsLayout);
buttonsWidget->setAttribute(Qt::WA_TranslucentBackground);
buttonsWidget->setAttribute(Qt::WA_NoSystemBackground);
for(int i = 0; i < 10; ++i) {
QPushButton *button = new QPushButton("Button " + QString::number(i), buttonsWidget);
buttonsLayout->addWidget(button);
}
QScrollArea *scrollArea = new QScrollArea(mainWindow);
scrollArea->setAttribute(Qt::WA_TranslucentBackground);
scrollArea->setAttribute(Qt::WA_NoSystemBackground);
scrollArea->setWidgetResizable(true);
scrollArea->setFixedHeight(100);
scrollArea->setWidget(buttonsWidget);
scrollArea->setWindowFlag(Qt::WindowStaysOnTopHint);
mainWindow->show();
scrollArea->show();
return a.exec();
}
Example artifact when, compiled with Qt5.12.1 open source version, ubuntu 16.04.

Using drawComplexControl to retrieve QSliderHandle image

Today I was trying to take a picture of the QSlider handle in order to use it in an adpated QSlider widget with two handles.
This is somewhat similar to the following question: Range slider in Qt (two handles in a QSlider)
For a full fledged solution I can not use a simple image files. I tried to create the image of the QSlider by using the drawComplexControl function, but it leaves me basically with a black image.
What I'm doing wrong here? It seems so simple to me, but it is just not working.
#include <QApplication>
#include <QPushButton>
#include <QPainter>
#include <QStyleOptionSlider>
int main(int argc, char** args) {
QApplication app(argc, args);
auto slider = new QSlider;
slider->setOrientation(Qt::Orientation::Horizontal);
slider->show();
auto btn = new QPushButton("Create Image");
QObject::connect(btn, &QPushButton::clicked, [&] {
auto style = QApplication::style();
QStyleOptionSlider sliderOptions;
QPixmap pix(slider->size());
auto painter = new QPainter();
painter->begin(&pix);
style->drawComplexControl(QStyle::CC_Slider, &sliderOptions, painter, slider);
pix.save("SliderImage.png");
auto handleRect = style->subControlRect(QStyle::ComplexControl::CC_Slider, &sliderOptions, QStyle::SubControl::SC_SliderHandle, slider);
QPixmap handlePix = pix.copy(handleRect);
handlePix.save("SliderHandleImage.png");
painter->end();
});
btn->show();
app.exec();
}
The solution was very simple. I just forgot to add:
sliderOption.initFrom(slider);

Fill background outside window QT

I have read a documentation and aswell many sites on website.
Unfortunatly I didn't find answer to my question.
Is there any chance(I believe there is) to fill background outside the popup window? Let me explain: If i have window like of my whole app with resolution 500x500 [px] and I create a popup window 300x300 in the middle - it means I have 200 px in each side "parent-window". Is there any chance (method, flag) to fill background in gray color?
Image: https://imgur.com/Hunev58
Modifying the palette does the job. Here you get a purple background when the MessageBox is shown , and come back to normal once clicked
#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QMessageBox>
#include <QPalette>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
QVBoxLayout mainLayout;
QLabel foolabel("FooLabel");
QPushButton foobutton("FooButton");
mainLayout.addWidget(&foolabel);
mainLayout.addWidget(&foobutton);
QWidget window;
window.setLayout(&mainLayout);
w.setCentralWidget(&window);
QPalette palette = QApplication::palette(&w);
palette.setColor(QPalette::Inactive,QPalette::Window,QColor(138,43,226));
w.setPalette(palette);
w.show();
QMessageBox box(&w);
box.exec();
return a.exec();
}

How to center items in a QBoxLayout without using QSpacerItems

A QLayout always tries to use the whole available space of the QWidget. But, sometimes, you want it to keep it's minimal size and center itself on the widget...because you feel like it looks better (if the layout only contains items that does not make sense to be displayed bigger than their default size: QLabel, QPushButton and stuffs like that).
I had this problem hundreds of times in the past, and I'm always adding stupid QSpacerItems everywhere to fix that. I'm wondering if there could be a better solution.
I isolated the problem as an illustration:
#include <QApplication>
#include <QDialog>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QSpacerItem>
class MainFrame : public QDialog
{
public:
MainFrame() : QDialog(NULL)
{
QHBoxLayout* theLayout = new QHBoxLayout();
setLayout( theLayout );
// don't want to add spacers all the time!
//theLayout->addSpacerItem( new QSpacerItem( 10, 10, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ) );
theLayout->addWidget( new QLabel( "A text", this ) );
theLayout->addWidget( new QPushButton( "A button", this ) );
// don't want to add spacers all the time!
//theLayout->addSpacerItem( new QSpacerItem( 10, 10, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ) );
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainFrame w;
w.resize(400,400);
w.show();
return a.exec();
}
Without the spacers, here's how it looks like:
I hate this display, on larger QWidget your eyes have to go all around the widget to find the relevant information.
With spacers, here's how it looks like:
I like it much better.
Is there a way to do this without adding the spacers? It's a pain adding them and always having to specify all those arguments (defaults won't do what you want...).
I tried to use QLayout::setSizeConstraint with no success. Does not appear to be meant to do this.
I would do it in the following way:
[..]
theLayout->addStretch();
theLayout->addWidget( new QLabel( "A text", this ) );
theLayout->addWidget( new QPushButton( "A button", this ) );
theLayout->addStretch();
[..]