In order to replicate the problem I have I prepared a small verifiable example.
I have 2 QStackedWidgets inside a QGroupBox with a couple more components as shown below:
I created another widget called QBoxForm which carries a QComboBox only.
This last widget should appear on the QStackedWidget on the left as soon as the QCheckbox is ticked.
The QStackedWidget receive something because it becomes bigger but it does not show the QComboBox. How to make sure that a component is fully visible inside a QStackedWidget?
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
mCombo = new CBoxForm;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_checkBox_toggled(bool checked)
{
if(ui->checkBox->isChecked())
{
if(checked)
{
ui->stackedWidget->insertWidget(0, mCombo);
ui->stackedWidget->show();
}
}
if(!ui->checkBox->isChecked())
{
ui->stackedWidget->removeWidget(mCombo);
}
}
mainwindow.h
#include <QMainWindow>
#include "cboxform.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_checkBox_toggled(bool checked);
private:
Ui::MainWindow *ui;
CBoxForm *mCombo;
};
Lastly the additional combobox handled by another widget:
cboxform.h
#include <QWidget>
namespace Ui {
class CBoxForm;
}
class CBoxForm : public QWidget
{
Q_OBJECT
public:
explicit CBoxForm(QWidget *parent = nullptr);
~CBoxForm();
private:
Ui::CBoxForm *ui;
};
cboxform.cpp
CBoxForm::CBoxForm(QWidget *parent) :
QWidget(parent),
ui(new Ui::CBoxForm)
{
ui->setupUi(this);
}
CBoxForm::~CBoxForm()
{
delete ui;
}
What I have done so far:
1) I followed the official documentation and applied the method insertWidget() as advised. In fact here is what I have done exactly. This part works and can be confirmed by the fact that the QStackedWidget become larger as I check the box.
Also consequently I remove the widget in a similar way applying removeWidget() method available in the official documentation.
Everything seems to follow the correct functioning, but the only missing part is that I don't understand why the QComboBox does not appear on the QStackedWidget as I followed precisely the official documentation.
Any idea on what I might be missing or forgot to include in the above code?
Thanks for pointing in the right direction for solving this problem.
You should add ui->stackedWidget->setCurrentIndex(0) after ui->stackedWidget->insertWidget(0, mCombo) to make it visible.
Related
I am new to Qt and am have to make a GUI having multiple windows for this I found QStackedWidget class using Qt designer tools.
I added QStackedWidget using add new->Qt designer form class->Qstackwidget
after that I created an object of this class in my main window
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<stackedwidget.h>
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
StackedWidget *stk; };
#endif // MAINWINDOW_H
then i tried to display StackedWidget by:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
stk = new StackedWidget(this);
stk->show();
}
But stackwidget is not opening .
Can someone tell me what am I doing wrong and how to implement QStackedWidget GUI using designer tools?
The QStackedWidget class provides a stack of widgets where only one widget is visible at a time.
You are new to Qt so I suggest you to using Qt Designer:
You can drag&drop StackedWidget to your form, customize it then use arrows to go to the next page and work on it too.
StackedWidget is like a vector you can access them via indexes.
ui->stackedWidget->setCurrentIndex(1);
I have a QT application and I'm trying to have a button in one of my windows open another window.
The way I have done my window objects so far in the main is like this:
Website control;
control.show();
This displays my first window fine and if I declare my other window in a similar way that also displays at runtime, although this is not what I want
Then in a separate header file:
class Website: public QWidget, public Ui::Website
{
public:
Website();
}
Then in the corresponding Cpp file I have:
Website::Website()
{
setupUi(this);
}
Now all this works and have added a custom slot so that when I click a button it triggers a slot in my other cpp file. The issue is I'm not sure how to show my other window as I declare them in my main so can't access them to do .show()?
Any help would be appreciated, I'm fairly new to C++ and QT
It's not clear to me what you want to do. But i might understand your struggle as I had one myself the first time approaching this framework.
So let's say you have a MainWindow class that controls the main Window view. Than you want to create a second window controlled by Website class.
You then want to connect the two classes so that when you click a button on the Website window something happens in the MainWindow.
I made a simple example for you that is also on GitHub:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "website.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void changeText();
private slots:
void on_openButton_clicked();
private:
Ui::MainWindow *ui;
//You want to keep a pointer to a new Website window
Website* webWindow;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::changeText()
{
ui->text->setText("New Text");
delete webWindow;
}
void MainWindow::on_openButton_clicked()
{
webWindow = new Website();
QObject::connect(webWindow, SIGNAL(buttonPressed()), this, SLOT(changeText()));
webWindow->show();
}
website.h
#ifndef WEBSITE_H
#define WEBSITE_H
#include <QDialog>
namespace Ui {
class Website;
}
class Website : public QDialog
{
Q_OBJECT
public:
explicit Website(QWidget *parent = 0);
~Website();
signals:
void buttonPressed();
private slots:
void on_changeButton_clicked();
private:
Ui::Website *ui;
};
#endif // WEBSITE_H
website.cpp
#include "website.h"
#include "ui_website.h"
Website::Website(QWidget *parent) :
QDialog(parent),
ui(new Ui::Website)
{
ui->setupUi(this);
}
Website::~Website()
{
delete ui;
}
void Website::on_changeButton_clicked()
{
emit buttonPressed();
}
Project composed:
SOURCES += main.cpp\
mainwindow.cpp \
website.cpp
HEADERS += mainwindow.h \
website.h
FORMS += mainwindow.ui \
website.ui
Consider the Uis to be composed:
Main Window: a label called "text" and a button called "openButton"
Website Window: a button called "changeButton"
So the keypoints are the connections between signals and slots and the management of windows pointers or references.
Edit: I removed the destructor from the slot. But now I have memory leaking problems. Each new window that I open occupies some memory,and when I close it,the memory stays occupied
When I execute the program,and open new windows, they are opened normally. When I close any of them, the whole application crashes (not only that specific window),and I get the crash error.
What am I doing wrong?
mainWindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class QHBoxLayout;
class QTextEdit;
class QWidget;
class QDialog;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void closeWindow();
void newWindow();
private:
Ui::MainWindow *ui;
MainWindow *tempMainWindow;
QHBoxLayout * mainLyt;
QTextEdit *txtEdit;
QWidget *mainWidget;
};
#endif // MAINWINDOW_H
mainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QWidget>
#include <QHBoxLayout>
#include <QTextEdit>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mainWidget=new QWidget();
mainLyt=new QHBoxLayout();
txtEdit=new QTextEdit();
mainLyt->addWidget(txtEdit);
mainWidget->setLayout(mainLyt);
setCentralWidget(mainWidget);
connect(ui->actionExit,SIGNAL(triggered()),this,SLOT(closeWindow()));
connect(ui->actionNew,SIGNAL(triggered()),this,SLOT(newWindow()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::closeWindow()
{
this->close();
delete txtEdit;
delete mainLyt;
delete mainWidget;
this->~MainWindow();
}
void MainWindow::newWindow()
{
tempMainWindow=new MainWindow(this);
tempMainWindow->show();
}
If you pass to QWidget(), QHBoxLayout() and QTextEdit() also this (which is the parent), at the delection of the MainWindow Qt will delete for you the ui and all the additional widgets yur defined in the construstor. In this way you can avoid to call closeWindow() method.
delete ui is also not necessary.
ui->setupUi(this);
mainWidget = new QWidget(this);
mainLyt = new QHBoxLayout(this);
txtEdit = new QTextEdit(this);
I'm trying to make basic text editor,and when New is triggered, it should open a new window for new text document. Is there some better way to do this?
Yes. It's called a factory, and it can be a static method as it doesn't operate on any object. You can call it from a slot, of course.
I imagine you'll need to pass a file name to the newly created window - that could be an argument to the factory method and the factory slot. If the "new" window is empty, then this is not an issue.
Other issues:
There is no reason to keep the mainWidget member: it is always available as centralWidget().
There's also no reason to have the members other than ui as pointers. It is actually a premature pessimization - it will waste a bit more heap memory.
You don't need a layout for the central widget if it has no child widgets. The QTextEdit instance itself can be the central widget.
The ui instance should be retained using a smart pointer. This makes the destructor completely compiler-generated (it has an empty body).
You don't need anything fancy in the closeWindow slot. Simply delete the instance!
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow * createWindow();
void setFileName(const QString & fileName);
public slots:
void closeWindow();
void newWindow();
private:
QScopedPointer<Ui::MainWindow> const ui;
QTextEdit m_txtEdit;
};
void MainWindow::newWindow() {
createWindow()->show();
}
void MainWindow::closeWindow() {
deleteLater();
}
MainWindow * MainWindow::createWindow(QWidget * parent) {
return new MainWindow(parent);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setCentralWidget(&m_txtEdit);
connect(ui->actionExit, SIGNAL(triggered()), SLOT(closeWindow()));
connect(ui->actionNew, SIGNAL(triggered()), SLOT(newWindow()));
}
MainWindow::~MainWindow()
{}
Let us see your code:
this->close();
delete txtEdit;
delete mainLyt;
delete mainWidget;
this->~MainWindow();
You are trying to destroy them and for the next open you allocate them almost the same way.
What you achieve here is basically performance penalty. I would suggest to hide, modify, and so on the unwanted items instead.
I have a subclassed QToolButton(in a toolbar added to mainwindow with addToolBar() ) that works as a "drag and drop button" dynamically generating subclassed QWidgets( which contain just 1 QTextEdit) on the central Widget of a QMainWindow which is a QWidget. The drag and drop works fine.
However unless the user accesses them in a very specific order, only one of the QTextEdit widgets stays accessible after which the others do not respond to mouse clicks and the whole central Widget is "stuck".
By that i mean any other widgets who are children of the central widget are unresponsive.
Why is that? Does it have something to do with focus policies possibly?
EDIT:
Thanks to SpongeBobs comment, where he suggested to test plain QTextEdit generating instead of a whole custom class, we know that the error is somewhere in the custom class ideafield. So how do I change it to get the appropriate behavior?
#ifndef IDEAFIELD_H
#define IDEAFIELD_H
#include <QWidget>
#include <QTextEdit>
#include <QFrame>
class IdeaField : public QWidget
{
Q_OBJECT
public:
explicit IdeaField(QWidget *parent = 0);
void move_all(int,int);
void move_all(QPoint);
QTextEdit *textField;
signals:
public slots:
};
code:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setStyleSheet("background-color: white;");
ideaPlane = new IdeaPlane(this);
setCentralWidget(ideaPlane);
MainWindow::createToolBars();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::createToolBars()
{
QToolBar * topToolBar = addToolBar(tr("Title"));
dragIdeaButton = new dragButton(this);
topToolBar->addWidget(dragIdeaButton);
}
ideafield.cpp: subclassed QTextEdit:
#include "ideafield.h"
IdeaField::IdeaField(QWidget *parent):QWidget(parent)
{
textField = new QTextEdit(this);
textField->setFrameShape(QFrame::StyledPanel);
textField->setPlainText(tr("TEST TEXT\nHURRAY!"));
}
void IdeaField::move_all(int x,int y)
{
textField->move(x,y);
}
void IdeaField::move_all(QPoint point)
{
textField->move(point);
}
I'm trying to make a simple program consisting of a button and a label. When the button is pressed, it should change the label text to whatever is in a QString variable inside the program. Here's my code so far:
This is my widget.h file:
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
private:
Ui::WidgetClass *ui;
QString test;
private slots:
void myclicked();
};
And here's the implementation of the Widget class:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent), ui(new Ui::WidgetClass)
{
ui->setupUi(this);
test = "hello world";
connect(ui->pushButton, SIGNAL(clicked()), ui->label, SLOT(myclicked()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::myclicked(){
ui->label->setText(test);
}
It runs but when the button is clicked, nothing happens. What am I doing wrong?
Edit: after i got it working, the text in the label was larger than the label itself, so the text got clipped. I fixed it by adding ui->label->adjustSize() to the definition of myclicked().
You are connecting the signal to the wrong object. myclicked() is not a slot of QLabel, it is a slot of your Widget class. The connection string should be:
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(myclicked()));
Take a look at the console output of your program. There should be an error message saying something like:
Error connecting clicked() to
myclicked(): No such slot defined in QLabel