juce::Value


#1

So, i’ve scoured the forum for info about this class. You can use it to see if a value changes, which works well. But how are we supposed to query what this new value is?

Example:
Value v; v.setValue(false); //now it's a boolean

Somewhere else, we have a listener who is responding to changes to v;

void MyClass::valueChanged(juce::Value &value) {
  if( value == v ) {...}
}

but now what? how do we take the next step and
if( value == true ) { } else { }
?

the closest thing i’ve found is:
if( value.getValue().equals( juce::var(false) ) ) { }

but that’s just ugly


#2
Value bVal;

bVal.setValue (true);

if (bVal == false)        // or if (! bVal.getValue())
    DBG ("bVal is FALSE");
else
    DBG ("bVal is TRUE");

#3

ok. That does work after all…

My next problem has to do with figuring out which Value instance was changed:

class ActivityIndicator : public Component {
public: 
   ...
   juce::Value& getIsSelected() { return isSelected; }
private:
   ...
   juce::Value isSelected;
};


class Channel : public Component {
public: 
   ...
   ActivityIndicator activity;
   void setIsSelected(bool s) { activity.setIsSelected(s); }
   juce::Value& getIsSelected() { return activity.getIsSelected(); }
};

and here’s where 16 of 'em get put together

    class Channels : public Component, public Value::Listener {
    public: 
       ...
      Channels();
      void ValueChanged( Value& value ) override;
    private:
       ...
       const std::vector<unique_ptr<MidiChannel>> channelSections;
    };

    Channels::Channels() {
       ...
       //make 16 midiChannel objects
       for( auto i = 0; i < 16; i++ ) { channelSections.push_back(...); }
      ...
       for( auto i = 0; i < channelSections.size(); i++ ) {
          //add listeners to the isSelected member in the ActivityIndicator
            channelSections[i]->getIsSelected().addListener(this); 
       }
    }

Here’s the valueChanged callback:

void Channels::valueChanged(juce::Value &value) {
    //how can we tell which value was used?
    for(uint i = 0; i < channelSections.size(); ++i ) {
        if( value == channelSections[i]->getIsSelected() ) {
            DBG( "value changed: " + value.toString() + " channel: " + String(i) );
            if( value == true ) { //if a channel was selected, deselect all other channels
                for( uint j = 0; j < channelSections.size(); ++j ) {
                    if( j != i ) {
                        channelSections[j]->setIsSelected(false);
                        //DBG( "setting channel off: " + String(j) );
                    }
                }
            }
            break;
        }
    }
}

If l click on Channel 8 to begin with, When I click on a channel LOWER than 8, it toggles correctly (channel 8 turns off, the other channel turns on). if I click on a channel HIGHER than 8, 8 doesn’t turn off, and the other channel doesn’t turn on either. The DBG( “value changed:” ) line prints out
value changed: 1 channel: 8
value changed: 0 channel: 0

I have no idea what is causing that either. it’s driving me nuts!!


#4

ah! the ol’ == being used where Value::refersToSameSourceAs( const Value& other) should be used!!


#5

Anyone have any insight for determining the underlying type and being able to cast/store it that way for comparison?

I’m trying to determine if a juce::Value is between some values and it is not cooperating. Do i need to cast, or what?

i saw the Value::getValue() method, which returns the juce::var object, and from there, there is an operator overload method for int(), but I’m not sure how to use it.


#6
Value bVal;

bVal.setValue (true);

if (bVal.getValue().isBool())
    {
    DBG ("It's a Bool");
    }

if (bVal.getValue().isDouble())
    {
    DBG ("It's a Double");
    }

double makeMineADouble = double (bVal.getValue());  // See Jules' next post, use a static_cast<double> (v)
                                                    // or implicit conversion

DBG ("bVal = " + bVal.getValue().toString());

DBG ("makeMineADouble = " + String (makeMineADouble, 3));

Rail


#7

Can be simpler than that, e.g…

Value value;
auto v = value.getValue();

bool isBool = v.isBool();
bool isDouble = v.isDouble();

double asDouble = v;

C-style casts are a really bad idea when using non-primitive types, so never write double (bVal.getValue()). Instead just allow it to be implicitly converted (e.g. when you pass it as a function arg or if you assign it like in my example here), or do a static_cast<double> (v)


#8

A proper tutorial showing how to use juce::Value in a class that has two different Value objects (each a different type like int and Array), and how to use valueChanged() in that class would be awesome!!


#9

I was being verbose to demonstrate :wink:

Cheers,

Rail


#10

Ok, what about ++'ing or += 1’ing a juce::Value that is holding an int? I’m getting nothing but "Invalid operands to binary expression (‘juce::Value’ and ‘int’) for the line:

juce::Value loadedFileCounter;
loadedFileCounter.setValue(int(0));
...
loadedFileCounter.setValue( loadedFileCounter + 1 ) ;

#11

The Value class can contain strings, objects or arrays, so it’d make no sense to give it an operator like “+”. You’d need to actually get an integer before you try to add 1 to it, e.g.

v.setValue (static_cast<int> (v.getValue()) + 1);

#12

cool. that class doesn’t have a lot of documentation, so your examples in this thread are extremely helpful.


#13

as a general rule, are we supposed to use the syntax
TYPE val = static_cast<TYPE>( v.getValue() )
to retrieve the value of a, er, value?


#14

If you need a cast, then yes, be modern and use a static_cast. But like in my examples above, you usually don’t.


#15

in fact, the compiler should tell you when you have to use a cast. One reason might be, that there exist different types that provide implicit conversions from that object, like float or double.

Here are some explanations: http://en.cppreference.com/w/cpp/language/implicit_conversion