how to detect a Double Click event on a Chart ?

 

Hi,

How can I detect a double click event on a Chart ?

I can do it for a single click using :

void OnChartEvent(const int id,

                  const long &lparam,

                  const double &dparam,

                  const string &sparam)

{


//new logic

   if(id==CHARTEVENT_CLICK)

   { ......

 

is there an CHARTEVENT_DOUBLECLICK  event ?

 

Thanks in advance. 

 
jfortes: is there an CHARTEVENT_DOUBLECLICK  event ?
Do you see any in the documention? Types of Chart Events - MQL4 Documentation

 
jfortes:

Hi,

How can I detect a double click event on a Chart ?

I can do it for a single click using :

void OnChartEvent(const int id,

                  const long &lparam,

                  const double &dparam,

                  const string &sparam)

{


//new logic

   if(id==CHARTEVENT_CLICK)

   { ......

 

is there an CHARTEVENT_DOUBLECLICK  event ?

 

Thanks in advance. 


You cannot catch the system double-click event, but you may record the click time and coordinates and detect the double-click with your own metrics.
 

Thanks DeepThought, good suggestion.

I will try to implement the logic: if x,y coordinates are clicked twice then consider a double click event. Thanks. 

 
ulong click = 0;
ulong dclick = 200000;

int OnInit()
{
   return(INIT_SUCCEEDED);
}

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(rates_total);
}

void OnChartEvent(const int id,
                  const long& lparam,
                  const double& dparam,
                  const string& sparam)
{
   int x = (int)lparam;
   int y = (int)dparam;

   int window  = 0;
   datetime dt = 0;
   double   p  = 0;
   
   if (ChartXYToTimePrice(0, x, y, window, dt, p))
   {
      if (id == CHARTEVENT_CLICK)
      {
         if (GetMicrosecondCount() - click < dclick)
         {
            onDoubleClick(id, lparam, dparam, sparam);
            click = 0;
         } else {
            onClick(id, lparam, dparam, sparam);
            click = GetMicrosecondCount();
         }
      }
   }
}

void onDoubleClick(const int id,
                  const long& lparam,
                  const double& dparam,
                  const string& sparam)
{
   int x = (int)lparam;
   int y = (int)dparam;

   int window  = 0;
   datetime dt = 0;
   double   p  = 0;

   if (ChartXYToTimePrice(0, x, y, window, dt, p))
      onXYDoubleClick(window, x, y, dt, p);      
}

void onClick(const int id,
                  const long& lparam,
                  const double& dparam,
                  const string& sparam)
{
   int x = (int)lparam;
   int y = (int)dparam;

   int window  = 0;
   datetime dt = 0;
   double   p  = 0;

   if (ChartXYToTimePrice(0, x, y, window, dt, p))
      onXYClick(window, x, y, dt, p);      
}

void onXYDoubleClick(int window, int x, int y, datetime dt, double p)
{
}

void onXYClick(int window, int x, int y, datetime dt, double p)
{
}
 

//that's the sourcecode of an Indicator whose only purpose is to detect a doubleclick on the chart

//+------------------------------------------------------------------+
//|                                         detect a doubleclick.mq4 | //|                        Copyright 2017, MetaQuotes Software Corp. | //|                                        http://www.metaquotes.net | //+------------------------------------------------------------------+ #property copyright "Copyright 2017, MetaQuotes Software Corp." #property link      "http://www.metaquotes.net" #property  indicator_chart_window //************************************************************************************************************** //**************************************************************************************************************   int init() {    return(0) ; } //************************************************************************************************************** //************************************************************************************************************** int deinit() { return(0) ; } //************************************************************************************************************** //************************************************************************************************************** int start() { return(0) ; } //************************************************************************************************************** //************************************************************************************************************** void OnChartEvent(const int id,                   const long &lparam,                   const double &dparam,                   const string &sparam) {      if(id == CHARTEVENT_OBJECT_CLICK)  //custom defined Buttons for example      {         //Print("l: " + lparam + "      d: "  + dparam + "        s: " + sparam) ;                         return ;          }//end of: if(id == CHARTEVENT_OBJECT_CLICK)      //********************************************************      //********************************************************      if(id==CHARTEVENT_KEYDOWN)  //keystrokes      {         //Print("l: " + lparam + "      d: "  + dparam + "        s: " + sparam) ;                     return ;      }//end of: if(id==CHARTEVENT_KEYDOWN)           //********************************************************      //********************************************************      if(id==CHARTEVENT_CLICK)      {         //beginning of: detection of a doubleclick          static ulong ClickTimeMemory ; //static is crucial to remember ClickTimeMemory's content next time OnChartEvent() is called          //***                   ulong ClickTime = GetTickCount() ; //GetTickCount() uses milliseconds - it's not necessary to use GetMicrosecondCount()                   if(ClickTime > ClickTimeMemory && ClickTime < ClickTimeMemory + 300)   //the second click should appear within 300 milliseconds after the first click. That's 0.3 seconds - that's about the typical delay of the second click relative to the first click when making a doubleclick          {             Alert("just detected a doubleclick") ;          }                 //***                 ClickTimeMemory = ClickTime ;         //end of: detection of a doubleclick                       }//end of: if(id==CHARTEVENT_CLICK)      //********************************************************      //********************************************************      if(id == CHARTEVENT_MOUSE_MOVE)      {      }//end of: if(id == CHARTEVENT_MOUSE_MOVE)         //********************************************************      //********************************************************      return ;     }//end of: void OnChartEvent(...)
 
HaraldSchurr:

Thank you very much.

 
good info
 
HaraldSchurr:

Hi... just wanted to drop by and offer some tips to improve your code readability... 

  1. return statements are implicit with void functions so it is not necessary to include them, however, if you do you should keep them indented at the proper nesting level. 
  2. By convention, classes use the CapWords style and variables use either mixedWords or snake_case. Diverging from this convention makes it hard to read your code because when a seasoned developer sees ClickTimeMemory, it looks like a type declaration, and a variable is expected to follow. So as you can see, it's just more difficult to quickly mentally parse your code. 
  3. Accidental triple clicks will also register as a second double click, therefore it is advisable to reset your clickTimeMemory to zero and exit the block. 
Here's an example of these minor suggestions. 


void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   static ulong clickTimeMemory;
   
   if(id == CHARTEVENT_CLICK)
   { 
      ulong clickTime = GetTickCount();
      if(clickTime < clickTimeMemory + 300){
         Alert("just detected a doubleclick");
         clickTimeMemory = 0;
      }
      else
         clickTimeMemory = clickTime;    
   }
   else if(id == CHARTEVENT_MOUSE_MOVE){}
   else if(id == CHARTEVENT_KEYDOWN)
   {
      return;
   }
}
 
nicholi shen:

Hi... just wanted to drop by and offer some tips to improve your code readability... 

  1. return statements are implicit with void functions so it is not necessary to include them, however, if you do you should keep them indented at the proper nesting level. 
  2. By convention, classes use the CapWords style and variables use either mixedWords or snake_case. Diverging from this convention makes it hard to read your code because when a seasoned developer sees  ClickTimeMemory, it looks like a type declaration, and a variable is expected to follow. So as you can see, it's just more difficult to quickly mentally parse your code. 
  3. Accidental triple clicks will also register as a second double click, therefore it is advisable to reset your clickTimeMemory to zero and exit the block. 
Here's an example of these minor suggestions. 


Hi,

Why do you need the Mouse Move event and KeyDown event?

 

A double-click isn't recognized as such when the mouse moves between the two clicks, this should be taken into account. Same may hold for any key event between the clicks (Windows doesn't care but OP might.)

The code looks a bit easier to read with a switch.

const int DoubleClickDelayMillis = 500; // system default

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   static ulong lastClickTime=0;
   
   switch(id)
     {
      case CHARTEVENT_CLICK:
        {
         ulong clickTime = GetTickCount();
         if(clickTime < lastClickTime + DoubleClickDelayMillis)
           {
            Alert("just detected a doubleclick");
            lastClickTime = 0;
           }
         else
            lastClickTime = clickTime;
         break;
        }
      case CHARTEVENT_MOUSE_MOVE:
        {
         lastClickTime = 0;
         break;
        }
      case CHARTEVENT_KEYDOWN:
        {
         lastClickTime = 0;
         break;
        }
      ...
     }
  }

And did you know a triple-click will be recognized by Windows when for example you are going to mark a whole paragraph? Try it in the text above.
Reason: