Detecting Overlapping Objects Order

 

Probably a very simple question, but I am too stupid to sort it out.

When the graphic objects overlap in the chart, how do I learn their mutual position? E.g, which one is the topmost object?

I tried iterating the ObjectName() in a hope that it preserved the creation order, but obviously it did not. The index reads differently on each run.

 

Maybe not exactly what you need but in case of a mouse click you can specify which object gets the priority by specifying object property zorder.

https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjzorder

Documentation on MQL5: Standard Library / Panels and Dialogs / CWndObj / ZOrder
Documentation on MQL5: Standard Library / Panels and Dialogs / CWndObj / ZOrder
  • www.mql5.com
Standard Library / Panels and Dialogs / CWndObj / ZOrder - Reference on algorithmic/automated trading language for MetaTrader 5
 
Marco vd Heijden:

Maybe not exactly what you need but in case of a mouse click you can specify which object gets the priority by specifying object property zorder.

https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjzorder


Thank you, in fact I do not need it for the click event - it works properly, but rather for mouse move. Neither I do need changing the Z order, but I would like to know the topmost object under the mouse pointer.

 
Ex Ovo Omnia:

Thank you, in fact I do not need it for the click event - it works properly, but rather for mouse move. Neither I do need changing the Z order, but I would like to know the topmost object under the mouse pointer.

That's an interesting question but I am afraid there is no simple answer.

I would suggest to use OBJPROP_CREATETIME, the last object created should be the topmost. Of course it will also depend if you place it in background or not, or use Z order. And you will have to check which objects exist under the mouse pointer of course.

 

Why you don't care? The mouse can only drag one at a time, just look at the drag event to find which. See my GUI: Indicators: 'Money Manager Graphic Tool' indicator by 'takycard' Forum - Page 5

 
Alain Verleyen:

That's an interesting question but I am afraid there is no simple answer.

I would suggest to use OBJPROP_CREATETIME, the last object created should be the topmost. Of course it will also depend if you place it in background or not, or use Z order. And you will have to check which objects exist under the mouse pointer of course.


Thank you, though it looked promising first, all the objects in the chart have identical timestamps finally, especially after the indicators reinitialise with the timeframe change.

 
whroeder1:

Why you don't care? The mouse can only drag one at a time, just look at the drag event to find which. See my GUI: Indicators: 'Money Manager Graphic Tool' indicator by 'takycard' Forum - Page 5


Thank you, I will test your idea. At least if might solve selecting a single object for dragging.

EDIT: No, the object would need to be dragged by a single point, which is not what I could accept.

 
Ex Ovo Omnia:

Thank you, though it looked promising first, all the objects in the chart have identical timestamps finally, especially after the indicators reinitialise with the timeframe change.

Yeah, you would need to manage that all by yourself by saving the order in which you create your objects. Boring work.
 

You can also expand to using other languages inside or in conjunction with MQL to expand the possibilities.

For example i occasionally write HTML and JavaScript inside of MQL so i can access things like SVG and use the goodies of third party API's.

This way you can create complex and interactive products/charts that are close to impossible to create with MQL alone.

This is a good way to escape the obstacles, or limitations, and tackle the problems from other angles.

 

You can preserve the creation order if you're tracking it with OnChartEvent... similar to this...

//+------------------------------------------------------------------+
//|                                                  ObjectOrder.mq4 |
//|                                                      nicholishen |
//|                                   www.reddit.com/u/nicholishenFX |
//+------------------------------------------------------------------+
#property copyright "nicholishen"
#property link      "www.reddit.com/u/nicholishenFX"
#property version   "1.00"
#property strict
#property indicator_chart_window
#include <Arrays\ArrayObj.mqh>
//#include <Strings\StringEnhanced.mqh>
#include <ChartObjects\ChartObject.mqh>

class ObjectOrder : public CChartObject
{
protected:
   int m_order;
public:
      ObjectOrder(string name,int order):m_order(order){m_name = name;m_chart_id = ::ChartID();m_window = 0;}
int   Order() { return m_order;}
};

class ChartObjVector : public CArrayObj
{
public:
   ObjectOrder* operator[](int i){return (ObjectOrder*)At(i);}
   void Add(string name)
   {
      for(int i=0;i<Total();i++)
      {
         if(this[i].Name() == name)
            return;
      }
      ObjectOrder *obj =  new ObjectOrder(name,Total()+1);
      obj.Description("My order is "+string(obj.Order()));
      obj.Z_Order(obj.Order());
      obj.Selectable(true);
      obj.Tooltip(obj.Description());
      CArrayObj::Add(obj);
   }
   void Debug()
   {
      for(int i=0;i<Total();i++)
         ::Print("name = "+this[i].Name()+" | create-order = "+string(this[i].Order())+
                  " | z-order = "+string(this[i].Z_Order()));
   }
};

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   ChartEventCreate(true);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
ChartObjVector objs;

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
//---
   //String params = "id=={}, lparam=={}, dparam=={}, sparam=={}";
   //params.Format(id,lparam,dparam,sparam).Print();
   
   if(id==CHARTEVENT_OBJECT_CREATE)
   {
      objs.Add(sparam);
   }
   if(id==CHARTEVENT_CLICK)
   {
      objs.Debug();
   }
   
}
//+------------------------------------------------------------------+
bool ChartEventCreate(const bool value,const long chart_ID=0) 
  { 
//--- reset the error value 
   ResetLastError(); 
//--- set property value 
   if(!ChartSetInteger(chart_ID,CHART_EVENT_OBJECT_CREATE,0,value)) 
     { 
      //--- display the error message in Experts journal 
      Print(__FUNCTION__+", Error Code = ",GetLastError()); 
      return(false); 
     } 
//--- successful execution 
   return(true); 
  }
 
nicholishen:

You can preserve the creation order if you're tracking it with OnChartEvent... similar to this...


Yes, thank you, tracking all the objects on the chart did the job, though the implementation effort was quite inadequate to the resulting functionality.

Reason: