While using the QtStackedWidget for switching windows in a big project, it doesn't seem to take in consideration the " setWindowTitle " part added in every window, and even for the size it takes only the first size precise in the QtStackedWidget declaration. This is weird.Any clarification I'm here to read.
So My question is:
-does the QtStackedWidget allow us to change the window's title each time we switch the window?
-and what about the size is it fixed or dynamic?
From the Qt docs setWindowTitle
This property only makes sense for top-level widgets, such as windows and dialogs. If no caption has been set, the title is based of the windowFilePath. If neither of these is set, then the title is an empty string.
You can connect the QStackedWidget signals to the QMainWindow
Here is a working example:
#include <QPushButton>
#include <QHBoxLayout>
#include <QLabel>
#include <QStackedWidget>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QWidget * poCentral = new QWidget(this);
QVBoxLayout * poVLayout = new QVBoxLayout;
QHBoxLayout * poHBtnLayout = new QHBoxLayout;
QStackedWidget * poMyStackedWidget = new QStackedWidget(this);
QPushButton * poNextPage = new QPushButton("Next page", this);
this->setWindowTitle("Page: 0");
// switch stacked pages
connect(poNextPage, &QPushButton::clicked,
[=]()
{
int iPageIndex = poMyStackedWidget->currentIndex() + 1;
if (iPageIndex >= poMyStackedWidget->count())
{
poMyStackedWidget->setCurrentIndex(0);
}
else
{
poMyStackedWidget->setCurrentIndex(iPageIndex);
}
// set window title
poMyStackedWidget->setWindowTitle(QString("Page: %1").arg(poMyStackedWidget->currentIndex()));
});
// Connect the signlas so the main window will display the title.
connect(poMyStackedWidget, &QStackedWidget::windowTitleChanged,
this, &MainWindow::setWindowTitle);
// UI layout
poHBtnLayout->addWidget(poNextPage);
poVLayout->addLayout(poHBtnLayout);
poVLayout->addWidget(poMyStackedWidget);
poCentral->setLayout(poVLayout);
// Add dumy pages
poMyStackedWidget->insertWidget(0,new QLabel("First page", this));
poMyStackedWidget->insertWidget(1,new QLabel("Second page", this));
poMyStackedWidget->insertWidget(2,new QLabel("third page", this));
this->setCentralWidget(poCentral);
}
Related
Problem
I'm creating the main window with multiple dock widgets. My current goal is to save the whole layout on exit. Everything works fine until I try to tabify some of my dock widgets using the tabifyDockWidget() method. And now the tabified widgets don't save their positions for some reason.
Example
Here is the minimal reproducible example.
You can check the described behavior by (un)commenting the tabifyDockWidget() line and resizing the dock widgets.
Of course, don't forget to remove the saved settings file to reset the layout to its initial state.
#include "mainwindow.h"
#include <QDockWidget>
#include <QLabel>
#include <QSettings>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
resize(800, 320);
auto centralWidget = new QLabel("Central Widget", this);
centralWidget->setAlignment(Qt::AlignCenter);
centralWidget->setStyleSheet("border: 2px solid black");
setCentralWidget(centralWidget);
auto dockLeft1 = new QDockWidget(this);
auto dockLeft2 = new QDockWidget(this);
auto dockRight = new QDockWidget(this);
dockLeft1->setObjectName("dockLeft1");
dockLeft2->setObjectName("dockLeft2");
dockRight->setObjectName("dockRight");
dockLeft1->setWindowTitle(tr("Left Dock 1"));
dockLeft2->setWindowTitle(tr("Left Dock 2"));
dockRight->setWindowTitle(tr("Right Dock"));
addDockWidget(Qt::LeftDockWidgetArea, dockLeft1);
addDockWidget(Qt::LeftDockWidgetArea, dockLeft2);
addDockWidget(Qt::RightDockWidgetArea, dockRight);
tabifyDockWidget(dockLeft1, dockLeft2);
QSettings settings("foo", "bar");
restoreGeometry(settings.value("geometry").toByteArray());
restoreState(settings.value("state").toByteArray());
}
void MainWindow::closeEvent(QCloseEvent *event)
{
QSettings settings("foo", "bar");
settings.setValue("geometry", saveGeometry());
settings.setValue("state", saveState());
QMainWindow::closeEvent(event);
}
Behavior without tabifyDockWidget()
Resize left and right dock widget.
Close and reopen the application.
The layout settings are properly restored. 👍
Behavior with tabifyDockWidget()
Resize left and right dock widget.
Close and reopen the application.
The restored layout settings are wrong for the left (tabified) dock. 👎
What's the reason?
Is there any proper workaround?
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.
I'm trying to add buttons to a vertical layout in QT.
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
mRootLayout = new QVBoxLayout(this);
setLayout(mRootLayout);
mRootLayout->addWidget(new QPushButton("Button1", this));
mRootLayout->addWidget(new QPushButton("Button2", this));
}
I have 2 problems
1. The buttons are created on top of the menu bar
2. The buttons are not one under the other one.
I'm using a QVBoxLayout.
I think code must be change to:
mRootLayout = new QVBoxLayout(ui->centralWidget);
mRootLayout->addWidget(new QPushButton("Button1", this));
mRootLayout->addWidget(new QPushButton("Button2", this));
It's not necessary do setLayout().
I want to have a QScrollArea inside QGroupBox, so when I add new widgets to group box its size stays the same, but I have scroll bars instead of resizing group box itself.
Here's my code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtCore>
#include <QtGui>
#include <QLayout>
#include <QScrollArea>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGroupBox *box = new QGroupBox(QObject::tr("Example"));
QScrollArea *sa = new QScrollArea;
QGridLayout *gridLayout = new QGridLayout;
QPushButton *b1 = new QPushButton("A");
QPushButton *b2 = new QPushButton("B");
QPushButton *b3 = new QPushButton("C");
QPushButton *b4 = new QPushButton("D");
QPushButton *b5 = new QPushButton("E");
QPushButton *b6 = new QPushButton("F");
QPushButton *b7 = new QPushButton("F");
QPushButton *b8 = new QPushButton("F");
QPushButton *b9 = new QPushButton("F");
// addWidget(*Widget, row, column, rowspan, colspan)
// 0th row
gridLayout->addWidget(b1,0,0,1,1);
gridLayout->addWidget(b2,0,1,1,1);
gridLayout->addWidget(b3,0,2,1,1);
// 1st row
gridLayout->addWidget(b4,1,0,1,1);
// 2nd row with 2-column span
gridLayout->addWidget(b5,2,0,1,2);
// 3rd row with 3-column span
gridLayout->addWidget(b6,3,0,1,3);
gridLayout->addWidget(b7,4,0,1,3);
gridLayout->addWidget(b8,5,0,1,3);
gridLayout->addWidget(b9,6,0,1,3);
box->setLayout(gridLayout);
sa->setWidget(box);
setCentralWidget(sa);
}
MainWindow::~MainWindow()
{
delete ui;
}
What I have now is that every time I add a new QPushButton, QGroupBox resizes, no matther there is a QScrollArea. What should I change to have the behaviour I want? Is it possible?
That's because you are putting the groupbox inside the scroll area. Scroll area doesn't restrict its childrens size.
You should do the opposite, put scrollarea inside group box. Here is how;
QWidget* sw = new QWidget();
sw->setLayout(gridLayout);
sa->setWidget(cont);
QVBoxLayout* bl = new QVBoxLayout(box);
bl->addWidget(sa);
setCentralWidget(box);
Note that if you are using toggle buttons (such as radio button) they will not act as a group. Because technically they are not in the same QGroupBox any more - they are inside the scroll area. You can provide group behavior using a QButtonGroup instance.
I'm trying to find the settings or size policy so that each page in my QToolBox instance only takes up the space needed by its content. I've tried everything I could see in the properties for both the instance and for each of the individual pages.
Am I misconstruing the functionality of QToolBox widget or just missing the right setting?
What I am going for is something similar to the accordion fold type widget in Qt Creator:
I can't seem to get this "Sort" page to take only the size needed to display the button and field.
Unfortunately you can't do that directly because it will span all the available space that the title widgets don't occupy. You can emulate what you want by setting a fixed height on the QToolBox if you know the exact height your page(s). But you do not want to do that in practise.
If you want the behavior you ask for then you need to write your own custom control. It doesn't have to be hard. Use a QVBoxLayout and fill into it items of a custom class, let's call it ToolItem, which is a QWidget with a title (perhaps a button to show/hide) and another QWidget for showing the contents that is either visible or not.
The following very simple example will toggle the visibility of the ToolItem when it is clicked. And only when visible will it occupy any space.
class ToolItem : public QWidget {
public:
ToolItem(const QString &title, QWidget *item) : item(item) {
QVBoxLayout *layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(new QLabel(title));
layout->addWidget(item);
setLayout(layout);
item->setVisible(false);
}
protected:
void mousePressEvent(QMouseEvent *event) {
item->setVisible(!item->isVisible());
}
private:
QWidget *item;
};
class ToolBox : public QWidget {
public:
ToolBox() : layout(new QVBoxLayout) {
setLayout(layout);
}
void addItem(ToolItem *item) {
// Remove last spacer item if present.
int count = layout->count();
if (count > 1) {
layout->removeItem(layout->itemAt(count - 1));
}
// Add item and make sure it stretches the remaining space.
layout->addWidget(item);
layout->addStretch();
}
private:
QVBoxLayout *layout;
};
And simple usage of it:
QWidget *window = new QWidget;
window->setWindowTitle("QToolBox Example");
QListWidget *list = new QListWidget;
list->addItem("One");
list->addItem("Two");
list->addItem("Three");
ToolBox *toolBox = new ToolBox;
toolBox->addItem(new ToolItem("Title 1", new QLabel("Some text here")));
toolBox->addItem(new ToolItem("Title 2", list));
toolBox->addItem(new ToolItem("Title 3", new QLabel("Lorem Ipsum..")));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(toolBox);
window->setLayout(layout);
window->resize(500, 500);
window->show();
You can now tweak it to look like the QToolBox if needed.
Please don't hesitate to ask follow-up questions.
The example shown from Qt Designer may not be using a QToolBox, which behaves more like a stacked tab widget only displaying a single page at a time. The example in Qt Designer appears to be a QTreeWidget with custom drawing or styling.
This is not the complete answer.
I traced down the actual component, it can be included outside designer (kind of). Here is a minimal example showing how to do that (modified from https://github.com/zdenekzc/qtdesigner-integration).
form.h
#ifndef FORM_H
#define FORM_H
#include <QMainWindow>
class FormWindow : public QMainWindow {
Q_OBJECT
public:
explicit FormWindow (QWidget * parent = 0);
};
#endif // FORM_H
form.cc
#include "form.h"
#include <QApplication>
#include <QtDesigner/QtDesigner>
#include <QtDesigner/QDesignerComponents>
FormWindow::FormWindow (QWidget* parent) : QMainWindow (parent) {
QDesignerFormEditorInterface* core = QDesignerComponents::createFormEditor (this);
core->setWidgetBox (QDesignerComponents::createWidgetBox (core, 0));
this->setCentralWidget (core->widgetBox());
}
extern "C" int main (int argc, char * * argv) {
QApplication app (argc, argv);
FormWindow * win = new FormWindow ();
win->show ();
return app.exec();
}
qt-designer.pro
QT += designer
HEADERS = form.h
SOURCES = form.cc
LIBS += -lQt5DesignerComponents
Build it:
mkdir -p build
cd build
qmake-qt5 ../qt5-design.pro
make
./qt5-design
This is obviously not useful by itself unless you want to build a designer but another step towards isolating the actual component.