I have a class “Wave” and inside I’d like to access the slider value ‘waveSpeed’ but it gives me linking errors.
z += ofApp::waveSpeed * deltaTime;
That gives me invalid use of non-static
If I make it a static variable it throws:
Undefined symbols for architecture i386:
"ofApp::waveSpeed", referenced from:
ofApp::setup() in ofApp.o
Wave::update() in Wave.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
the easiest way to do this is either pass the value through to the wave object from ofApp, or in the .cpp file of wave (you can’t do this in the .h file) you can do:
#include "ofApp.h" // note you can't do this in wave.h b/c it would be a recursive include...
then later in the cpp you can do:
((ofApp*) ofGetAppPtr())->waveSpeed
ofGetAppPtr() gets a pointer to the app that OF is running (ie, ofApp) and (ofApp*) casts it as an ofApp (it’s a pointer to an ofBaseApp). I use ofGetAppPtr() to get access to the main level of the ofApp inside of other classes, like what you are trying to do here…
I don’t know if this is the way the gui slider is supposed to be used. I mean it is ok to modify a class slider from ofApp, but not the other way around.
maybe you should declare a listener that updates a Wave::speed variable every time the slider is updated in ofApp
This seems like functionality that would be used often, no? To have a class’ behavior modified from sliders?
Gallo, with your method, in the update() function, shall I do something to the effect of…?
Wave::speed = waveSpeed;
The only thing about this that strikes me as funny is that I have many wave objects on at a time, so isn’t it a waste for them to each have a speed var if it’s meant to be the same for all waves?
every wave should have a speed, you can update it by listening the slider in ofApp (although the best approach here would be to declare speed in wave as ofParameter then populate the ofApp gui with that parameter)
the easiest, and cleanest way to use this is to use ofParameter to represent the speed and then pass that to a panel which will create a slider automatically. take a look at guiFromParametersExample but it would be something like:
class Wave{
public:
void setup(){
speed.set("wave speed",0,10,100); // value, min, max
}
...
ofParameter<float> speed;
}
so is not recommended to create the ofxGui panel inside the classes? Should be always on the ofApp class?
I am trying to create some instances from a class with the gui panel included but only the last (?) created panel is usable. In the other panels, sliders and panel itself can’t be moved…
What’s the difference between to create the parameters into a setup() function besides the constructor?
It depends on how many instances you plan to populate. And also how do you want to organize XML setting files.
Here is two working examples I made and tested on macOS. I personaly design it like #2.
NOTICE:
If you use vector for MyClass like #1 example above, please make sure MyClass’s destructor won’t be called.
This happen often for example when you push_back() new element to vector. When you add new element to your vector, it could be automatically change its memory size to prepare future addition. During this auto expansion process, destructor ofGui is called and lose callback pointer information. Resulting mouse event stop working. To avoid this, and makes really sure its pointer and memory is under your control always, one could use shared pointer like below
vector<shared_ptr<MyClass>> myClasses;
I think this is not a bug but not a best user experience because I also confused sometimes.
@arturo
May I ask to check if it’s correct?
Also is it doable to update ofxGui to be std::vector friendly class?
When we call .push_back(), it calls destructor of MyClass and ofxPanel, then unregisterMouseEvents() will be called. It should register again during copy process but somehow it won’t. I didn’t look inside deep enough so not sure what is happening. So I guess it’s not copy-friendly.
If you replace push_back(MyClass(i)) to emplace_back(i), it does not work either because of std::vector changes its size automatically after first or second insertion and call ofxGui destructor.
Hi, I see what you mean.
I am assumming that you are initializing the gui in the constructor of your MyClass class. There are a few options.
use a setup method in myClass and call it after pushing it into the vector.
This does not work on macOS.
To be precise, 3rd gui slider works, but 1st and 2nd slider does not.
This is natural because it force vector to increase its size. If we call myClasses.reserve(3); it works.
With shared_ptr, no problem at all, but it’s not really user friendly.
C++ beginner or students does not know how to use shared_ptr also can not aware of cyclic reference issue even if they manage to use smart pointer.
nope I use macos but i did not really test that code I posted, I just wrote it straight out of my head into the forum.
Can you post the complete code you are using for testing please. There might be something in there.
The following code works for me but it does not work with push_back. Maybe reenabling the mouse events can work.
well, certainly the problem is because the vector will reallocate its objects when using push, so internally the pointer to this object changes which is the one used for registering to the mouse events, hence it does not work.
I still think that the best solution is with the smart pointers. it might be a bit unfriendly at first but it is much easier to handle than regular pointers.
in the code you sent if you put the following ugly hack it works
So, avoid pushing into the vector. emplace_back will not work either I think. std::vector::reserve does not seem to work either.
If you still want to avoid the smart pointers I’d prefer to use std::vector::resize as in the previous code I posted and setup everything on a setup function rather than with the constructor.
hope this helps.