Dynamic cast in class hierarchy with templates - c++

in my project if I define base class Base_Dialog as non template and then try to assign 'caller' in already_exists_ it works in the way expected but if I make Base_Dialog as a template class then the algorithm 'already_exists_' (unchanged) will not work and caller will not change (this is especially intriguing that the algorithm is unchanged and yet once works and other time it doesn't):
//This is minimal example (I know it's somewhat longer than usual but in order to show what I mean it needs to be this length)
MAIN_DIALOG_HPP
#ifndef MAIN_DIALOG_HPP
#define MAIN_DIALOG_HPP
#include <QSet>
#include <QtDebug>
#include "Base_Dialog.hpp"
#include "ui_Main_Dialog.h"
#include "_1Dialog.hpp"
#include "_2Dialog.hpp"
/*The following approach will not work*/
class Main_Dialog : public Base_Dialog<Ui::Main_Dialog>
{
/*but if I would do as below (changing Base_Dialog to non-template) it will work:*/
//class Main_Dialog : public QDialog, private Ui::Main_Dialog, public Base_Dialog
Q_OBJECT
QSet<QDialog*>* dialogs_;
private:
template<class Dialog,class Caller>
bool already_created_(Caller*const&, QDialog*& already_exists);
template<class Dialog,class Caller, class Parent>
QDialog* create_(Caller*const&,Parent*const&);
public:
explicit Main_Dialog(QWidget *parent = 0);
template<class Dialog,class Caller>
QDialog* get_dialog(Caller*const& caller);
public slots:
void _1clicked()
{
this->hide();
get_dialog<_1Dialog>(this)->show();
}
void _2clicked()
{
this->hide();
get_dialog<_2Dialog>(this)->show();
}
};
template<class Dialog,class Caller>
bool Main_Dialog::already_created_(Caller*const& caller,QDialog*& already_exists)
{/*the already_exists is introduced here in order to remove repetions of code and
searching*/
auto beg = dialogs_->begin();
auto end = dialogs_->end();
while(beg != end)
{
if(dynamic_cast<Dialog*>(*beg))
{
already_exists = *beg;
static_cast<Base_Dialog*>(already_exists)->set_caller(caller);
return true;
}
++beg;
}
return false;
}
template<class Dialog,class Caller, class Parent>
QDialog* Main_Dialog::create_(Caller *const&caller, Parent *const&parent)
{
return (*dialogs_->insert(new Dialog(this,caller,parent)));
}
template<class Dialog,class Caller>
QDialog* Main_Dialog::get_dialog(Caller *const&caller)
{
QDialog* already_exists = nullptr;
if (already_created_<Dialog>(caller,already_exists))
{
return already_exists;
}
else
{
return create_<Dialog>(caller,this);
}
}
Main_Dialog::Main_Dialog(QWidget *parent) :
Base_Dialog<Ui::Main_Dialog>(this,this,parent),dialogs_(new QSet<QDialog*>)
{
setupUi(this);
}
#endif // MAIN_DIALOG_HPP
BASE_DIALOG_HPP
#ifndef BASE_DIALOG_HPP
#define BASE_DIALOG_HPP
#include <QDialog>
#include <QString>
class Main_Dialog;
template<class Ui_Dialog>
class Base_Dialog : public QDialog, protected Ui_Dialog
{
// Q_OBJECT //no signals/slots
protected:
Main_Dialog* main_dlg_;
QDialog* caller_;
public:
Base_Dialog(Main_Dialog *const &main_dlg, QDialog *const&caller, QWidget *parent = nullptr);
QDialog* set_caller(QDialog *const&);
QDialog* clear_caller();
Main_Dialog* clear_main_dlg();
};
/*----------------*/
//#include "Main_Dialog.hpp"
template<class Ui_Dialog>
Base_Dialog<Ui_Dialog>::Base_Dialog(Main_Dialog *const&main_dlg,QDialog *const&caller, QWidget *parent):
QDialog(parent),
main_dlg_(main_dlg),
caller_(caller)
{
//setupUi(this);
}
#include <QtDebug>
template<class Ui_Dialog>
QDialog* Base_Dialog<Ui_Dialog>::set_caller(QDialog *const&new_caller)
{
QDialog* old_caller = caller_;
caller_ = new_caller;
return old_caller;
}
#endif
_1DIALOG_HPP
#ifndef _1DIALOG_HPP
#define _1DIALOG_HPP
#include "Base_Dialog.hpp"
#include "ui__1Dialog.h"
class Main_Dialog;
class _1Dialog : public Base_Dialog<Ui::_1Dialog>
{
Q_OBJECT
public:
explicit _1Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent = 0);
private slots:
void _2clicked();
void caller_clicked();
void main_clicked();
};
#endif // _1DIALOG_HPP
_1Dialog cpp
//_1Dialog cpp
#include "_1Dialog.hpp"
#include "_2Dialog.hpp"
#include "Main_Dialog.hpp"
_1Dialog::_1Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent) :
Base_Dialog<Ui::_1Dialog>(main_dlg,caller,parent)
{
setupUi(this);
}
void _1Dialog::_2clicked()
{
this->hide();
main_dlg_->get_dialog<_2Dialog>(this)->show();
}
void _1Dialog::caller_clicked()
{
this->hide();
caller_->show();
}
void _1Dialog::main_clicked()
{
this->hide();
main_dlg_->show();
}
_2DIALOG_HPP
#ifndef _2DIALOG_HPP
#define _2DIALOG_HPP
#include "Base_Dialog.hpp"
#include "ui__2Dialog.h"
class Main_Dialog;
class _2Dialog : public Base_Dialog<Ui::_2Dialog>//,private Ui::_2Dialog
{
Q_OBJECT
private:
public:
explicit _2Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent = 0);
private slots:
void _1clicked();
void caller_clicked();
void main_clicked();
};
#endif // _2DIALOG_HPP
_2Dialog cpp
//_2Dialog cpp
#include "_2Dialog.hpp"
#include "_1Dialog.hpp"
#include "Main_Dialog.hpp"
_2Dialog::_2Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent) :
Base_Dialog<Ui::_2Dialog>(main_dlg,caller,parent)
{
setupUi(this);
}
void _2Dialog::_1clicked()
{
this->hide();
main_dlg_->get_dialog<_1Dialog>(this)->show();
}
void _2Dialog::caller_clicked()
{
this->hide();
caller_->show();
}
void _2Dialog::main_clicked()
{
this->hide();
main_dlg_->show();
}
Why is this behavior? Algorithm is unchanged and yet once it assigns correctly and the other time it doesn't?

In already_exists_ change line:
static_cast<Base_Dialog*>(already_exists)->set_caller(caller);
to:
static_cast<Dialog*>(already_exists)->set_caller(caller);
and add virtual inheritance for QDialog in Base_Dialog
#sehe, I want to thank you for pointing me into right direction, which allow me to resolve this problem. Great thanks, +1;

Related

setWindowState from QMainWindow from QWidget

I have a QMainWindow Application which also includes an QStackedWidget.
The pages of the QstackedWidget are promoted to ui widgets for example heating_widget.ui
If I use a button slot on my QMainWindow I can use this to get my application to fullscreen:
void SmartHome::on_fullscreen_on_clicked()
{
SmartHome::setWindowState(Qt::WindowFullScreen);
}
But how can I do this from a button which is in the heating_widget.cpp file?
Using:
void heating_widget::on_fullscreen_on_clicked()
{
SmartHome::setWindowState(Qt::WindowFullScreen);
}
obviously doesn't work and throws this error at me:
cannot call member function 'void
QWidget::setWindowState(Qt::WindowStates)' without object
SmartHome::setWindowState(Qt::WindowFullScreen);
I know this has something to do with parent() but I can't get it to work.
Do you have any idea?
My smarthome.h file:
#ifndef SMARTHOME_H
#define SMARTHOME_H
#include <QTime>
#include <QMainWindow>
namespace Ui {
class SmartHome;
}
class SmartHome : public QMainWindow
{
Q_OBJECT
public:
explicit SmartHome(QWidget *parent = 0);
~SmartHome();
private slots:
void on_Info_Button_clicked();
void on_News_Button_clicked();
void on_Heating_clicked();
void timerslot();
void on_Config_clicked();
void on_About_clicked();
public slots:
void setFullscreen();
private:
Ui::SmartHome *ui;
QTimer* myTimer;
};
#endif // SMARTHOME_H
My heating_widget.h :
#ifndef HEATING_WIDGET_H
#define HEATING_WIDGET_H
#include "smarthome.h"
#include <QWidget>
namespace Ui {
class heating_widget;
class SmartHome;
}
class heating_widget : public QWidget
{
Q_OBJECT
public:
explicit heating_widget(QWidget *parent = 0);
~heating_widget();
private slots:
void on_fullscreen_on_clicked();
private:
Ui::heating_widget *ui;
};
#endif // HEATING_WIDGET_H
and my heating.widget.cpp:
#include "heating_widget.h"
#include "ui_heating_widget.h"
#include "smarthome.h"
#include "iostream"
heating_widget::heating_widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::heating_widget)
{
ui->setupUi(this);
QObject::connect(ui->fullscreen_on, SIGNAL(clicked()), this , SLOT(SmartHome::setFullscreen()));
}
heating_widget::~heating_widget()
{
delete ui;
}
void heating_widget::on_fullscreen_on_clicked()
{
parentWidget()->setWindowState(Qt::WindowFullScreen);
std::cout<<"clicked"<<std::endl;
}
I would do it in the following way:
void heating_widget::on_fullscreen_on_clicked()
{
foreach(QWidget *widget, QApplication::topLevelWidgets()) {
if (auto mainWindow = qobject_cast<SmartHome *>(widget)) {
mainWindow->setWindowState(Qt::WindowFullScreen);
}
}
}
The idea is finding your main window among application top level widgets and change its state. This code can be called from anywhere in your application regardless of the windows hierarchy.

cannot access staticmetaobject

I cannot access staticmetaobject and I dont know why. I would need some help.
Here is the code
The two errors are:
staticMetaObject is not a member of MainWIndow*
I feel like it has something to do with the list, but I'm not sure.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "form.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Form<MainWindow*>* form;
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*qDebug() << MainWindow::staticMetaObject.className();
if (QString(MainWindow::staticMetaObject.className()) == QString("MainWindow")) {
qDebug() << "test";
}*/
form = new Form<MainWindow*>(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
form->myFunc();
}
form.h
#ifndef FORM_H
#define FORM_H
#include <QObject>
#include <QDebug>
class FormBase : public QObject
{
Q_OBJECT
public:
FormBase() {}
};
template <typename T>
class Form : public FormBase, public QList<T>
{
public:
Form(T a)
{
QList<T>::append(a);
}
void myFunc()
{
qDebug() << T::staticMetaObject.className();
}
};
#endif // FORM_H
You are getting you types confused.
You want T to be MainWindow so that you can do
T::staticMetaObject.className()
That means you want a QList<T*>. You derive from that so you can just call
append(a);
The following code compiles fine:
class FormBase : public QObject
{
Q_OBJECT
public:
FormBase() {}
};
template <typename T>
class Form : public FormBase, public QList<T*>
{
public:
Form( T* a )
{
append( a );
}
void myFunc()
{
qDebug() << T::staticMetaObject.className();
}
};
class MainWindow:
public QMainWindow
{
MainWindow()
{
form = new Form<MainWindow>( this );
}
FormBase* form;
};

error: expected class-name before '{' token { ^

Hello I keep getting this
error: expected class-name before '{' token
{
^ line 15
what does this error mean exactly? Im attempting to inherit the controller class that has a function that I need to call in form1's cpp.
#ifndef FORM1_H
#define FORM1_H
#include <QDialog>
#include "controller.h"
namespace Ui {
class form1 ;
}
class form1 : public QDialog, public controller
{
Q_OBJECT
public:
explicit form1(QWidget *parent = 0);
~form1();
private slots:
void on_pushButton_clicked();
private:
Ui::form1 *ui;
};
#endif // FORM1_H
the controller class
#include "controller.h"
#include "ui_controller.h"
controller::controller(QWidget *parent) :
QWidget(parent),
ui(new Ui::controller) {
ui->setupUi(this);
show(1); }
void controller::show(int x) {
if(x==1)
{
myform1 = new form1(this);
myform1->show();
}
if(x==2)
{
myform2 = new form2(this);
myform2->show();
}
if(x==3)
{
myform3 = new form3(this);
myform3->show();
} }
controller::~controller() {
delete ui; }
controller.h:
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QWidget>
#include <form1.h>
#include <form2.h>
#include <form3.h>
namespace Ui {
class controller;
}
class controller : public QWidget
{
Q_OBJECT
public:
form1 * myform1;
form2 * myform2;
form3 * myform3;
void show(int x);
explicit controller(QWidget *parent = 0);
~controller();
private:
Ui::controller *ui;
};
#endif // CONTROLLER_H
My guess is you have a circular include issue, meaning controller.h includes, either directly or indirectly, form1.h.
EDIT: Change the include I was talking about to a forward declaration - you don't need the full definition of form1:
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QWidget>
class form1;
class form2;
class form3;
namespace Ui {
class controller;
}
class controller : public QWidget
{
//.................
//.................

QString::toInt() fails when converting a QString from another class

I want to convert a QString from another class toInt, but it seams to fail because the result is 0 while it should be 5 and the rest of the code works.
Because I am new to C/Qt and find classes a bit confusing, I think I have done something wrong with my classes.
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
MyClass tmp;
int myNumber = tmp.m_replyStr.toInt();
ui->lcdNumber->display(myNumber);
}
MyClass::MyClass()
{
m_manager = new QNetworkAccessManager(this);
connect( m_manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
}
void MyClass::fetch()
{
m_manager->get(QNetworkRequest(QUrl("http://example.tld/test.html"))); // html contains only the number 5
}
void MyClass::replyFinished(QNetworkReply* pReply)
{
QByteArray data=pReply->readAll();
QString str(data);
m_replyStr = str;
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QObject>
#include <QNetworkAccessManager>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
};
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass();
void fetch();
QString m_replyStr;
public slots:
void replyFinished(QNetworkReply*);
private:
QNetworkAccessManager* m_manager;
};
#endif // WIDGET_H
You're accessing m_replyStr of a newly initialised instance tmp, which doesn't set anything into its m_replyStr. So it has the default-initialised value of "empty string."
EDIT
Based on your follow-up question, perhaps you were looking for something like this?
class MyClass;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(MyClass &myClassInstance, QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
MyClass *myClass;
};
Widget::Widget(MyClass &myClassInstance, QWidget *parent = 0)
: QWidget(parent)
, ui(new Ui::Widget)
, myClass(&myClassInstance)
{
ui->setupUi(this);
}
void Widget::on_pushButton_clicked()
{
int myNumber = myClass->m_replyStr.toInt();
ui->lcdNumber->display(myNumber);
}

"Cannot" move pointer

In my code I have:
template<class Ui_Dialog>
QDialog* Base_Dialog<Ui_Dialog>::set_caller(QDialog *new_caller)
{
QDialog* old_caller = caller_;
caller_ = new_caller;//Here I'm trying to set this to new caller
return old_caller;
}
but after setting the caller to new caller and exiting from this fnc, when I call caller I'm still getting the old caller instead of new one, as if no changes were made. Why?
EDIT:
//caller is defined in a following way:
class Main_Dialog : public Base_Dialog<Ui::Main_Dialog> {};
EDIT 2:
The interesting thing is that if instead of public Base_Dialog I alter Base_Dialog to non-template and define Main_Dialog as:
class Main_Dialog : public Base_Dialog, private Ui::Main_Dialog {};
Then it works as intended. Why?!
EDIT 3:
class Main_Dialog;
template<class Ui_Dialog>
class Base_Dialog : public QDialog, protected Ui_Dialog
{
// Q_OBJECT //no signals/slots
protected:
Main_Dialog* main_dlg_;
QDialog* caller_;
public:
Base_Dialog(Main_Dialog *main_dlg, QDialog *caller, QWidget *parent = nullptr);
QDialog* set_caller(QDialog *);
QDialog* clear_caller();
Main_Dialog* clear_main_dlg();
};
/*----------------*/
#include "Main_Dialog.hpp"
template<class Ui_Dialog>
Base_Dialog<Ui_Dialog>::Base_Dialog(Main_Dialog *main_dlg,QDialog *caller, QWidget *parent):
QDialog(parent),
main_dlg_(main_dlg),
caller_(caller)
{
//setupUi(this);
}
#include <QtDebug>
template<class Ui_Dialog>
QDialog* Base_Dialog<Ui_Dialog>::set_caller(QDialog *new_caller)
{
QDialog* old_caller = caller_;
caller_ = new_caller;
return old_caller;
}
#include "_1Dialog.hpp"
#include "_2Dialog.hpp"
class Main_Dialog : public Base_Dialog<Ui::Main_Dialog>
{
Q_OBJECT
QSet<QDialog*>* dialogs_;
private:
template<class Dialog,class Caller>
bool already_created_(Caller*&, QDialog*& already_exists)const;
template<class Dialog,class Caller, class Parent>
QDialog* create_(Caller*,Parent*);
/*template<class Dialog>
void show_();*/
/* template<class Dialog,class Caller>
QDialog* find_(Caller*)const;*/
public:
explicit Main_Dialog(QWidget *parent = 0);
template<class Dialog,class Caller>
QDialog* get_dialog(Caller*& caller);
public slots:
void _1clicked();
void _2clicked();
};
template<class Dialog,class Caller>
bool Main_Dialog::already_created_(Caller*& caller,QDialog*& already_exists)const
{/*the already_exists is introduced here in order to remove repetions of code and
searching*/
auto beg = dialogs_->begin();
auto end = dialogs_->end();
while(beg != end)
{
if(dynamic_cast<Dialog*>(*beg))
{
already_exists = *beg;
static_cast<Base_Dialog*>(already_exists)->set_caller(caller);
return true;
}
++beg;
}
return false;
}
template<class Dialog,class Caller, class Parent>
QDialog* Main_Dialog::create_(Caller *caller, Parent *parent)
{
return (*dialogs_->insert(new Dialog(this,caller,parent)));
}
template<class Dialog,class Caller>
QDialog* Main_Dialog::get_dialog(Caller *&caller)
{
QDialog* already_exists = nullptr;
if (already_created_<Dialog>(caller,already_exists))
{
return already_exists;
}
else
{
return create_<Dialog>(caller,this);
}
#include "Base_Dialog.hpp"
#include "ui__1Dialog.h"
class Main_Dialog;
class _1Dialog : public Base_Dialog<Ui::_1Dialog>
{
Q_OBJECT
public:
explicit _1Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent = 0);
private slots:
void _2clicked();
void caller_clicked();
void main_clicked();
};
#endif // _1DIALOG_HPP
#include "_1Dialog.hpp"
#include "_2Dialog.hpp"
#include "Main_Dialog.hpp"
_1Dialog::_1Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent) :
Base_Dialog(main_dlg,caller,parent)
{
setupUi(this);
}
void _1Dialog::_2clicked()
{
this->hide();
main_dlg_->get_dialog<_2Dialog>(this)->show();
}
void _1Dialog::caller_clicked()
{
this->hide();
caller_->show();
}
void _1Dialog::main_clicked()
{
this->hide();
main_dlg_->show();
}
}
#endif // MAIN_DIALOG_HPP
I think your problem not in set_caller. Next works for me:
#include <iostream>
using namespace std;
class QDialog {
int i;
public:
QDialog() : i(0) {}
QDialog(int i) : i(i) {}
void me() { cout << i << endl; }
};
namespace UI {
class Main_Dialog {}; // EDITED
}
template<class Ui_Dialog>
class Base_Dialog : public QDialog, protected Ui_Dialog
{
QDialog* caller_;
public:
QDialog* set_caller(QDialog *new_caller);
QDialog* get_caller() {return caller_; } ;
};
template<class Ui_Dialog>
QDialog* Base_Dialog< Ui_Dialog>::set_caller(QDialog *new_caller)
{
QDialog* old_caller = caller_;
caller_ = new_caller;//Here I'm trying to set this to new caller
return old_caller;
}
class Main_Dialog : public Base_Dialog<UI::Main_Dialog> {
public:
};
int main()
{
QDialog q1(1);
QDialog q2(2);
Main_Dialog md;
md.set_caller(&q1);
md.get_caller()->me();
md.set_caller(&q2);
md.get_caller()->me();
return 0;
}