How do I get a QLabel to expand to full width? - c++

I want a QLabel to expand to full width of the container regardless of the contents. (I want this because I dynamically set the text and add widgets later which cause it to cut off part of the text)
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->setFixedSize(100,100);
QHBoxLayout *layout = new QHBoxLayout;
this->setLayout(layout);
QLabel *label = new QLabel;
label->setStyleSheet("background-color:blue");
label->setSizePolicy(QSizePolicy::MinimumExpanding,
QSizePolicy::MinimumExpanding);
label->setText(tr("test"));
layout->addWidget(label, 0, Qt::AlignTop | Qt::AlignLeft);
}
This code shows that the blue box does not expand to the entire width, why?

You must set:
layout->setContentsMargins(0,0,0,0);
By default every QWidget or QFrame add 15 pixels of margin in every direction.
The main problem is with setting the alignment when you add the widget to the layout. Use label->setAlignment instead.
layout->addWidget(label);
I compiled your code, it works with those changes.
Here is the minimal example:
#include <QApplication>
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget* w = new QWidget;
w->setFixedSize(100,100);
QHBoxLayout* layout = new QHBoxLayout;
layout->setContentsMargins(0,0,0,0);
w->setLayout(layout);
QLabel* label = new QLabel;
label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
label->setContentsMargins(0,0,0,0);
label->setStyleSheet("background-color:blue");
label->setSizePolicy(QSizePolicy::MinimumExpanding,
QSizePolicy::MinimumExpanding);
label->setText("test");
layout->addWidget(label);
w->show();
return a.exec();
}

Related

Qt Application with layout's, QPushButton and QGraphicsItem

I am trying to draw various shapes like rectangle, ellipse, text etc uisng QGraphicsView and QGraphicsScene. For that I am trying to create an interface where there will be a vertical layout and besides that there will be few buttons. On clicking those buttons, I can show various QGraphicsItem's on screen. I want to create this interface programatically but not using ui.
I tried and ended up this way.
I wanted buttons on the right side and verticalLayout on the left side and both should filled up the whole screen.
Here is my current implementation :
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QGraphicsScene* scene = new QGraphicsScene(this);
QGraphicsView* view = new QGraphicsView(this);
view->setScene(scene);
QWidget* mainWidget = new QWidget(this);
QHBoxLayout *mainLayout = new QHBoxLayout();
QVBoxLayout *buttonLayout = new QVBoxLayout();
QVBoxLayout *vlayout2 = new QVBoxLayout();
vlayout2->addWidget(view);
QPushButton *btn1 = new QPushButton("Rectangle");
btn1->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
QPushButton *btn2 = new QPushButton("Ellipse");
btn2->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
QPushButton *btn3 = new QPushButton("Text");
btn3->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
buttonLayout->addWidget(btn1);
buttonLayout->addWidget(btn2);
buttonLayout->addWidget(btn3);
buttonLayout->addStretch();
mainLayout->addLayout(buttonLayout);
mainLayout->addLayout(vlayout2);
mainWidget->setLayout(mainLayout);
}
Can anyone guide me ?
Actually, it should work with the hints given in my comments.
I made an MCVE to convince myself:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QWidget qMain;
qMain.setWindowTitle("Test Box Layout");
qMain.resize(640, 320);
QHBoxLayout qHBox;
QVBoxLayout qVBoxBtns;
QPushButton qBtnRect("Rectangle");
qVBoxBtns.addWidget(&qBtnRect);
QPushButton qBtnCirc("Circle");
qVBoxBtns.addWidget(&qBtnCirc);
QPushButton qBtnText("Text");
qVBoxBtns.addWidget(&qBtnText);
qVBoxBtns.addStretch();
qHBox.addLayout(&qVBoxBtns);
QVBoxLayout qVBoxView;
QGraphicsView qView;
qVBoxView.addWidget(&qView, 1);
qHBox.addLayout(&qVBoxView, 1);
qMain.setLayout(&qHBox);
qMain.show();
// runtime loop
return app.exec();
}
Output:
Thus, there must be something else in OP's code…
Unfortunately, OP didn't expose an MCVE.
Thus, it's not clear how OP's Widget is instanced. Is it the widget which becomes the main window? Is there another widget where the Widget's instance becomes child of?
It's just guessing but the latter would explain what OP described.
To confirm my guess, I modified the above code a bit:
// setup GUI
QWidget qMain0; // main window widget
QWidget qMain(&qMain0); // child widget of main window widget
⋮
qMain.setLayout(&qHBox);
qMain0.show();
// runtime loop
return app.exec();
Please, note that qMain is now a child of qMain0 but there is no layout which adjusts the size of qMain when qMain0 is resized.
Hence, the size of view stays the initial size while the window is resized.

Overlay widgets

I am trying to overlay a few buttons over my video player.
I have added a new class called overlay.cpp that subclassed a QWidget for the overlay purpose.
What I did in my code is to overlay button onto the video. In my centralWidget I have added a verticalLayout and morph it into a QWidget. The video was added into this verticalLayout. Upon program is running, the video is playing well. However, what's not working is the overlay of the button. The background doesn't seem to appear transparent even though it was set. I am not sure what is causing it to not appear transparent.
My code is as follows:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[]){
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),
ui(new Ui::MainWindow){
ui->setupUI(this);
initializeVideo();
initializeButton();
}
MainWindow::~MainWindow(){
delete ui;
}
void MainWindow::initializeVideo(){
QVideoWidget *v_widget = new QVideoWidget;
QMediaPlayer *m_player = new QMediaPlayer;
m_player->setMedia(QUrl::fromLocalFile("C:/user/Desktop/video.wmv"));
m_player->setVideoOutput(v_widget);
ui->verticalLayout->addWidget(v_widget);
m_player->player();
v_widget->show();
}
void MainWindow::initializeButton(){
QFrame *b_frame = new QFrame;
QGridLayout *grid = new QGridLayout;
b_frame->setLayout(grid);
b_frame->setAttribute(Qt::WA_TranslucentBackground, true);
QPushButton *buttonStop = new QPushButton;
buttonStop->setText("STOP");
grid->addWidget(buttonStop, 0, 0, Qt::AlignTop);
overlay *overlay_1 = new overlay;
QGridLayout *gridLayout = new QGridLayout;
gridLayout->addWidget(b_frame);
overlay_1->setLayout(gridLayout);
overlay_1->setParent(ui->verticalWidget);
overlay_1->show();
b_frame->show();
}
overlay.cpp
#include "overlay.h"
overlay::overlay(QWidget *parent): QWidget(parent){
this->setAttribute(Qt::WA_TranslucentBackground, true);
}
Move declaration of QVideoWidget *v_widget and QMediaPlayer *m_player to mainwindow.h like this:
private:
Ui::MainWindow *ui;
QVideoWidget *v_widget;
QMediaPlayer *m_player;
In mainwindow.cpp:
void MainWindow::initializeVideo()
{
v_widget = new QVideoWidget(this);
m_player = new QMediaPlayer(this);
m_player->setMedia(QUrl::fromLocalFile("C:/user/Desktop/video.wmv"));
m_player->setVideoOutput(v_widget);
ui->verticalLayout->addWidget(v_widget);
m_player->play();
}
void MainWindow::initializeButton()
{
QGridLayout *grid = new QGridLayout(v_widget);
QPushButton *buttonStop = new QPushButton(this);
buttonStop->setText("STOP");
grid->addWidget(buttonStop, 0, 0, Qt::AlignTop);
}
This will add "STOP" button on top of QVideoWidget.
Specify widget's parent when crating it. new QVideoWidget(this) will create new QVideoWidget as child of current MainWindow widget. If you are creating child of already visible widget you do not need to call show() on it.

QPushButton does not honor horizontal expanding size policy

I'm trying to put several QPushButton entities inside a QVBoxLayout such that they are centered and expanding. The expanding tag works fine until I tell the QVBoxLayout to use AlignHCenter, after which the QPushButton's all jump to the minimum size and stay there. What am I doing wrong?
QVBoxLayout *vBoxLayout = new QVBoxLayout(this);
setLayout(vBoxLayout);
//Create title and add to layout
QLabel *titleLabel = new QLabel(this);
titleLabel->setText(menuTitle);
titleLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
titleLabel->setMaximumHeight(35);
titleLabel->setStyleSheet(QString("QLabel { font-size: 16pt; }"));
vBoxLayout->addWidget(titleLabel);
vBoxLayout->setStretchFactor(titleLabel, 1);
//Create buttons and add to layout
QMap<int, QString>::const_iterator it;
for (it = m_buttonMapping.cbegin(); it != m_buttonMapping.cend(); ++it)
{
QPushButton *button = new QPushButton(it.value(), this);
connect(button, SIGNAL(clicked()), sigMapper, SLOT(map()));
sigMapper->setMapping(button, it.key());
button->setMinimumHeight(40);
button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button->setMaximumWidth(800);
button->setMinimumWidth(300);
vBoxLayout->addWidget(button);
vBoxLayout->setAlignment(button, Qt::AlignHCenter); //<-- without this, expanding works fine!
vBoxLayout->setStretchFactor(button, 1);
}
vBoxLayout->setContentsMargins(10, 0, 10, 0);
By specifying the alignment on the layout, you keep your QPushButtons from being able to expand. Available new space will be used to keep the QPushButtons centered, instead of allowing them to resize and for an amount of space around them to be utilized for centering. Stretch factors fulfill your requirement for a proportional resizing and centering of a layout's contents.
To get around this, create a wrapper widget and layout (or just a layout), and add the widget that is laid out by your vBoxLayout to the wrapper layout with a stretch factor applied. Before and after adding your widget, you'll add QSpacerItems to the wrapper layout with QHBoxLayout::addStretch. You can then adjust the stretch factors of your widget and the spacers to get the effect you want.
Here's some sample code that should solve your problem:
MainWindow.cpp
#include "MainWindow.hpp"
#include <QPushButton>
#include <QLabel>
#include <QBoxLayout>
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent) {
QWidget* centralWidget = new QWidget(this);
QVBoxLayout* layout = new QVBoxLayout(centralWidget);
// Create a wrapper widget that will align horizontally
QWidget* alignHorizontalWrapper = new QWidget(centralWidget);
layout->addWidget(alignHorizontalWrapper);
// Layout for wrapper widget
QHBoxLayout* wrapperLayout = new QHBoxLayout(alignHorizontalWrapper);
// Set its contents margins to 0 so it won't interfere with your layout
wrapperLayout->setContentsMargins(0, 0, 0, 0);
wrapperLayout->addStretch(1);
QWidget* widget = new QWidget(alignHorizontalWrapper);
wrapperLayout->addWidget(widget, 3);
wrapperLayout->addStretch(1);
QVBoxLayout* vBoxLayout = new QVBoxLayout(widget);
QLabel* titleLabel = new QLabel(this);
titleLabel->setText(QStringLiteral("Menu"));
titleLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
titleLabel->setMaximumHeight(35);
titleLabel->setStyleSheet(QStringLiteral("QLabel { font-size: 16pt; }"));
vBoxLayout->addWidget(titleLabel);
vBoxLayout->setStretchFactor(titleLabel, 1);
for (int i = 0; i < 3; ++i) {
const QString& value = QStringLiteral("Button ") + QString::number(i);
QPushButton* button = new QPushButton(value, this);
button->setMinimumHeight(40);
button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
//button->setMaximumWidth(800);
button->setMinimumWidth(300);
vBoxLayout->addWidget(button);
//vBoxLayout->setAlignment(button, Qt::AlignHCenter); // without this, expanding works fine!
vBoxLayout->setStretchFactor(button, 3);
}
vBoxLayout->setContentsMargins(10, 0, 10, 0);
this->setCentralWidget(centralWidget);
}
MainWindow.hpp
#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP
#include <QMainWindow>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = nullptr);
};
#endif // MAINWINDOW_HPP
main.cpp
#include "MainWindow.hpp"
#include <QApplication>
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}

Qt custom widget not showing child widgets

I have a custom widget with some standard child widgets inside. If I make a separate test project and redefine my custom widget to inherit QMainWindow, everything is fine. However, if my custom widget inherits QWidget, the window opens, but there are no child widgets inside.
This is the code:
controls.h:
#include <QtGui>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QPushButton>
class Controls : public QWidget
{
Q_OBJECT
public:
Controls();
private slots:
void render();
private:
QWidget *frame;
QWidget *renderFrame;
QVBoxLayout *layout;
QLineEdit *rayleigh;
QLineEdit *mie;
QLineEdit *angle;
QPushButton *renderButton;
};
controls.cpp:
#include "controls.h"
Controls::Controls()
{
frame = new QWidget;
layout = new QVBoxLayout(frame);
rayleigh = new QLineEdit;
mie = new QLineEdit;
angle = new QLineEdit;
renderButton = new QPushButton(tr("Render"));
layout->addWidget(rayleigh);
layout->addWidget(mie);
layout->addWidget(angle);
layout->addWidget(renderButton);
frame->setLayout(layout);
setFixedSize(200, 400);
connect(renderButton, SIGNAL(clicked()), this, SLOT(render()));
}
main.cpp:
#include <QApplication>
#include "controls.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Controls *controls = new Controls();
controls->show();
return app.exec();
}
This opens up a window with correct dimensions, but with no content inside.
Bear in mind this is my first day using Qt. I need to make this work without inheriting QMainWindow because later on I need to put this on a QMainWindow.
You're missing a top level layout:
Controls::Controls()
{
... (yoour code)
QVBoxLayout* topLevel = new QVBoxLayout(this);
topLevel->addWidget( frame );
}
Or, if frame is not used anywhere else, directly:
Controls::Controls()
{
layout = new QVBoxLayout(this);
rayleigh = new QLineEdit;
mie = new QLineEdit;
angle = new QLineEdit;
renderButton = new QPushButton(tr("Render"));
layout->addWidget(rayleigh);
layout->addWidget(mie);
layout->addWidget(angle);
layout->addWidget(renderButton);
setFixedSize(200, 400);
connect(renderButton, SIGNAL(clicked()), this, SLOT(render()));
}
Note that setLayout is done automatically when QLayout is created (using parent widget)
You'll want to set a layout on your Controls class for managing its child sizes. I'd recommend removing your frame widget.
controls.cpp
Controls::Controls()
{
layout = new QVBoxLayout(this);
.
.
.
}
main.cpp
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.show();
return app.exec();
}

QLabel takes complete space

I have a QWidget which contains a QVBoxLayout and that layout contains a QLabel and QToolButtons. My problem is, that the QLabel takes all the space. The only solution I found is to set maximumHeight to the QLabel, but if I do that, the Qt::AlignTop doesn't work anymore.
main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window_main;
QWidget *widget_steps = new QWidget(&window_main);
widget_steps->setFixedWidth(75);
widget_steps->move(QPoint(0, 0));
widget_steps->setStyleSheet("background-color: red;");
QVBoxLayout *layout_steps = new QVBoxLayout(widget_steps);
layout_steps->setContentsMargins(0, 0, 0, 0);
layout_steps->setSpacing(0);
QLabel *label_steps_start = new QLabel("steps:");
label_steps_start->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
label_steps_start->setStyleSheet("background-color: blue;");
layout_steps->addWidget(label_steps_start);
QToolButton *tbutton_step1 = new QToolButton();
layout_steps->addWidget(tbutton_step1);
QToolButton *tbutton_step2 = new QToolButton();
layout_steps->addWidget(tbutton_step2);
QToolButton *tbutton_step3 = new QToolButton();
layout_steps->addWidget(tbutton_step3);
window_main.showMaximized();
return a.exec();
}
Here a picture that shows how much space the QLable takes(the blue space):
So please help to minimize the space the QLable takes :)
Your problem is that the tool buttons have a fixed size, and therefore when resizing, the label is the only type that can grow: Therefore:
After adding the label, add stretch to the layout:
layout_steps->addWidget(label_steps_start);
layout_steps->addStretch();
Modified code - adds stretch at the bottom. Label size remains fixed, and buttons remain under it. I've removed the whole main window around the outside for the sake of testing.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *widget_steps = new QWidget;
widget_steps->setFixedWidth(75);
widget_steps->move(QPoint(0, 0));
widget_steps->setStyleSheet("background-color: red;");
QVBoxLayout *layout_steps = new QVBoxLayout(widget_steps);
layout_steps->setContentsMargins(0, 0, 0, 0);
layout_steps->setSpacing(0);
QLabel *label_steps_start = new QLabel("steps:");
label_steps_start->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
label_steps_start->setStyleSheet("background-color: blue;");
layout_steps->addWidget(label_steps_start);
//--- Removed.... layout_steps->addStretch();
QToolButton *tbutton_step1 = new QToolButton();
layout_steps->addWidget(tbutton_step1);
QToolButton *tbutton_step2 = new QToolButton();
layout_steps->addWidget(tbutton_step2);
QToolButton *tbutton_step3 = new QToolButton();
layout_steps->addWidget(tbutton_step3);
layout_steps->addStretch(); //<----- Added!
widget_steps->show();
return a.exec();
}
One way you could do is to set the stretch factor for that particular widget inside the QVBoxLayout. You can find the documentation for that in here.
Basically, when you add a widget you can set that, for instance:
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QToolButton>
#include <QtWidgets/QVBoxLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window_main;
QWidget *widget_steps = new QWidget(&window_main);
widget_steps->setFixedWidth(75);
widget_steps->move(QPoint(0, 0));
widget_steps->setStyleSheet("background-color: red;");
QVBoxLayout *layout_steps = new QVBoxLayout(widget_steps);
layout_steps->setContentsMargins(0, 0, 0, 0);
layout_steps->setSpacing(0);
QLabel *label_steps_start = new QLabel("steps:");
label_steps_start->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
label_steps_start->setStyleSheet("background-color: blue;");
layout_steps->addWidget(label_steps_start, 3, Qt::AlignTop);
layout_steps->addStretch();
QToolButton *tbutton_step1 = new QToolButton();
layout_steps->addWidget(tbutton_step1, 1);
QToolButton *tbutton_step2 = new QToolButton();
layout_steps->addWidget(tbutton_step2, 1);
QToolButton *tbutton_step3 = new QToolButton();
layout_steps->addWidget(tbutton_step3, 1);
window_main.showMaximized();
return a.exec();
}