QT Layout display - c++

I am new to Qt application programming, I have a task to complete i.e
I need to create a paint like application
Based on left side panel objects Right side List must display..
PFA
so now i am stuck with displaying right side panel
To be more clear...
I used left side QGroupBox with Push Buttons.
Right side i used QGridLayout to show specific objects.
Center graphics view ( ignore this point).
now when I am calling the function after push button clicked Button 1 : should display only numbered objects Button 2 : should display only other objects Button 3 : should display empty plane Button N : should display all objects
could some one suggest me with small code for it.... like
ui->gridLayout_1->... ( to hide previous options )
when called second time ui->gridLayout_1->addWidget(label0,0,0); should display relevant
when called for third time display all objects ui->gridLayout_1->addWidget(label0,0,0);

Edit: After seeing a better example of what you were trying to accomplish I threw this together using QStackedWidget. I think the below code mimics the behavior you are looking for. This has replaced my old answer as I didn't want to add any unnecessary confusion.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMainWindow>
#include <QPushButton>
#include <QStackedWidget>
#include <QWidget>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
QWidget *central_widget = new QWidget(this);
QHBoxLayout *central_layout = new QHBoxLayout();
QVBoxLayout *ctl_btn_layout = new QVBoxLayout();
QPushButton *ctl_btn_1 = new QPushButton("1", central_widget);
QPushButton *ctl_btn_2 = new QPushButton("2", central_widget);
QStackedWidget *widget_stack = new QStackedWidget(central_widget);
QWidget *page_0 = new QWidget();
QWidget *page_1 = new QWidget();
QGridLayout *page_1_layout = new QGridLayout();
QPushButton *r_btn = new QPushButton("R", page_1);
QPushButton *j_btn = new QPushButton("J", page_1);
QPushButton *l_btn = new QPushButton("L", page_1);
QPushButton *o_btn = new QPushButton("O", page_1);
QPushButton *v_btn = new QPushButton("V", page_1);
QPushButton *f_btn = new QPushButton("F", page_1);
QWidget *page_2 = new QWidget();
QVBoxLayout *page_2_layout = new QVBoxLayout();
QPushButton *btn_1 = new QPushButton("1", page_2);
QPushButton *btn_2 = new QPushButton("2", page_2);
QPushButton *btn_3 = new QPushButton("3", page_2);
QPushButton *btn_4 = new QPushButton("4", page_2);
QPushButton *btn_5 = new QPushButton("5", page_2);
QPushButton *btn_6 = new QPushButton("6", page_2);
QLabel *r = new QLabel("R", central_widget);
QLabel *j = new QLabel("J", central_widget);
QLabel *id = new QLabel("ID", central_widget);
QLabel *x = new QLabel("X", central_widget);
QLabel *y = new QLabel("Y", central_widget);
QLineEdit *r_line = new QLineEdit(central_widget);
QLineEdit *j_line = new QLineEdit(central_widget);
QLineEdit *id_line = new QLineEdit(central_widget);
QLineEdit *x_line = new QLineEdit(central_widget);
QLineEdit *y_line = new QLineEdit(central_widget);
QVBoxLayout *lines_layout = new QVBoxLayout();
public slots:
void ctl_btn_1_clicked();
void ctl_btn_2_clicked();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
ctl_btn_layout->addWidget(ctl_btn_1);
connect(ctl_btn_1, SIGNAL(clicked(bool)), this, SLOT(ctl_btn_1_clicked()));
ctl_btn_layout->addWidget(ctl_btn_2);
connect(ctl_btn_2, SIGNAL(clicked(bool)), this, SLOT(ctl_btn_2_clicked()));
central_layout->addLayout(ctl_btn_layout);
page_1_layout->addWidget(r_btn, 0, 0, 1, 1);
page_1_layout->addWidget(j_btn, 1, 1, 1, 1);
page_1_layout->addWidget(l_btn, 2, 0, 1, 1);
page_1_layout->addWidget(o_btn, 3, 1, 1, 1);
page_1_layout->addWidget(v_btn, 4, 2, 1, 1);
page_1_layout->addWidget(f_btn, 5, 3, 1, 1);
page_1->setLayout(page_1_layout);
page_2_layout->addWidget(btn_1);
page_2_layout->addWidget(btn_2);
page_2_layout->addWidget(btn_3);
page_2_layout->addWidget(btn_4);
page_2_layout->addWidget(btn_5);
page_2_layout->addWidget(btn_6);
page_2->setLayout(page_2_layout);
widget_stack->addWidget(page_0); //Empty QWidget.
widget_stack->addWidget(page_1);
widget_stack->addWidget(page_2);
central_layout->addWidget(widget_stack);
lines_layout->addWidget(r);
r->hide();
lines_layout->addWidget(r_line);
r_line->hide();
lines_layout->addWidget(j);
j->hide();
lines_layout->addWidget(j_line);
j_line->hide();
lines_layout->addWidget(id);
id->hide();
lines_layout->addWidget(id_line);
id_line->hide();
lines_layout->addWidget(x);
x->hide();
lines_layout->addWidget(x_line);
x_line->hide();
lines_layout->addWidget(y);
y->hide();
lines_layout->addWidget(y_line);
y_line->hide();
central_layout->addLayout(lines_layout);
central_widget->setLayout(central_layout);
setCentralWidget(central_widget);
}
MainWindow::~MainWindow()
{
}
void MainWindow::ctl_btn_1_clicked()
{
if (j->isVisible())
{
j->hide();
j_line->hide();
}
r->show();
r_line->show();
if (!id->isVisible())
{
id->show();
id_line->show();
x->show();
x_line->show();
y->show();
y_line->show();
}
widget_stack->setCurrentIndex(1);
}
void MainWindow::ctl_btn_2_clicked()
{
if (r->isVisible())
{
r->hide();
r_line->hide();
}
j->show();
j_line->show();
if (!id->isVisible())
{
id->show();
id_line->show();
x->show();
x_line->show();
y->show();
y_line->show();
}
widget_stack->setCurrentIndex(2);
}
This works by using a QStackedWidget, which is populated with 3 QWidgets. The first widget is completely empty to mimic the empty page from your example. The second and third widgets have layouts that hold your different button configurations, and the QStackedWidget will flip between pages through functions connected to the button slots.
Note that I tend not to use the form designer that comes w/ Qt Creator, preferring pure C++ UI design. It doesn't matter how you set it up, with or without the form, I just find it easier this way. Main.cpp was left as default from a new Qt GUI project with the generate form box unchecked.

Related

How to reduce distance between widgets and window size with Qt?

What I currently have:
What I want:
For those unable to view the images; the widgets are spread out by some sort of margin between them. I would like to keep them as close as possible. How can I squeeze the widgets closer together?
I have already tried:
setFixedSize(sizeHint()); and setSizeConstraint(QLayout::SetFixedSize); on the main window, layouts, and widget object. Nothing seems to work.
As an extra, I would also appreciate this:
(having the label get even closer to the lineEdit)
I am using Windows and Qt 5.11.1, 64-bits.
The window constructor code:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
widget = new QWidget();
label = new QLabel(tr("Enter your name:"));
nameLine = new QLineEdit;
nameLine->setMinimumWidth(250);
label->setBuddy(nameLine);
okButton = new QPushButton (tr("Ok"));
clearButton = new QPushButton (tr("Clear"));
connect(okButton, SIGNAL(clicked()), this, SLOT(message()));
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
QGridLayout *grid = new QGridLayout;
grid->addWidget(label,0,0);
grid->addWidget(nameLine,1,0);
grid->addWidget(okButton,0,1);
grid->addWidget(clearButton,1,1);
widget->setLayout(grid);
setWindowTitle(tr("Leo v0.0"));
setCentralWidget(widget);
}
A possible solution is to establish a QVBoxLayout with addStretch():
QVBoxLayout *vlay = new QVBoxLayout;
QGridLayout *grid = new QGridLayout;
grid->addWidget(label, 0, 0);
grid->addWidget(nameLine, 1, 0);
grid->addWidget(okButton, 0, 1);
grid->addWidget(clearButton, 1, 1);
vlay->addLayout(grid);
vlay->addStretch();
widget->setLayout(vlay);
setCentralWidget(widget);

Creating sequenced tabs in Qt

A program has the main window, the menu bar, the menu item (QAction in Qt), the tab widget, the text edit. I try to receive the sequenced numeration in the tabs when I press on the menu item (New Tab).
When I press on the New Tab then tab 1, tab 2, tab 3, tab 4 and so on must appear.
The suggested approximate code is here:
MainWindow::MainWindow(QWidget* parent):QMainWindow(parent)
{
QMenuBar* menuBar = new QMenuBar(this);
setMenuBar(menuBar);
QMenu* fileMenu = new QMenu("&File", this);
menuBar->addMenu(fileMenu);
QAction* newTabAction = new QAction("&New Tab", this);
fileMenu->addAction(newTabAction);
connect(newTabAction, SIGNAL(triggered()), this, SLOT(newTabActionHandler()));
QTabWidget* tabWidget = new QTabWidget(this);
QList<QWidget*> widgetList;
widgetList.append(new QWidget(this));
tabWidget->addTab(widgetList[0], "Tab 0");
tabWidget->setMovable(true);
tabWidget->setTabsClosable(true);
QList<QTextEdit*> textEditList;
textEditList.append(new QTextEdit(this));
QVBoxLayout* vBoxLayout = new QVBoxLayout();
widgetList[0]->setLayout(vBoxLayout);
vBoxLayout->addWidget(textEditList[0]);
setCentralWidget(tabWidget);
}
void MainWindow::newTabActionHandler()
{
widgetList.append(new QWidget(this));
tabWidget->addTab(widgetList[widgetList.size()-1], ????);
textEditList.append(new QTextEdit(this));
QVBoxLayout* vBoxLayout = new QVBoxLayout();
widgetList[widgetList.size()-1]->setLayout(vBoxLayout);
vBoxLayout->addWidget(textEditList[textEditList.size()-1]);
}
Please, put the correct code into the line where question signs take place to be (in the newTabActionHandler() method body).
tabWidget->addTab(widgetList[widgetList.size()-1], ????);
Thank You!
You have to order your code, in this case you only need to use the size of the list. but I have given the freedom to correct your code, for example widgetList and textEditList are local variables so you can not access from the slot so it is appropriate that they are members of the class.
Another recommendation is to order your code, the more readable your code is, so you can create widget and textedit and make your links without using your containers.
mainwindow.cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void newTabActionHandler();
private:
QList<QWidget*> widgetList;
QList<QTextEdit*> textEditList;
QTabWidget* tabWidget;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QMenu>
#include <QMenuBar>
#include <QTextEdit>
#include <QVBoxLayout>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QMenuBar *menuBar = new QMenuBar(this);
setMenuBar(menuBar);
QMenu* fileMenu = new QMenu("&File", this);
menuBar->addMenu(fileMenu);
QAction *newTabAction = new QAction("&New Tab", this);
fileMenu->addAction(newTabAction);
connect(newTabAction, &QAction::triggered, this, &MainWindow::newTabActionHandler);
tabWidget = new QTabWidget(this);
tabWidget->setMovable(true);
tabWidget->setTabsClosable(true);
newTabActionHandler();
setCentralWidget(tabWidget);
}
void MainWindow::newTabActionHandler()
{
QWidget *widget = new QWidget;
widgetList << widget;
tabWidget->addTab(widget, QString("Tab %1").arg(widgetList.size()-1));
QTextEdit *textEdit = new QTextEdit;
textEditList << textEdit;
QVBoxLayout* vBoxLayout = new QVBoxLayout(widget);
vBoxLayout->addWidget(textEdit);
}
MainWindow::~MainWindow()
{
}
You can find the complete example in the following link
Replace ???? by QString("Tab %1").arg(widgetList.size()-1)

Changing the content of a QTabWidget's widget, knowing only the tab index

How do I change the QWidget inside a tab of a QTabWidget, knowing only the tab index?
void MainWindow::on_toolButton_2_clicked()
{
TextItem myitem = new TextItem;//is a class TextItem : public QWidget
int tabindex = 2;
ui->tabwidget1->//i don't have a idea to change widget of a Tab by tab index
}
It's hard to say what solution would best suit your problem since you don't explain much of it.
A first approach would be to wrap the content of each tab inside a container QWidget: when you want to change the content of one tab, you just have to change the content of the container QWidget.
Another approach would be to delete the tab with the old content and create a new one with the new content.
EDIT:
Here is a quick implementation of the first approach I mentioned above:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
void buildTabWidget();
private slots:
void changeTabContent() const;
private:
QTabWidget* tab_widget;
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include <QLabel>
#include <QLayout>
#include <QPushButton>
#include <QTabWidget>
void MainWindow::buildTabWidget()
{
// The container will hold the content that can be changed
QWidget *container = new QWidget;
tab_widget = new QTabWidget(this);
tab_widget->addTab(container, "tab");
// The initial content of the container is a blue QLabel
QLabel *blue = new QLabel(container);
blue->setStyleSheet("background: blue");
blue->show();
}
void MainWindow::changeTabContent() const
{
// retrieve the QWidget 'container'
QWidget *container = tab_widget->widget(0);
// the 'blue' QLabel
QWidget *old_content = dynamic_cast<QWidget*>(container->children()[0]);
delete old_content;
// create a red QLabel, as a new content
QWidget *new_content = new QLabel(container);
new_content->setStyleSheet("background: red");
new_content->show();
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
buildTabWidget();
QPushButton* push_button = new QPushButton("Change content");
connect(push_button, SIGNAL(clicked(bool)), this, SLOT(changeTabContent()));
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(tab_widget);
layout->addWidget(push_button);
QWidget *window = new QWidget();
window->setLayout(layout);
window->show();
setCentralWidget(window);
}
Clicking the button Change content will delete the old content (the blue QLabel) in the tab, and will replace it by creating a new content (a red QLabel):

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

QGridlayout changes height of row

I have a problem with a QGridLayout. One row of my layout contains an element (QProgressbar) that is normaly hidden. When there is some progress to report i call show on it. The problem is that when i call show on the QProgressbar the row above the row containing it will be slightly resized in height (1-3 px). So the whole layout does a little "jump" which looks ugly.
I have given a minimalRowHeight to the row that contains the QProgressbar that is much larger then the height of the QProgressbar but still the height of the row will increase on show().
I have attached a very minimal version of my program that demonstrates the problem. Can anyone give me a hint what is going on there?
Header:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui/QMainWindow>
#include <QLineEdit>
#include <QtWebKit/QWebView>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
private:
QLineEdit* input;
QWebView *webview;
private slots:
void slotLoadButton();
};
#endif // MAINWINDOW_H
Source:
#include "mainwindow.h"
#include <QProgressBar>
#include <QPushButton>
#include <QGridLayout>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QGridLayout *grid = new QGridLayout;
input = new QLineEdit;
QPushButton *loadButton = new QPushButton("load");
connect(loadButton, SIGNAL(clicked()),
this, SLOT(slotLoadButton()));
webview = new QWebView;
QProgressBar *progress = new QProgressBar;
progress->setFixedHeight(25);
progress->hide();
connect(webview, SIGNAL(loadStarted()),
progress, SLOT(show()));
connect(webview, SIGNAL(loadProgress(int)),
progress, SLOT(setValue(int)));
connect(webview, SIGNAL(loadFinished(bool)),
progress, SLOT(hide()));
grid->addWidget(input, 0, 0);
grid->addWidget(loadButton, 0, 1);
grid->addWidget(webview, 1, 0, 1, -1);
grid->setRowMinimumHeight(2, 35);
grid->addWidget(progress, 2, 1);
QWidget* widget = new QWidget;
widget->setLayout(grid);
setCentralWidget(widget);
}
void MainWindow::slotLoadButton()
{
QUrl url = input->text();
webview->load(url);
}
This is likely caused by the vertical spacing and/or margins of the layout. You should try playing with those properties.
This looks like a bug in Qt. Try reporting it
This is a workaround:
//grid->addWidget(progress, 2, 1);
QHBoxLayout *l = new QHBoxLayout;
l->addWidget(progress);
QWidget *w = new QWidget;
w->setLayout(l);
grid->addWidget(w, 2, 1);