Creating Multiple Canvas Panels in a Single Indicator

 
I want to build two information panels in one indicator and use the Canvas class for that.
Because I want only 2 bitmap label objects on chart.
I could find this article for creating a panel using canvas class, but unfortunately, it is only possible to create one panel in each indicator.

- If you have an example or solution for this, I would appreciate your guidance.

https://www.mql5.com/en/articles/13179
Making a dashboard to display data in indicators and EAs
Making a dashboard to display data in indicators and EAs
  • www.mql5.com
In this article, we will create a dashboard class to be used in indicators and EAs. This is an introductory article in a small series of articles with templates for including and using standard indicators in Expert Advisors. I will start by creating a panel similar to the MetaTrader 5 data window.
 
B.Moreno:
I want to build two information panels in one indicator and use the Canvas class for that.
Because I want only 2 bitmap label objects on chart.
I could find this article for creating a panel using canvas class, but unfortunately, it is only possible to create one panel in each indicator.

- If you have an example or solution for this, I would appreciate your guidance.

https://www.mql5.com/en/articles/13179

You can create as many canvases you like , there is no limitation 

Why only 2 bitmaps on the chart ?
 
Lorentzos Roussos #:

You can create as many canvases you like , there is no limitation 

  did it, but unfortunately, I encountered problems when moving the panels.
 
B.Moreno #:
  did it, but unfortunately, I encountered problems when moving the panels.

Are you sending events to both panels in OnChartEvent?

 
Lorentzos Roussos #:

Are you sending events to both panels in OnChartEvent?

Yes, let me share my sample code.
 
B.Moreno #:
Yes, let me share my sample code.

this is the section in the dashboard event handles that interests you:

send a &isDragged on the chart event of the dashboard.

Set it to true here and cancel it when draggin stops

have 2 booleans (global) , draggingA draggingB 

if either panel is dragged then dont send events to the other one.

else if(state==MOUSE_STATE_PRESSED_INSIDE_HEADER)
        {
         //--- Disable chart scrolling, right-click menu and crosshair 
         this.SetChartsTool(false);
         //--- Redraw the header area with a new background color 
         color new_color=this.NewColor(this.m_header_back_color,-10,-10,-10);
         if(this.m_header_back_color_c!=new_color)
           {
            this.RedrawHeaderArea(new_color);
            this.m_canvas.Update();
           }
         //--- Shift the panel following the cursor taking into account the amount of cursor displacement relative to the initial coordinates of the panel
         if(this.m_movable)
            this.Move(mouse_x-diff_x,mouse_y-diff_y);
         return;
        }
 
Lorentzos Roussos #:

Are you sending events to both panels in OnChartEvent?

//+------------------------------------------------------------------+
//|                                                TestDashboard.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window

#property indicator_buffers 1
#property indicator_plots   1

//--- includes
#include "Dashboard.mqh"

//---  variables

//--- panel 1
int  PanelX_1   =  20;            /* Dashboard X */ // Panel X coordinate
int  PanelY_1   =  20;            /* Dashboard Y */ // Panel Y coordinate
int  UniqID_1   =  0;             /* Unique ID   */ // Unique ID for the panel object

//--- panel 2
int  PanelX_2   =  200;            /* Dashboard X */ // Panel X coordinate
int  PanelY_2   =  200;            /* Dashboard Y */ // Panel Y coordinate
int  UniqID_2   =  1;              /* Unique ID   */ // Unique ID for the panel object



//--- global variables
CDashboard    *dashboard_1 = NULL;
CDashboard    *dashboard_2 = NULL;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Create the panel 2 object
   dashboard_1 = new CDashboard(UniqID_1, PanelX_1, PanelY_1, 200, 250);
   if(dashboard_1 == NULL)
   {
      Print("Error. Failed to create dashboard_1 object");
      return INIT_FAILED;
   }

//--- Create the panel 2 object
   dashboard_2 = new CDashboard(UniqID_2, PanelX_2, PanelY_2, 200, 250);
   if(dashboard_2 == NULL)
   {
      Print("Error. Failed to create dashboard_2 object");
      return INIT_FAILED;
   }

   
//--- Display the panel with the "Symbol, Timeframe description" header text
   dashboard_1.View(Symbol() + ", " + StringSubstr(EnumToString(Period()), 7));
   dashboard_2.View(Symbol() + ", " + StringSubstr(EnumToString(Period()), 7));

//--- Draw the name plate on the panel background
   dashboard_1.DrawGridAutoFill(2, 12, 2);
   dashboard_2.DrawGridAutoFill(2, 12, 2);

//--- Display tabular data in the journal
   dashboard_1.GridPrint(2);
   dashboard_2.GridPrint(2);

//--- Successful initialization
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- If the panel object exists, delete it
   if(dashboard_1 != NULL)
      delete dashboard_1;

   if(dashboard_2 != NULL)
      delete dashboard_2;
      
//--- Delete all comments
   Comment("");
}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
//--- Call the panel event handler
   dashboard_1.OnChartEvent(id, lparam, dparam, sparam);

   dashboard_2.OnChartEvent(id, lparam, dparam, sparam);

}
//+------------------------------------------------------------------+
//| 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 the next call
   return(rates_total);
}
 
B.Moreno #:

great

okay on the section quoted above , add a isDragged=true;

if you follow the elses in that section of the code in the article you will find the final else section

add isDragged=false; there

then on the header of the chartevent handler of the dashboard add ,bool &isDragged

then create 2 globals Dragging1=false; Dragging2=false;

reset them on init and deinit

pass them in on the 2 dashboard calls in on chart event.

gate the 2 onchart event calls with the opposite dragg not being true

 
Nice work by Artyom , i would not have thought to disable the right mouse button during drag. neat
 
Lorentzos Roussos #:
MOUSE_STATE_PRESSED_INSIDE_HEADER
Thanks for your guidance.
I'll try to see if I can do it or not. :-)