Switching between windows. Qt Widgets ( 1 widget in memory ) - c++

For example I have 2 widgets and I press button on first widget. I need to delete first widget and create new widget.
How is it possible? I mean some structure for this. I used stackedwidgets, but pages from stackedwidgets located in memory. I need to avoid this.
void Window::on_registrationButton_clicked(){
ui->logWindow->hide();
ui->RegistrWindow->show();
}

As you are going to eliminate the object you can not do it within the same class the object belongs to, you have to do it outside of it, for example in the following code I created a signal that is triggered when the button is pressed, this I have connected it to a lambda function where the new object is created and the object that emits it is eliminated.
class LogWindow: public QWidget{
Q_OBJECT
public:
LogWindow(const QString &text, QWidget *parent=Q_NULLPTR):QWidget(parent){
setLayout(new QVBoxLayout);
btn = new QPushButton(text, this);
layout()->addWidget(btn);
connect(btn, &QPushButton::clicked, this, &LogWindow::customSignal);
}
signals:
void customSignal();
private:
QPushButton *btn;
};
class RegWindow : public QWidget{
[...]
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LogWindow *log= new LogWindow("LogWindow");
RegWindow *reg;
QObject::connect(log, &LogWindow::customSignal, [&reg, &log](){
reg = new RegWindow("RegWindow");
reg->show();
log->deleteLater();
});
log->show();
return a.exec();
}
#include "main.moc"
The complete example can be found in the following link

Related

It it right way to user a global QObject for cross signal/slot forward

My situation is, a big Qt project with many QWidget communication requirement.
For example, I've a QPushButton B and a QLabel L, I need to click thd button B to show some text on label L or hide it, etc. But the problem is neither of them can get each other's object pointer, because both of them located in a deep QWidget tree, maybe their grandgrandgrand parent widget was sibling, what ever.
So my option, is creating a global unique QObject, just for singal/slot forwad,like this:
class GlobalForward: public QObject
{
Q_OBJECT
public:
GlobalForward():QObject(null) {}
signal:
void SigForwardButton(bool toggle);
}
GlobalForward* gForwardObj;
int main(int argc, char* argv[])
{
QApplication app(argc, argv[]);
gForwardObj = new GlobalForward();
QWidget w;
QPushButton* button = new QPushButton(&w);
QWidget m;
QLabel* label = new QLabel(&m);
w.show();
m.show();
connect(button, &QPushButton::clicked, gForwardObj, &GlobalForward::SigForwardButton);
connect(gForwardObj, &GlobalForward::SigForwardButton, label, &QWidget::hide);
return app.exec();
}
Actually, the button and the label are so faraway that they cannot see each other. I want to use GlobalForward to concat the singnal to make it work . Further more, it can forwad QEvent silmiarly.
What I want to know is, is this way properly solved my problem, and what's the disadvantage of it. Also, any better solution will be appropriate, thanks.

How to call created widget object in other widgets in QT [duplicate]

This question already exists:
How to create object widget in other widgets in QT
Closed 7 years ago.
In my application I'm having three widgets, I created the objects for all widgets in main() function, but I don't know how to call the created objects in other widgets, please guide me, I create the objects like this:
#include <QtGui/QApplication>
#include "widget.h"
#include "one.h"
#include "two.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget *w = new Widget();
One *one = new One();
Two *two = new Two();
w->show();
return a.exec();
}
How can created objects call other widgets?
You're not supposed to 'call' them, but to connect them through the Qt signal slot mechanism:
class One : public QObject {... boilerplate omitted
public slots:
void slotWithVoid(){ emit slotWithInt(1); }
signals:
void signalWithInt(int); // filled in by Qt moc
};
// note: give your widgets an owner
auto *w = new QButton(&app);
auto *one = new One(&app);
auto *two = new Two(&app);
connect(w, &QButton::click,
one, &One::slotWithVoid);
connect(one, &One::signalWithInt,
two, &Two::slotWithInt);
Now when something happens (e.g. a button click), Qt event system will take care that your objects are called in the right order, from the right thread, safely, etc...

How to add a Menu Bar into a Window Frame? [QT with C++]

I'm a beginner in C++ and I started learning how to use QT components through code at MVS IDE. I still don't know if that was the best option to begin, but since I'm a java programmer, I made the path I made with Java (Swing components). So, my problem is, how to comunicate two class of my code, since in one I made the window frame and in the other I made my menu bar?
In java I would make something like:
JFrame frame = new JFrame();
JMenu menu = new JMenu();
frame.add(menu);
Anyway, This is my code:
#include "Header.h"
class MainWindow{
private:
QWidget *widget;
public:
void buildWindow(QApplication& app){
widget = app.desktop();
QMainWindow *main_window = new QMainWindow();
QWidget *mainWid = new QWidget(main_window);
MyMenuBar myMenuBar(mainWid);
main_window->setWindowState(mainWid->windowState() | Qt::WindowMaximized);
main_window->setWindowTitle("QT Trainning");
main_window->show();
}
};
class MyMenuBar:QMainWindow {
public:
MyMenuBar(QWidget* mainWid){
QAction *quit = new QAction("&Quit", this);
QMenuBar *menu = new QMenuBar(mainWid);
QMenu *file;
menu->addMenu(file);
file = menuBar()->addMenu("&File");
file->addAction(quit);
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow frame;
frame.buildWindow(app);
return app.exec();
}
I tryed to create an Instance of MenuBar inside the Window class but wans't so helpfull and to be honest most of the materials I found to deal with QT interface they supose that you are using the QT GUI...Any tips about how to solve the problem or what should I really do to practice C++??
Thanks in advance
You should specify access specifier for inheritance,otherwise default mode is public.
Also, if you are going to have all the classes in the same file the ordering is important(i think). In your case MyMenuBar should come before MainWindow. So, it is a better practice to have different components in different headers and then include them as necessary.
Here is the code for the case where you need two classes separately:
class TrainingMenu:public QMainWindow {
public:
TrainingMenu(QMenuBar *menubar){
QAction *quit = new QAction("&Quit", menubar);
QMenu *file;
file = menubar->addMenu("&File");
file->addAction(quit);
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
}
};
class MainWindows:public QMainWindow{
private:
TrainingMenu* _menu;
public:
MainWindows(QMainWindow *parent = 0):QMainWindow(parent) {
_menu=new TrainingMenu(MainWindows::menuBar());
this->setWindowTitle("Qt training");
this->setWindowState(Qt::WindowMaximized);
this->show();
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindows window;
return app.exec();
}
This example should be good enough. You do the following:
Create a QMenu with the top widget as a parent
Add submenu QMenu instances to the root level menu

How to get which QradioButton invoke the SLOT

I create several QradioButton and connect to the same SLOT. In the slot, I want to know which QradioButton invoke the slot and do the related action. I found there is a way by using qobject_cast and QObject::sender(), but it seems not work. Here is the code:
header file:
class dialoginput : public QDialog
{
Q_OBJECT
public:
dialoginput(QWidget *parent = 0);
QRadioButton *radio1;
QRadioButton *radio2;
QRadioButton *radio3;
private slots:
void setText_2();
private:
QLabel *label_0_0;
QLabel *label_1;
};
main file:
dialoginput::dialoginput(QWidget *parent): QDialog(parent){
label_0_0 = new QLabel("label_1:");
label_1 = new QLabel;
QWidget *window = new QWidget;
QVBoxLayout *windowLayout = new QVBoxLayout;
QGroupBox *box = new QGroupBox("Display Type");
radio1 = new QRadioButton("3");
radio2 = new QRadioButton("5");
radio3 = new QRadioButton("9");
QVBoxLayout *radioLayout = new QVBoxLayout;
connect(radio1,SIGNAL(clicked()),this,SLOT(setText_2()));
connect(radio2,SIGNAL(clicked()),this,SLOT(setText_2()));
connect(radio3,SIGNAL(clicked()),this,SLOT(setText_2()));
radioLayout->addWidget(radio1);
radioLayout->addWidget(radio2);
radioLayout->addWidget(radio3);
box->setLayout(radioLayout);
windowLayout->addWidget(box);
windowLayout->addWidget(label_0_0);
windowLayout->addWidget(label_1);
window->setLayout(windowLayout);
window->show();
}
void dialoginput::setText_2(){
QObject *object = QObject::sender();
QRadioButton* pbtn = qobject_cast<QRadioButton*>(object);
QString name = pbtn->objectName();
label_1->setText(name);
if(!QString::compare(name, "3")){
}
else if(!QString::compare(name, "5")){
}
else if(!QString::compare(name, "9")){
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
dialoginput *input = new dialoginput();
return a.exec();
}
Even though using the sender() method solves your problem, i do not recommend using it. The problem is, signals and slots are designed to seperate the emitter and the receiver. A receiver does not need to know which objects, even what types of objects can trigger its slot. When you use sender(), you are relying on the fact that the receiver has knowledge of all of the objects that triggers its slot. What if this changes in the future?
You should take a look at QSignalMapper, it is designed specifically for this kind of needs. There are good examples about it in the docs.
You could create separate wrapper slots for each radio button, which then passes the information to the function you want to call. Something like this: -
class dialoginput : public QDialog
{
Q_OBJECT
public:
QRadioButton *radio1;
QRadioButton *radio2;
QRadioButton *radio3;
private slots:
void Radio1Selected() { setText_2(1); }
void Radio2Selected() { setText_2(2); }
void Radio3Selected() { setText_2(3); }
private:
void setText_2(int id);
};
Then connect each radio button: -
connect(radio1,SIGNAL(clicked()),this,SLOT(Radio1Selected()));
connect(radio2,SIGNAL(clicked()),this,SLOT(Radio2Selected()));
connect(radio3,SIGNAL(clicked()),this,SLOT(Radio3Selected()));
Now when setText_2 is called, the id will represent the selected radio button.
You are getting sender Object correctly on setText_2(), But you are not setting objectName property of radio1, radio2 and radio3. Please use "setObjectName( )" API.
write single argument custom signal for radiobuttons and then emit it .catch that argument in slot.check for corresponding radio button
You could also create a QButtonGroup and use lambda expression (c++11)
class dialoginput : public QDialog
{
Q_OBJECT
public:
private:
void setText_2(int id);
QRadioButton *radio1;
QRadioButton *radio2;
QRadioButton *radio3;
QButtonGroup _btnGroup;
};
After add the 3 QRadioButton to the QButtonGroup
_btnGroup.addButton(radio1, 1);
_btnGroup.addButton(radio2, 2);
_btnGroup.addButton(radio3, 3);
connect(&_btnGroup, static_cast<void(QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), [=](int id){
setText_2(id);});

How button onClick works

I am a bit confused with Qt's onClick handling. I have a class which looks like this:
class DatabaseManager : public QObject
{
Q_OBJECT;
private:
QSqlDatabase db;
public slots:
bool openDB(const QString& path);
};
And I have a class which handles the click on the button:
Click::Click(QWidget *parent) : QWidget(parent){
QPushButton *create = new QPushButton("Create database", this);
create->setGeometry(50,100,100,100);
connect(create, SIGNAL(clicked()), this, SLOT(openDB("/home/peter/database.db")));
}
main.cpp
int main(int argc,char **argv){
QApplication *app = new QApplication(argc, argv);
QPushButton btn;
DatabaseManager db;
btn.move(300,300);
btn.resize(250,250);
btn.setWindowTitle("Dibli");
btn.show();
return app->exec();
}
How could I tell to the click handler, that I want to use a specific DatabaseManager object's openDB function? Because it doesn't create the file, if I click on it.
I've updated the code.
assuming your Click class derives from QObject, you should add a slot
public slots:
void onClick() { openDB("/home/peter/database.db"); }
and connect that:
connect(create, SIGNAL(clicked()), this, SLOT(onClick()))
edit Since you show more code now, here is a different hint. Change main like
int main(int argc,char **argv){
QApplication *app = new QApplication(argc, argv);
QPushButton btn;
DatabaseManager db;
db.path = "/home/peter/database.db";
QObject::connect(&btn, SIGNAL(clicked()), &db, SLOT(openDB()));
btn.move(300,300);
btn.resize(250,250);
btn.setWindowTitle("Dibli");
btn.show();
return app->exec();
}
and
class DatabaseManager : public QObject
{
Q_OBJECT;
private:
QSqlDatabase db;
public:
QString path;
public slots:
bool openDB();
};
Note I added a member variable (db.path) to DatabaseManager, and changed the slot openDB removing the argument.
That's because the button' signal cannot provide the string. The easier way then is to make it available in the class.
You cannot call the specific argument instance in the connect function call.
connect is processed by the MOC - meta object compiler - and add some magick to all object that has the macro Q_OBJECT. You have to call a function inside the connect in which you specify only the argument it will receive. (And if they are non qt-object you have to register them with qRegisterMetaType<MyDataType>("MyDataType"); but this is a different story).
So, remember, every time call:
connect(sender, SIGNAL( event() ),
receiver, SLOT( onEvent() ))
and then:
void onEvent() {
mycomplexoperation( ... )
}
EDIT:
thank to Riateche comment, I have to specify that you need qRegisterMetaType<MyDataType>("MyDataType"); with all object not listed in this list. QString not inherits from QObject but could be used in signal/slot system without registration. and thanks to Frank Osterfeld comment I have to add that only for queued signal/slot connections the registration is needed (I didn't know that)
thankd to