PDA

View Full Version : How to send data from a static function of other Class to a MainWindow function?



hakermania
4th September 2012, 14:54
I have a class called Global and it does a repetitive task once in a while via a static function... This function is called through many different classes so it is important to be static so as not to create objects all the time.

glob.h:

class Global: public QObject
{
Q_OBJECT

public:
static void send_name(QString color_name);
...

Q_SIGNALS:
send_color(QString color_name);
};

glob.cpp:

void Global::send_name(QString color_name){
if(_window_loaded_){
/*SEND MESSAGE WITH COLOR_NAME*/
Q_EMIT send_color(color_name);
}
}

Inside my MainWindow class I have to connect the send_color message sent by my static function to a local function so as to update some gui content.

I know that there are many many threads about this but, believe me, I've searched all of them and nothing worked for me. I searched in depth the mailing lists and still nothing. I even tried to use QCustomEvent with qApplication->postEvent() but it is deprecated and it is suggested to use QEvent , which doesn't have setdata() function though, so it is no usable for this case (?)

I've spent my morning searching about this, so all suggestions are appreciated!

spirit
4th September 2012, 15:21
It's an interesting interpretation, but I would make this in other way: make this object as a singleton


class Global: public QObject
{
Q_OBJECT

public:
static Global *instance();

void send_name(const QString &color_name);
...

Q_SIGNALS:
void send_color(const QString &color_name);

private:
Q_DISABLE_COPY(Global);
};

#define myGlobal Global::instance() //shortcut


Then


...
connect(myGlobal, SIGNAL(send_color(const QString &)), SLOT(applyColor(const QString &)));
...
myGlobal->send_name("lightgray");

hakermania
4th September 2012, 17:09
It's an interesting interpretation, but I would make this in other way: make this object as a singleton


class Global: public QObject
{
Q_OBJECT

public:
static Global *instance();

void send_name(const QString &color_name);
...

Q_SIGNALS:
void send_color(const QString &color_name);

private:
Q_DISABLE_COPY(Global);
};

#define myGlobal Global::instance() //shortcut


Then


...
connect(myGlobal, SIGNAL(send_color(const QString &)), SLOT(applyColor(const QString &)));
...
myGlobal->send_name("lightgray");


Thanks for your reply but I am not 100% sure that I understand your code. I want to call a Global static function from my MainWindow class, let's say


Global::set_new_color();

and then, from within set_new_color I want to send a message back to mainwindow getting the color_name. From your code I assume that the send_name function then emits the send_color signal? If I use


Q_EMIT send_color(color_name);

it doesn't let me emit it without an object... And I cannot create a new Global instance, because, as far as I understood from your code, Q_DISABLE_COPY avoids me from doing so...

If you want, I will provide you with example files.

spirit
4th September 2012, 17:14
it doesn't let me emit it without an object... And I cannot create a new Global instance, because, as far as I understood from your code, Q_DISABLE_COPY avoids me from doing so...


You should implement Global::instance. I left this for you. ;)
HINT: you'll be able to instantiate a Global object in Global::instance.

hakermania
4th September 2012, 18:30
You should implement Global::instance. I left this for you. ;)
HINT: you'll be able to instantiate a Global object in Global::instance.

But, as I said I haven't understood your code or what you're trying to achieve there... :(

spirit
4th September 2012, 19:11
What's not clear? It's a simple singleton implementation -- Q_DISABLE_COPY macro disables copy ctor & and assignment operator.

amleto
4th September 2012, 20:34
"Inside my MainWindow class I have to connect the send_color message sent by my static function to a local function so as to update some gui content."

Why not just emit that string as a signal from the class that uses Global, and connect those signals to the mainwindow???


You have some widget (actually lots of widgets), W, Global, G, and main window, M:

W -> G -> M.

You could just have

W -> M.

So what are you doing?

hakermania
4th September 2012, 23:08
Why not just emit that string as a signal from the class that uses Global, and connect those signals to the mainwindow???

Ok, I see your point, but hold on a little bit. I don't know if I made myself 100% clear.

Example (wrong) code:

MainWindow class:



...
connect( Global::instance(), SIGNAL(mysignal(QString)), this, SLOT(update_gui(QString)); //<-instructor of MainWindow
...
Global::do_stuff(); ///<-- inside some other mainwindow function.. (dostuff() is a MUST BE static function)

...
void MainWindow::update_gui(QString name){
ui->pushButton->setText(name); //<- simple example
}


inside this function I have this:



void Global::do_stuff(QString name){
//do a lot of things...
...
...
if(MainWindow_is_visible){
//generate a color_name depending on the previously done things...
QString color_name = previous_stuff.component.at(3).toString(); //<- example
Q_EMIT mysignal(color_name);
}
}


So, is your saying possible for my situation where I need the previous things of the do_stuff() function so as to emit the proper signal?

amleto
5th September 2012, 09:13
I highly doubt you truly have a 'MUST BE' global static. It just points to bad design.

hakermania
5th September 2012, 12:35
I highly doubt you truly have a 'MUST BE' global static. It just points to bad design.

Nope, seriously, this function is being called from almost every class. Would you recommend making class objects and calling the function through there?

d_stranz
5th September 2012, 17:04
I think you don't understand the concept of a "Singleton".

Basically, a singleton is an object that can only have a single instance. That instance can be used exactly like a global class with a static method in most cases.

So, you implement your Global class without a static function for doing the global stuff (it is just an ordinary member function, which must be called through an instance pointer). Every time you want to call that method, you get a pointer to the global instance of your class (using the getInstance() static method, and call it. Since that pointer is a genuine pointer to an instance, the doStuff() method can emit signals, get connected to slots, whatever.



// Global.h
class Global : public QObject
{
Q_OBJECT

public:
static Global * getInstance();

public slots:
void doStuff();

signals:
void somethingChanged();

private:
Global( QObject * pParent = 0 );
virtual ~Global() = 0; // singleton can't be deleted by a caller of getInstance()
};

// Global.cpp

#include "Global.h"

static Global * theInstance = 0;

Global * Global::getInstance()
{
if ( theInstance == 0 )
theInstance = new Global();
return theInstance;
}

Global:: Global( QObject * pParent )
: QObject( pParent )
{
// Initialize whatever else needs to be done
}

void Global::doStuff();
{
// do what you need to do

emit somethingChanged();
}

// someOtherCode.cpp

#include "Global.h"

SomeOtherCode::SomeOtherCode( QObject * pParent )
: QObject( pParent )
{
connect( Global::getInstance(), SIGNAL( somethingChanged() ), this, SLOT( whoaGlobalStuffHappened() ) );

// Two ways to kill the same bird:
connect( somePushButton, SIGNAL( clicked() ), Global::getInstance(), SLOT( doStuff() ) );
connect( someOtherButton, SIGNAL( clicked() ), this, SLOT( doTheGlobalThing() ) );
}

void SomeOtherCode::doTheGlobalThing()
{
Global::getInstance()->doStuff();
}


All the same functionality as your Global class with the static method, except you get to use all the Qt signal / slot functionality. If "doStuff" needs to change some global properties, make them private member variables of the Global class and provide access functions for the app to get at their values after they have changed:



bool someConditionalValue = Global::getInstance()->conditionalValue();

amleto
5th September 2012, 20:47
Nope, seriously, this function is being called from almost every class. Would you recommend making class objects and calling the function through there?

Then you have very poor encapsulation - since every class wants to use this code. You could call this bad design. I know I do. It Also breaks the one class, one responsibility paradigm, since almost every class is responsible for gui/mainwindow updates.