[HELP] "CHARTEVENT_OBJECT_CLICK" - OBJPROP_STATE Is Always Returning 0 (False) - I used OBJ_LABEL to Create Wingdings For Fixed Position.. Bug?

 

[HELP] "CHARTEVENT_OBJECT_CLICK" - OBJPROP_STATE Is Always Returning 0 (False) - I used OBJ_LABEL to Create Wingdings For Fixed Position.. Bug?

I clicked the wingdings but ObjectGetInteger(0, "show_buff_obj"+0, OBJPROP_STATE); is returning Boolean value is 0 (false).. It should be true when clicked the object. What happen?

Here's the code:

int init()
{
   for(int h=0; h<=1; h++)      
   {
      ObjectCreate("show_buff_obj"+h, OBJ_LABEL, ChartWindowFind(), 0, 0, 0, 0);
      ObjectSet("show_buff_obj"+h, OBJPROP_SELECTABLE, false);
   }
   ObjectSet("show_buff_obj"+0, OBJPROP_XDISTANCE, 160);
   ObjectSet("show_buff_obj"+0, OBJPROP_YDISTANCE, .5);
      
   ObjectSet("show_buff_obj"+1, OBJPROP_XDISTANCE, 172);
   ObjectSet("show_buff_obj"+1, OBJPROP_YDISTANCE, .5);
      
   ObjectSetText("show_buff_obj"+0, CharToStr(108), 12, "Wingdings", clrDodgerBlue);
   ObjectSetText("show_buff_obj"+1, CharToStr(108), 12, "Wingdings", clrSilver);

   return(INIT_SUCCEEDED);
}


void OnChartEvent(const int id,         // Event identifier  
                  const long& lparam,   // Event parameter of long type
                  const double& dparam, // Event parameter of double type
                  const string& sparam) // Event parameter of string type
{
   
   if(id==CHARTEVENT_OBJECT_CLICK)
   {
      if(sparam == "show_buff_obj"+0)
      {
         bool pressed_buffer = ObjectGetInteger(0, "show_buff_obj"+0, OBJPROP_STATE);
         Print("Bool value in buffer: ", pressed_buffer);  // Output is always 0
         if(pressed_buffer)
         {
            SetIndexStyle(3, DRAW_NONE);
            ObjectSetText("show_buff_obj"+0, CharToStr(109), 12, "Wingdings", clrDodgerBlue);
         }
         else
         {
            SetIndexStyle(3, DRAW_LINE);
            ObjectSetText("buffer_and_object"+0, CharToStr(108), 12, "Wingdings", clrDodgerBlue);
         }
      }
      else if(sparam == "show_buff_obj"+1)
      {
         bool pressed_object = ObjectGetInteger(0, "show_buff_obj"+1, OBJPROP_STATE);
         Print("Bool value in obj: ", pressed_object);     // Output is always 0
         if(pressed_object)
         {
            
         }
         else
         {
            
         }
      }
   }
}
 
Musngi:

[HELP] "CHARTEVENT_OBJECT_CLICK" - OBJPROP_STATE Is Always Returning 0 (False) - I used OBJ_LABEL to Create Wingdings For Fixed Position.. Bug?

I clicked the wingdings but ObjectGetInteger(0, "show_buff_obj"+0, OBJPROP_STATE); is returning Boolean value is 0 (false).. It should be true when clicked the object. What happen?

Here's the code:

The primary reason your code doesn't work is because state only applies to button objects. Just a personal word of advice, you should try to develop better coding habits because there are many other errors in this example. Also, you are repeating your code which is a programming faux pas. For your program, I'd recommend using buttons and also encapsulating your event handling methods so you're not having to repeat your code and clutter up your OnChartEvent function... Here is an example...

 

#property strict
#property indicator_chart_window
//+------------------------------------------------------------------+
#include <ChartObjects\ChartObjectsTxtControls.mqh>
#include <Arrays\List.mqh>
#define  X_WIDTH 50
//+------------------------------------------------------------------+
class MultiButton : public CChartObjectButton
{
 protected:
   static int  s_instances;
   int         m_instance;
 public:
   MultiButton()
   {
      m_instance = ++s_instances;
      this.Create(0,"__button_"+string(s_instances),0,m_instance*X_WIDTH,50,X_WIDTH,20);
      this.Description(string(s_instances));
      this.Color(clrRed);
   }
   bool encapsulatedChartEventHandler(const int &id,const string &sp)
   {
      if(id==CHARTEVENT_OBJECT_CLICK && sp==this.Name())
      {
         this.Color(this.State() ? clrGreen : clrRed);
         Comment(StringFormat("Button #%d [%s]", m_instance, (string)this.State()));
         return true;
      }
      return false;
   }
};
int MultiButton::s_instances=0;
//+------------------------------------------------------------------+
CList buttons;
//+------------------------------------------------------------------+
void OnInit()
{
   //dynamic/random number of buttons
   for(int i=rand()%20;i>=0;i--)
      buttons.Add(new MultiButton());
}
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   MultiButton *b = buttons.GetFirstNode();
   for(;b!=NULL; b=b.Next())
      if(b.encapsulatedChartEventHandler(id, sparam))
         break;
}
//+------------------------------------------------------------------+
int start(){ return 0; }
 
Mark Watkins:

The primary reason your code doesn't work is because state only applies to button objects. Just a personal word of advice, you should try to develop better coding habits because there are many other errors in this example. Also, you are repeating your code which is a programming faux pas. For your program, I'd recommend using buttons and also encapsulating your event handling methods so you're not having to repeat your code and clutter up your OnChartEvent function... Here is an example...

 

It confusing because they called it "CHARTEVENT_OBJECT_CLICK" instead of "CHARTEVENT_BUTTON_CLICK". If OBJECT_CLICK don't work in other OBJECT then why they name it "OBJECT_CLICK". Why they include the OBJPROP_STATE in OBJ_LABEL"?? Even I set the OBJPROP_STATE to "True" it don't work either. I spend more than 2 days thinking and coding.

<moderator : please watch your language>

 
Musngi:

It confusing because they called it "CHARTEVENT_OBJECT_CLICK" instead of "CHARTEVENT_BUTTON_CLICK". If OBJECT_CLICK don't work in other OBJECT then why they name it "OBJECT_CLICK". Why they include the OBJPROP_STATE in OBJ_LABEL"?? Even I set the OBJPROP_STATE to "True" it don't work either. I spend more than 2 days thinking and coding.

<moderator : please watch your language>

Moderator deleted some part of my comment again. -_-
 
Musngi:

It confusing because they called it "CHARTEVENT_OBJECT_CLICK" instead of "CHARTEVENT_BUTTON_CLICK". If OBJECT_CLICK don't work in other OBJECT then why they name it "OBJECT_CLICK". Why they include the OBJPROP_STATE in OBJ_LABEL"?? Even I set the OBJPROP_STATE to "True" it don't work either. I spend more than 2 days thinking and coding.

<moderator : please watch your language>

OBJPROP_STATE only applies to buttons, and it says so in the documentation. 

OBJPROP_STATE

Button state (pressed / depressed)

bool


If you needed further proof you should've checked the return value of ObjectSetInteger when you tried to set the state of a label to "true" - because you would have gotten back false. Which makes since because a label can only ever have one state. 


The answer is super-simple. Use a button. 

 
Mark Watkins:

OBJPROP_STATE only applies to buttons, and it says so in the documentation. 

OBJPROP_STATE

Button state (pressed / depressed)

bool


If you needed further proof you should've checked the return value of ObjectSetInteger when you tried to set the state of a label to "true" - because you would have gotten back false. Which makes since because a label can only ever have one state. 


The answer is super-simple. Use a button. 

I remove ObjectGetInteger - OBJPROP_STATE then I used global Boolean variable counter. It works now.
 
Musngi:
I remove ObjectGetInteger - OBJPROP_STATE then I used global Boolean variable counter. It works now.

I'm not sure what you mean by "works" since a label object doesn't have a variable state.

 
Mark Watkins:

I'm not sure what you mean by "works" since a label object doesn't have a variable state.

bool pressed_buffer = true; 
bool pressed_object = true;

int init()
{
   for(int h=0; h<=1; h++)      
   {
      ObjectCreate("show_buff_obj"+h, OBJ_LABEL, ChartWindowFind(), 0, 0, 0, 0);
      ObjectSet("show_buff_obj"+h, OBJPROP_SELECTABLE, false);
   }
   ObjectSet("show_buff_obj"+0, OBJPROP_XDISTANCE, 160);
   ObjectSet("show_buff_obj"+0, OBJPROP_YDISTANCE, .5);
      
   ObjectSet("show_buff_obj"+1, OBJPROP_XDISTANCE, 172);
   ObjectSet("show_buff_obj"+1, OBJPROP_YDISTANCE, .5);
      
   ObjectSetText("show_buff_obj"+0, CharToStr(108), 12, "Wingdings", clrDodgerBlue);
   ObjectSetText("show_buff_obj"+1, CharToStr(108), 12, "Wingdings", clrSilver);

   return(INIT_SUCCEEDED);
}


void OnChartEvent(const int id,         // Event identifier  
                  const long& lparam,   // Event parameter of long type
                  const double& dparam, // Event parameter of double type
                  const string& sparam) // Event parameter of string type
{
   
   if(id==CHARTEVENT_OBJECT_CLICK)
   {
      if(sparam == "show_buff_obj"+0)
      {
         if(pressed_buffer)
         {
            SetIndexStyle(3, DRAW_NONE);
            ObjectSetText("show_buff_obj"+0, CharToStr(109), 12, "Wingdings", clrDodgerBlue);
            pressed_buffer = false;
         }
         else
         {
            SetIndexStyle(3, DRAW_LINE);
            ObjectSetText("show_buff_obj"+0, CharToStr(108), 12, "Wingdings", clrDodgerBlue);
            pressed_buffer = true;
         }
      }

   }
}
 
Musngi:

The problem you're going to run into is as soon as you change the chart your global bool will reinitialize to true, which is not only an extreme nuisance but can also be very dangerous if you have any trading logic attached to its state. That's why you use a button instead, because it will retain its state through chart changes. Also you should never implicitly cast in MQL. You have to have seen the compiler warning you not to do it ...this is what it means. 

"show_buff_obj"+h //wrong!
"show_buff_obj"+string(h) //correct
"show_buff_obj"+(string)h //also correct
"show_buff_obj"+IntegerToString(h) //also correct

Finally you can cut way down on your on/off logic by simplifying your code, like this:

   string name = "show_buff_obj"+string(0);
   if(id==CHARTEVENT_OBJECT_CLICK && sparam == name)
      if(ObjectSetText(name, pressed_buffer?CharToStr(109):CharToStr(108), 12, "Wingdings", clrDodgerBlue))
         pressed_buffer = !pressed_buffer;
      else
         printf("there was an error setting the object text: Error(%d)", _LastError);

My final thoughts... if you need an object to toggle state, only use buttons or deal with the consequences. 

Reason: