PDA

View Full Version : static function/object accessibility



vonCZ
18th August 2007, 15:17
I'm trying to set up a static function and QLabel so that non-Qt parts of my application can call this function and change the setNum() value of the QLabel. I've done it like so:



//--window.h
class Window : public QWidget
{
Q_OBJECT

public:
Window();
static void setText(int value);
// etc...


//--window.cpp
#include <QtGui>
#include "window.h"

static QLabel *vuXLocLabel=0;


vuXLocLabel = new QLabel;
vuXLocLabel->setText("hello");



void Window::setText(int value)
{
vuXLocLabel->setNum(value);
//vuXLocLabel->setText("goodbye");
qDebug(" HERE %d", value);
}


The QLabel is displayed correctly initially: "hello". But when I call

Window::setText(value);

from the non-Qt part of the program, the value is sent and qDebug("HERE %d") is called (with correct value), but the QLabel isn't changed (using either setNum() or setText().)

I also tried setting up the vuXLocLabel like so:


//--window.h

static QLabel *vuXLocLabel;

//--window.cpp

QLabel *Window::vuXLocLabel=0;


but got the same result: code compiled, program didn't crash, but setNum/setText didn't work. Any insights greatly appreciated. (of course :D)

niko
18th August 2007, 16:39
hi,

you have here a global variable - which isn't a good thing - you could use the singleton-pattern like this:

class Window : public QWidget
{
Q_OBJECT

public:
Window();
static void setText(int value);
static Window* getInstance();
// etc...

static Window* Window::getInstance()
{
static Window* win = 0;
if (!win) {
win = new Window();
}
return win;
}

void Window::setText(int value)
{
Window* label = Window::getInstance();
label->setNum(value);
}

you can then access the window using:

Window* win = Window::getInstance();
win->show(); (in your main for example)

vonCZ
19th August 2007, 09:02
thanks Niko. I knew it was just a matter of time before someone would sling a Singleton solution at me. I tried incorporating your solution but get a
setNum is not a member of 'Window' error. But let me step back a bit first:

1. my "class Window" is my primary/main application window class with references to 100+ top-level widgets, etc. Confusing, perhaps, since it derives from QWidget and not QMainWindow; I may change this later. Anyway, given this fact, perhaps I need to go about this a different way, because...

2. from the Wiki (http://wiki.qtcentre.org/index.php?title=Singleton_Pattern) I see that a primary use of Singletons is "to encapsulate global variables", which is why I would want to use it here, of course. Here's where I'm confused: the Wiki example provides an example of a Singleton class, including things like a your getInstance() method, and a private constructor (which you left public). In *your* example, however: are you simply saying that I can create a class, Window, that is normal in most respects, yet has some singleton-pattern methods to enable access to a specific QLabel? If true, then I think this might be the best way for me to do it, since I will only have 5 or so QWidgets in Window that need to be accessed by non-Qt parts of the program. But if *not* true:

3. Perhaps the best thing to do: create a separate Singleton class (like in the Wiki) and put all my global variables there... so that they can be accessed by both Window and the non-Qt parts of my application?

wysota
19th August 2007, 09:20
What do you mean by "non-Qt parts"? Can't you just call setText() on the object directly?

vonCZ
19th August 2007, 09:29
non-Qt parts: a Coin3d scenegraph. My current task: as the user rotates the model (thus moving the camera), I want to send the new camera X position to a QLabel's setNum() method. I haven't any trouble sending Qt instructions/parameters to the Coin3d class, but going the other way around--from Coin3d to Qt--is where I'm currently stuck.

marcel
19th August 2007, 09:33
Just make the label visible outside the window class.
Add a method getLabel in the window that returns the label. You can use it to call setText or connect signals to it.

You don't need the label to be static. It will work with a singleton.
Something like:


Window::getInstance()->getLabel()->setText("x");



Regards

vonCZ
19th August 2007, 10:29
program compiles, but crashes when run. I've got:



// window.h
class Window : public QWidget {

Q_OBJECT

public:
Window();
static Window* getInstance();
QLabel *getLabel();
QLabel *myLabel;

// window.cpp
myLabel = new QLabel;
Window* Window::getInstance() {
static Window *win=0;
if(!win) {
win = new Window();
}
return win;
}

QLabel *Window::getLabel() {
return myLabel;
}

// model.h ...Coin3d scenegraph
#include <Inventor/*/*.h> //many
#include <QLabel> //was surprised I had to include this
#include "window.h"

// model.cpp

Window::getInstance()->getLabel()->setText("x");
// Window::getInstance(); //also crashes


based on the last commented line: looks like I'm not employing the Singleton correctly.

Another question though: the call to update the QLabel value will happen ~25 times a second as the camera is moved. Is this still a good way to connect the camera X-value to the QLabel?

marcel
19th August 2007, 10:43
What do you do in the constructor of Window?
It should work, although, you should add a static private Window membner, and take it out of get instance.

vonCZ
19th August 2007, 11:09
It should work, although, you should add a static private Window membner, and take it out of get instance.

ok, did that.


What do you do in the constructor of Window?

almost everything. Instantiate many of my widget objects, call functions to intantiate others, do connects, etc...


edit: NOTE my constructor is public.

i should also add: the application hangs for about 3-4 seconds, then crashes.

marcel
19th August 2007, 11:22
edit: NOTE my constructor is public.

Does not really matter, but it is not singleton if the constructor is not private.
If it is public it means that you can create other instances outside the class.

I am almost sure that something happens in the constructor.

Regards

vonCZ
19th August 2007, 11:30
Does not really matter, but it is not singleton if the constructor is not private.
If it is public it means that you can create other instances outside the class.

I am almost sure that something happens in the constructor.

Regards

well here's the code, when you or someone else has a moment.

"public it means that you can create other instances outside the class"- perhaps that's my problem. I'm calling:



Window::getInstance()->getLabel()->setText("x");


from another class, Model. Isn't this call, then, creating a 2nd instance of Window? ...thus the hang/crash? I'll try making the constructor private, also I suspect doing so will cause all sorts of other problems...

marcel
19th August 2007, 11:36
from another class, Model. Isn't this call, then, creating a 2nd instance of Window? ...thus the hang/crash? I'll try making the constructor private, also I suspect doing so will cause all sorts of other problems...

It won't create another instance because getInstance tests if there already is an instance available. That is the whole point of singletons.

Keeping the constructor public allows something like this from another class:


Window *w = new Window();

therefore creating another instance, other than the static one.

So you should make the constructor private to prevent it from being accessed from any other class than Window.



well here's the code, when you or someone else has a moment.

I can't compile it, bu I'll take a look.

Regards

wysota
19th August 2007, 11:38
Do you by any chance use multiple threads in your application?

marcel
19th August 2007, 11:39
Who initializes the members of Window::dafo?


for(int a=0; a<dafo.get_compNUM_TOT(); a++)
{
mkLyBuLayout(a); // comp Number
}


This code could cause the seg fault if get_compNUM_TOT returns an uninitialized int.

Regards

vonCZ
19th August 2007, 11:41
Do you by any chance use multiple threads in your application?

not intentionally :o ...i mean, no.

vonCZ
19th August 2007, 11:44
Who initializes the members of Window::dafo?


for(int a=0; a<dafo.get_compNUM_TOT(); a++)
{
mkLyBuLayout(a); // comp Number
}


This code could cause the seg fault if get_compNUM_TOT returns an uninitialized int.

Regards

dafo's members are all static, initialized in dafo.cpp.

marcel
19th August 2007, 11:56
Well, it is pretty hard to see anything without debugging.
I recommend doing so in the constructor.

BTW: "EARTH Earth, the 3rd planet from the sun, is approximately four and a half billion years old.". I think it is older than that, but I'm sure this isn't causing the crash :). The planet itself should be as old as the solar system.

EDIT: Oh, I read only half a billion years :), missed the "four".
Anyway, I see you are on Windows, so debugging should be a lot easier. A step by step debugging should reveal the error.
Did it work before, when you were not using a singleton?


Regards

vonCZ
19th August 2007, 12:04
So you should make the constructor private to prevent it from being accessed from any other class than Window.

oops- i didn't see this at first! Anyway, you were right on: I made the constructor private and changed changed a couple other things accordingly, i.e.



//-- main.cpp

// Window window; //changed to
Window* window = Window::getInstance();


and it runs without crashing. For some reason

Window::getInstance()->getLabel()->setText("x")

still doesn't update the text, but i'll figure it out.

Thanks to all for your help...:)

vonCZ
19th August 2007, 12:12
EDIT: Oh, I read only half a billion years :), missed the "four".


though i live in CZ, I work for a geologic research institute in Texas... a state in which half the population believes the earth is only 6,000 years old. I've heard Jesus turned water into wine... I guess he turned rocks into oil, too.;)

marcel
19th August 2007, 12:37
oops- i didn't see this at first! Anyway, you were right on: I made the constructor private and changed changed a couple other things accordingly, i.e.



//-- main.cpp

// Window window; //changed to
Window* window = Window::getInstance();
and it runs without crashing. For some reason

Window::getInstance()->getLabel()->setText("x")

still doesn't update the text, but i'll figure it out.

Thanks to all for your help...:)

This is is because you create 5 labels for each layer ( in mkZXag ). So, probably, the label you return is not the one which is visible.
The label you return in Window is the 7th.
Which layer do you have visible?

vonCZ
19th August 2007, 12:56
right again! ...this was just a test: the label "vuXLocLabel" will exist somewhere else--not on the zXag QStack or any other Stack--but I put it there just to test this out for convenience... by mistake (putting it on a stack).

huh- this was the cause of my original error, before I got into the Singleton stuff, i bet. Nevertheless, I'm glad ya'll helped me thru it: I still don't understand fully why, but I gather from this and other threads global variables--apparently even the kind I had coded in my original post--are a bad idea. I'll have to go back and re-do dafo.h/dafo.cpp using this singleton approach, I guess.

I'm still curious how this will work after I make the proper connections: for this test the QLabel is updated just once with a function call, but I'm going to created 3 QLabels that are updated by movement of the camera... ~25/sec. I'll be interested to see how making 3 getLabel()->setText("x/y/z") calls, 25/sec, works out.

marcel
19th August 2007, 13:00
I'm still curious how this will work after I make the proper connections: for this test the QLabel is updated just once with a function call, but I'm going to created 3 QLabels that are updated by movement of the camera... ~25/sec. I'll be interested to see how making 3 getLabel()->setText("x/y/z") calls, 25/sec, works out.

I wouldn't worry about that. There will be 25 function calls + signals/slots overhead.
There shouldn't be any problem with calling a function 25 times/second.

Eventually you could skip some of those values since no one can really see 25 coordinates/second anyway.

Regards