English Русский 中文 Español Deutsch Português
DoEasyライブラリのグラフィックス(第73部): グラフィック要素のフォームオブジェクト

DoEasyライブラリのグラフィックス(第73部): グラフィック要素のフォームオブジェクト

MetaTrader 5 | 30 9月 2021, 08:29
317 0
Artyom Trishkin
Artyom Trishkin

内容


概念

最新のプログラム、特に分析プログラムは、計算に大量のデータを使用することができます。しかし、視覚化なしで何かを理解することは難しいでしょう。また、明確で便利なインターフェイスなしでプログラムを最大限に使用することは非常に難しいでしょう。当然のことながら、グラフィックを操作する機能は、私たちのライブラリにとっても必須です。したがって、この記事では、グラフィック要素の操作に関する大きなセクションを開始します。

私の目的は、さまざまなグラフィカルオブジェクトを作成するための便利な機能を作成し、すべてのメインライブラリクラスがカスタムグラフィカルオブジェクトを使用してグラフィックをインタラクティブに操作できるようにし、複雑なコンポーネント階層を特徴とするグラフィカルオブジェクトを作成することです。

CCanvas標準ライブラリクラスに基づくグラフィッカルオブジェクトから始めます。このクラスを使用すると、カスタム画像を簡単に作成し、それらを基礎として使用して、より複雑なオブジェクトを作成できます。既製の画像を使用することも、作成したキャンバスにカスタム画像を描画することもできます。個人的には、後者のオプションの方がエキサイティングだと思うので、グラフィカルオブジェクトの設計に広く使用することにします。

単一のオブジェクトの階層は常に次のようになります。

  1. CObjectクラスに基づくすべてのライブラリグラフィック要素の基本オブジェクト。CCanvasクラスオブジェクトはその中で宣言されています。さらに、幅、高さ、チャートの座標、オブジェクトの右と下の境界線など、グラフィック要素に共通するすべてのパラメータが含まれています。
  2. グラフィック要素のオブジェクト形式 - グラフィカルオブジェクトの基礎(キャンバス)を表します。複合オブジェクトの他のすべての要素を含めます。そのパラメータを使用すると、グラフィカルオブジェクト全体のパラメータを設定できます。マウスステータス(カーソル座標と押されたボタン)を操作するメソッドを提供するクラスのオブジェクトもここで宣言されます。

階層は、CCanvasクラスに基づくすべてのライブラリグラフィカルオブジェクトの基本要素のハードコアを形成します。他のすべての作成されたオブジェクトはこのオブジェクトに基づいており、その基本的なプロパティを継承します。

それよりも、まず既製のライブラリクラスを少し改善して、ここで作成するオブジェクトの新しいデータを追加しましょう。


ライブラリクラスの改善

キャンバスパラメータの新しいサブセクションを\MQL5\Include\DoEasy\Defines.mqhに追加し、更新頻度のマクロ置換を追加します

//--- Parameters of the DOM snapshot series
#define MBOOKSERIES_DEFAULT_DAYS_COUNT (1)                        // The default required number of days for DOM snapshots in the series
#define MBOOKSERIES_MAX_DATA_TOTAL     (200000)                   // Maximum number of stored DOM snapshots of a single symbol
//--- Canvas parameters
#define PAUSE_FOR_CANV_UPDATE          (16)                       // Canvas update frequency
//+------------------------------------------------------------------+
//| Enumerations                                                     |
//+------------------------------------------------------------------+

キャンバスベースのオブジェクトは、16ミリ秒以内に更新(再描画)する必要があります。これにより、人間の目には見えないがシステムに余分な負荷がかかる画面の不要な再描画が排除されます。したがって、キャンバスベースのオブジェクトを更新する前に、前回の更新から何ミリ秒が経過したかを確認する必要があります。最適なレイテンシーを設定することで、グラフィカルオブジェクトを特徴とする画面の許容可能な表示を実現できます。

マウスボタンのステータス、およびShiftキーとCtrlキーのステータスを定義するために、マウスステータスオブジェクトのクラスを作成します。これを実現するには、2つの列挙が必要です。可能なマウスボタンのリストとShiftキーとCtrlキーの状態およびフォームに関連する可能なマウスステータスのリストです。それらをコードファイルの最後に追加します。

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Data for working with mouse                                      |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| The list of possible mouse buttons, Shift and Ctrl keys states   |
//+------------------------------------------------------------------+
enum ENUM_MOUSE_BUTT_KEY_STATE
  {
   MOUSE_BUTT_KEY_STATE_NONE              = 0,        // Nothing is clicked
//--- Mouse buttons
   MOUSE_BUTT_KEY_STATE_LEFT              = 1,        // The left mouse button is clicked
   MOUSE_BUTT_KEY_STATE_RIGHT             = 2,        // The right mouse button is clicked
   MOUSE_BUTT_KEY_STATE_MIDDLE            = 16,       // The middle mouse button is clicked
   MOUSE_BUTT_KEY_STATE_WHELL             = 128,      // Scrolling the mouse wheel
   MOUSE_BUTT_KEY_STATE_X1                = 32,       // The first additional mouse button is clicked
   MOUSE_BUTT_KEY_STATE_X2                = 64,       // The second additional mouse button is clicked
   MOUSE_BUTT_KEY_STATE_LEFT_RIGHT        = 3,        // The left and right mouse buttons clicked
//--- Keyboard keys
   MOUSE_BUTT_KEY_STATE_SHIFT             = 4,        // Shift is being held
   MOUSE_BUTT_KEY_STATE_CTRL              = 8,        // Ctrl is being held
   MOUSE_BUTT_KEY_STATE_CTRL_CHIFT        = 12,       // Ctrl and Shift are being held
//--- Left mouse button combinations
   MOUSE_BUTT_KEY_STATE_LEFT_WHELL        = 129,      // The left mouse button is clicked and the wheel is being scrolled
   MOUSE_BUTT_KEY_STATE_LEFT_SHIFT        = 5,        // The left mouse button is clicked and Shift is being held
   MOUSE_BUTT_KEY_STATE_LEFT_CTRL         = 9,        // The left mouse button is clicked and Ctrl is being held
   MOUSE_BUTT_KEY_STATE_LEFT_CTRL_CHIFT   = 13,       // The left mouse button is clicked, Ctrl and Shift are being held
//--- Right mouse button combinations
   MOUSE_BUTT_KEY_STATE_RIGHT_WHELL       = 130,      // The right mouse button is clicked and the wheel is being scrolled
   MOUSE_BUTT_KEY_STATE_RIGHT_SHIFT       = 6,        // The right mouse button is clicked and Shift is being held
   MOUSE_BUTT_KEY_STATE_RIGHT_CTRL        = 10,       // The right mouse button is clicked and Ctrl is being held
   MOUSE_BUTT_KEY_STATE_RIGHT_CTRL_CHIFT  = 14,       // The right mouse button is clicked, Ctrl and Shift are being held
//--- Middle mouse button combinations
   MOUSE_BUTT_KEY_STATE_MIDDLE_WHEEL      = 144,      // The middle mouse button is clicked and the wheel is being scrolled
   MOUSE_BUTT_KEY_STATE_MIDDLE_SHIFT      = 20,       // The middle mouse button is clicked and Shift is being held
   MOUSE_BUTT_KEY_STATE_MIDDLE_CTRL       = 24,       // The middle mouse button is clicked and Ctrl is being held
   MOUSE_BUTT_KEY_STATE_MIDDLE_CTRL_CHIFT = 28,       // The middle mouse button is clicked, Ctrl and Shift are being held
  };
//+------------------------------------------------------------------+
//| The list of possible mouse states relative to the form           |
//+------------------------------------------------------------------+
enum ENUM_MOUSE_FORM_STATE
  {
   MOUSE_FORM_STATE_NONE = 0,                         // Undefined state
//--- Outside the form
   MOUSE_FORM_STATE_OUTSIDE_NOT_PRESSED,              // The cursor is outside the form, the mouse buttons are not clicked
   MOUSE_FORM_STATE_OUTSIDE_PRESSED,                  // The cursor is outside the form, any mouse button is clicked
   MOUSE_FORM_STATE_OUTSIDE_WHEEL,                    // The cursor is outside the form, the mouse wheel is being scrolled
//--- Within the form
   MOUSE_FORM_STATE_INSIDE_NOT_PRESSED,               // The cursor is inside the form, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_PRESSED,                   // The cursor is inside the form, any mouse button is clicked
   MOUSE_FORM_STATE_INSIDE_WHEEL,                     // The cursor is inside the form, the mouse wheel is being scrolled
//--- Within the window header area
   MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED,   // The cursor is inside the active area, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED,       // The cursor is inside the active area,  any mouse button is clicked
   MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL,         // The cursor is inside the active area, the mouse wheel is being scrolled
//--- Within the window scrolling area
   MOUSE_FORM_STATE_INSIDE_SCROLL_NOT_PRESSED,        // The cursor is within the window scrolling area, the mouse buttons are not clicked
   MOUSE_FORM_STATE_INSIDE_SCROLL_PRESSED,            // The cursor is within the window scrolling area, any mouse button is clicked
   MOUSE_FORM_STATE_INSIDE_SCROLL_WHEEL,              // The cursor is within the window scrolling area, the mouse wheel is being scrolled
  };
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Data for handling graphical elements                             |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| The list of graphical element types                              |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_ELEMENT_TYPE
  {
   GRAPH_ELEMENT_TYPE_FORM,                           // Simple form
   GRAPH_ELEMENT_TYPE_WINDOW,                         // Window
  };
//+------------------------------------------------------------------+

グラフィック要素タイプのリストは、ここで作成されたクラスに基づく後続のクラスの「セキュアシート」に追加されました。このリストは今後の記事で入力され、使用されます。

可能なマウスボタン、ShiftおよびCtrl状態のリストには、基本的なマウスイベントとキーイベント、およびおそらく最も頻繁に必要となるそれらの組み合わせのいくつかが含まれています。
実際、マウスの状態は、 CHARTEVENT_MOUSE_MOVEイベントのヘルプで説明されているビットフラグの単純なセットです。

この表では、ビットと対応するマウスボタン、ShiftおよびCtrlの状態を指定しています。

ビット
 説明
0
 左マウスボタンのステータス
 1
1
 右マウスボタンのステータス
 2
2
 SHIFTのステータス
 4
3
 CTRLのステータス
 8
4
 中央マウスボタンのステータス
 16
5
 最初の追加のマウスボタンのステータス
 32
6
 2番目の追加のマウスボタンのステータス
 64

この表では、マウスステータスビットを格納する変数に設定された番号でマウスイベントを定義できます。

  • 左ボタンのみがクリックされた場合、変数は1に等しい
  • 左ボタンのみがクリックされた場合、変数は2に等しい
  • 両方のボタンがクリックされた場合、変数は3に等しい(1 + 2 = 3)
  • Shiftキーを押しながら左ボタンだけがクリックされた場合、変数は5に等しい(1 + 4 = 5)

このため、ENUM_MOUSE_BUTT_KEY_STATE列挙体の値は、表示された変数の計算に従って正確に設定され、列挙型定数によって記述されたフラグがアクティブになります。

ENUM_MOUSE_FORM_STATE列挙体は、マウスボタンのクリック/リリースで、フォームに対するマウスカーソルの位置を指定するために使用されます。マウスカーソル、そのボタン、および操作するオブジェクトの相対位置を定義するには、列挙定数の値が必要になります。

これらの2つの列挙をushort型変数の2バイトに格納すると、マウスとそのインタラクションオブジェクトで起こっていることの全体像を即座に把握することができます。この表には、変数のビットマップ全体が含まれています。

 ビット  バイト 状態

0
0
 左マウスボタン
1
1
0
 右マウスボタン
2
2
0
 SHIFT
4
3
0
 CTRL
8
4
0
 中央マウスボタン
16
5
0
 最初の追加のマウスボタン
32
6
0
 2番目の追加のマウスボタン
64
7
0
 ホイールをスクロールする
128
8 (0)
1
 フォーム内のカーソル
256
9 (1)
1
 フォームのアクティブ領域内のカーソル
512
10 (2)
1
 ウィンドウ制御領域内のカーソル(最小化/最大化/閉じるなど)
1024
11 (3)
1
 ウィンドウのスクロール領域内のカーソル
2048
12 (4)
1
 フォームの左端にあるカーソル
4096
13 (5)
1
 フォームの下端にあるカーソル
8192
14 (6)
1
 フォームの右端にあるカーソル
16384
15 (7)
1
 フォームの上端にあるカーソル
32768

今のところ、フォームオブジェクトとフォームに基づくウィンドウオブジェクトに対するマウスの状態とカーソル位置を示すフラグで十分です。

\MQL5\Include\DoEasy\Services\Pause.mqhの一時停止クラスオブジェクトを少し改善してみましょう。
SetTimeBegin()メソッドは、新しい一時停止カウントダウン時間を設定する以外に、メソッドに渡される時間をm_time_begin変数に設定します。
これは、データを操作ログに送信するためにのみ必要であり、メソッド内のどこかで一時停止をカウントするだけの場合は必要ありません。メソッドには任意の時間(ゼロを含む)を簡単に渡すことができますが、時間を指定せずにメソッドのオーバーロードを実装することにしました

//--- Set the new (1) countdown start time and (2) pause in milliseconds
   void              SetTimeBegin(const ulong time)         { this.m_time_begin=time; this.SetTimeBegin();              }
   void              SetTimeBegin(void)                     { this.m_start=this.TickCount();                            }
   void              SetWaitingMSC(const ulong pause)       { this.m_wait_msc=pause;                                    }

これで、マウスステータスオブジェクトクラスを作成できるようになりました。


マウスステータスクラス

サービス関数とクラスがある\MQL5\Include\DoEasy\Services\フォルダのMouseState.mqhにCMouseStateクラスを作成します。

クラスのprivateセクションで、オブジェクトパラメータを格納するための変数およびマウスボタンとキーの状態のフラグを設定するための2つのメソッドを宣言します。マウスの状態のビットフラグを格納するためのushort型変数でのビットフラグの位置に関する指示を残します

//+------------------------------------------------------------------+
//|                                                   MouseState.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "DELib.mqh"
//+------------------------------------------------------------------+
//| Mouse status class                                               |
//+------------------------------------------------------------------+
class CMouseState
  {
private:
   int               m_coord_x;                             // X coordinate
   int               m_coord_y;                             // Y coordinate
   int               m_delta_wheel;                         // Mouse wheel scroll value
   int               m_window_num;                          // Subwindow index
   long              m_chart_id;                            // Chart ID
   ushort            m_state_flags;                         // Status flags
   
//--- Set the status of mouse buttons, as well as of Shift and Ctrl keys
   void              SetButtonKeyState(const int id,const long lparam,const double dparam,const ushort flags);
//--- Set the mouse buttons and keys status flags
   void              SetButtKeyFlags(const short flags);

//--- Data location in the ushort value of the button status
   //-----------------------------------------------------------------
   //   bit    |    byte   |            state            |    dec    |
   //-----------------------------------------------------------------
   //    0     |     0     | left mouse button           |     1     |
   //-----------------------------------------------------------------
   //    1     |     0     | right mouse button          |     2     |
   //-----------------------------------------------------------------
   //    2     |     0     | SHIFT key                   |     4     |
   //-----------------------------------------------------------------
   //    3     |     0     | CTRL key                    |     8     |
   //-----------------------------------------------------------------
   //    4     |     0     | middle mouse button         |    16     |
   //-----------------------------------------------------------------
   //    5     |     0     | 1 add. mouse button         |    32     |
   //-----------------------------------------------------------------
   //    6     |     0     | 2 add. mouse button         |    64     |
   //-----------------------------------------------------------------
   //    7     |     0     | scrolling the wheel         |    128    |
   //-----------------------------------------------------------------
   //-----------------------------------------------------------------
   //    0     |     1     | cursor inside the form      |    256    |
   //-----------------------------------------------------------------
   //    1     |     1     | cursor inside active area   |    512    |
   //-----------------------------------------------------------------
   //    2     |     1     | cursor in the control area  |   1024    |
   //-----------------------------------------------------------------
   //    3     |     1     | cursor in the scrolling area|   2048    |
   //-----------------------------------------------------------------
   //    4     |     1     | cursor at the left edge     |   4096    |
   //-----------------------------------------------------------------
   //    5     |     1     | cursor at the bottom edge   |   8192    |
   //-----------------------------------------------------------------
   //    6     |     1     | cursor at the right edge    |   16384   |
   //-----------------------------------------------------------------
   //    7     |     1     | cursor at the top edge      |   32768   |
   //-----------------------------------------------------------------
      
public:

クラスのpublicセクションで、オブジェクトのプロパティ値を返すメソッドを設定します。

public:
//--- Reset the states of all buttons and keys
   void              ResetAll(void);
//--- Set (1) the subwindow index and (2) the chart ID
   void              SetWindowNum(const int wnd_num)           { this.m_window_num=wnd_num;        }
   void              SetChartID(const long id)                 { this.m_chart_id=id;               }
//--- Return the variable with the mouse status flags
   ushort            GetMouseFlags(void)                       { return this.m_state_flags;        }
//--- Return (1-2) the cursor coordinates, (3) scroll wheel value, (4) status of the mouse buttons and Shift/Ctrl keys
   int               CoordX(void)                        const { return this.m_coord_x;            }
   int               CoordY(void)                        const { return this.m_coord_y;            }
   int               DeltaWheel(void)                    const { return this.m_delta_wheel;        }
   ENUM_MOUSE_BUTT_KEY_STATE ButtKeyState(const int id,const long lparam,const double dparam,const string flags);

//--- Return the flag of the clicked (1) left, (2) right, (3) middle, (4) first and (5) second additional mouse buttons
   bool              IsPressedButtonLeft(void)           const { return this.m_state_flags==1;     }
   bool              IsPressedButtonRight(void)          const { return this.m_state_flags==2;     }
   bool              IsPressedButtonMiddle(void)         const { return this.m_state_flags==16;    }
   bool              IsPressedButtonX1(void)             const { return this.m_state_flags==32;    }
   bool              IsPressedButtonX2(void)             const { return this.m_state_flags==64;    }
//--- Return the flag of the pressed (1) Shift, (2) Ctrl, (3) Shift+Ctrl key and the flag of scrolling the mouse wheel
   bool              IsPressedKeyShift(void)             const { return this.m_state_flags==4;     }
   bool              IsPressedKeyCtrl(void)              const { return this.m_state_flags==8;     }
   bool              IsPressedKeyCtrlShift(void)         const { return this.m_state_flags==12;    }
   bool              IsWheel(void)                       const { return this.m_state_flags==128;   }

//--- Return the flag indicating the status of the left mouse button and (1) the mouse wheel, (2) Shift, (3) Ctrl, (4) Ctrl+Shift
   bool              IsPressedButtonLeftWheel(void)      const { return this.m_state_flags==129;   }
   bool              IsPressedButtonLeftShift(void)      const { return this.m_state_flags==5;     }
   bool              IsPressedButtonLeftCtrl(void)       const { return this.m_state_flags==9;     }
   bool              IsPressedButtonLeftCtrlShift(void)  const { return this.m_state_flags==13;    }
//--- Return the flag indicating the status of the right mouse button and (1) the mouse wheel, (2) Shift, (3) Ctrl, (4) Ctrl+Shift
   bool              IsPressedButtonRightWheel(void)     const { return this.m_state_flags==130;   }
   bool              IsPressedButtonRightShift(void)     const { return this.m_state_flags==6;     }
   bool              IsPressedButtonRightCtrl(void)      const { return this.m_state_flags==10;    }
   bool              IsPressedButtonRightCtrlShift(void) const { return this.m_state_flags==14;    }
//--- Return the flag indicating the status of the middle mouse button and (1) the mouse wheel, (2) Shift, (3) Ctrl, (4) Ctrl+Shift
   bool              IsPressedButtonMiddleWheel(void)    const { return this.m_state_flags==144;   }
   bool              IsPressedButtonMiddleShift(void)    const { return this.m_state_flags==20;    }
   bool              IsPressedButtonMiddleCtrl(void)     const { return this.m_state_flags==24;    }
   bool              IsPressedButtonMiddleCtrlShift(void)const { return this.m_state_flags==28;    }

//--- Constructor/destructor
                     CMouseState();
                    ~CMouseState();
  };
//+------------------------------------------------------------------+

ここには、クラス変数を返すメソッドと、事前定義されたマウスボタンとCtrl/Shiftキーの状態を返すいくつかのメソッドがあります。


クラスコンストラクタで、ボタンとキーのフラグの状態をリセットし、マウスホイールのスクロール値をリセットするメソッドを呼び出します

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMouseState::CMouseState() : m_delta_wheel(0),m_coord_x(0),m_coord_y(0),m_window_num(0)
  {
   this.ResetAll();
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMouseState::~CMouseState()
  {
  }
//+------------------------------------------------------------------+
//| Reset the states of all buttons and keys                         |
//+------------------------------------------------------------------+
void CMouseState::ResetAll(void)
  {
   this.m_delta_wheel = 0;
   this.m_state_flags = 0;
  }
//+------------------------------------------------------------------+

以下は、マウスボタンとShift/Ctrlキーのステータスを設定するメソッドです。

//+------------------------------------------------------------------+
//| Set the status of mouse buttons, as well as of Shift/Ctrl keys   |
//+------------------------------------------------------------------+
void CMouseState::SetButtonKeyState(const int id,const long lparam,const double dparam,const ushort flags)
  {
   //--- Reset the values of all mouse status bits
   this.ResetAll();
   //--- If a chart or an object is left-clicked
   if(id==CHARTEVENT_CLICK || id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Write the appropriate chart coordinates and set the bit of 0
      this.m_coord_x=(int)lparam;
      this.m_coord_y=(int)dparam;
      this.m_state_flags |=(0x0001);
     }
   //--- otherwise
   else
     {
      //--- in case of a mouse wheel scrolling
      if(id==CHARTEVENT_MOUSE_WHEEL)
        {
         //--- get the cursor coordinates and the total scroll value (the minimum of +120 or -120)
         this.m_coord_x=(int)(short)lparam;
         this.m_coord_y=(int)(short)(lparam>>16);
         this.m_delta_wheel=(int)dparam;
         //--- Call the method of setting flags indicating the states of the mouse buttons and Shift/Ctrl keys
         this.SetButtKeyFlags((short)(lparam>>32));
         //--- and set the bit of 8
         this.m_state_flags &=0xFF7F;
         this.m_state_flags |=(0x0001<<7);
        }
      //--- If this is a cursor movement, write its coordinates and
      //--- call the method of setting flags indicating the states of the mouse buttons and Shift/Ctrl keys
      if(id==CHARTEVENT_MOUSE_MOVE)
        {
         this.m_coord_x=(int)lparam;
         this.m_coord_y=(int)dparam;
         this.SetButtKeyFlags(flags);
        }
     }
  }
//+------------------------------------------------------------------+

ここでは、どのチャートイベントが処理されているかを確認します。
まず、マウスステータスビットフラグを格納している変数のすべてのビットをリセットします。
次に、チャートまたはオブジェクトがマウスでクリックされたイベントでは、ビットフラグを格納する変数にビット0を設定します。
マウスホイールのスクロールイベントの場合、lparam整数パラメータには、カーソル座標、スクロールサイズ、ボタンのビットフラグ、Ctrl/Shift状態に関するデータが含まれます。lparam変数からすべてのデータを抽出し、カーソル座標を格納する変数とビットフラグを使用してカスタム変数に書き込み、クラスのprivateセクションで説明されているビット順序が守られるようにします。次に、マウスホイールのスクロールイベントを示すビット8を設定します。
チャート上にカーソルが移動された場合、変数にカーソル座標を書き込み、マウスボタンとCtrl/Shiftステータスを示すビットフラグを設定するメソッドを呼び出します。

以下は、マウスボタンとキーを示すフラグを設定するメソッドです。

//+------------------------------------------------------------------+
//| Set the mouse buttons and keys status flags                      |
//+------------------------------------------------------------------+
void CMouseState::SetButtKeyFlags(const short flags)
  {
//--- Left mouse button status
   if((flags & 0x0001)!=0) this.m_state_flags |=(0x0001<<0);
//--- Right mouse button status
   if((flags & 0x0002)!=0) this.m_state_flags |=(0x0001<<1);
//--- SHIFT status
   if((flags & 0x0004)!=0) this.m_state_flags |=(0x0001<<2);
//--- CTRL status
   if((flags & 0x0008)!=0) this.m_state_flags |=(0x0001<<3);
//--- Middle mouse button status
   if((flags & 0x0010)!=0) this.m_state_flags |=(0x0001<<4);
//--- The first additional mouse button status
   if((flags & 0x0020)!=0) this.m_state_flags |=(0x0001<<5);
//--- The second additional mouse button status
   if((flags & 0x0040)!=0) this.m_state_flags |=(0x0001<<6);
  }
//+------------------------------------------------------------------+

ここではすべてが簡単です。メソッドは、マウスステータスフラグを表す変数を受け取ります検証済みビットが設置された状態でビットマスクを1つずつ適用します。ビットマスクを適用した後に取得された値は、両方の検証済みビットが設置されている場合にのみ、ビット単位の「AND」により真になります(1)。マスクが適用された変数がゼロに等しくない場合(検証済みビットが設置されている)、ビットフラグを格納するための適切なビットを変数に書き込みます

以下は、マウスボタンとShift/Ctrlキーを返すメソッドです。

//+------------------------------------------------------------------+
//| Return the mouse buttons and Shift/Ctrl keys states              |
//+------------------------------------------------------------------+
ENUM_MOUSE_BUTT_KEY_STATE CMouseState::ButtKeyState(const int id,const long lparam,const double dparam,const string flags)
  {
   this.SetButtonKeyState(id,lparam,dparam,(ushort)flags);
   return (ENUM_MOUSE_BUTT_KEY_STATE)this.m_state_flags;
  }
//+------------------------------------------------------------------+

ここでは、最初にすべてのマウスボタンとCtrl/Shiftキーのステータスフラグを確認して設定するメソッドを呼び出し、m_state_flags変数値をENUM_MOUSE_BUTT_KEY_STATE列挙型として返します。列挙では、すべての定数の値は、設置された可変ビットのセットによって取得された値に対応します。したがって、列挙値の1つをすぐに返します。この値は、マウス、そのボタン、Ctrl / Shiftキーの状態を必要とするクラスで処理されます。このメソッドはOnChartEvent()ハンドラから呼び出されます。


すべてのライブラリグラフィック要素の基本オブジェクトのクラス

メインライブラリクラスが標準ライブラリ基本クラスの子孫であるのと同様に、グラフィック要素オブジェクトのすべてのクラスはそこから継承する必要があります。このような継承により、標準のMQL5オブジェクトと同様に各グラフィカルオブジェクトを操作できます。つまり、CObjectクラスオブジェクトを処理するメソッドで、さまざまなタイプのグラフィカルオブジェクトを処理できることが重要です。これを実現するには、CObjectオブジェクトの子孫であり、各(および任意の)ライブラリグラフィカルオブジェクトに共通の変数とメソッドを含む新しい基本オブジェクトを作成する必要があります。

以下は、各グラフィカルオブジェクトに固有で、基本のグラフィカルオブジェクトに存在する一般的なプロパティです。

  • チャート上のオブジェクト座標
  • 要素(キャンバス)の幅と高さ。複合オブジェクトの他の要素(すべてのオブジェクトに共通の同じプロパティを含む)を特徴とします
  • キャンバスの右端と下端の座標(左端と上端は座標に対応)
  • さまざまなオブジェクトID(オブジェクトタイプ、名前、およびチャートIDとサブウィンドウID)
  • オブジェクトと対話するときのオブジェクトの動作を指定するいくつかの追加のフラグ

クラスは非常に単純です。private変数protected設定メソッド、それらの値を返すためのpublicメソッドです。
このクラスは、CObject標準ライブラリの基本クラスの子孫になります。

\MQL5\Include\DoEasy\Objects\で、CGBaseObjクラスのGBaseObj.mqhファイルを含むGraph\フォルダを作成します。

//+------------------------------------------------------------------+
//|                                                     GBaseObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\Services\DELib.mqh"
//+------------------------------------------------------------------+
//| Class of the base object of the library graphical objects        |
//+------------------------------------------------------------------+
class CGBaseObj : public CObject
  {
private:
   int               m_type;                                // Object type
   string            m_name_obj;                            // Object name
   long              m_chart_id;                            // Chart ID
   int               m_wnd_num;                             // Chart subwindow index
   int               m_coord_x;                             // Canvas X coordinate
   int               m_coord_y;                             // Canvas Y coordinate
   int               m_width;                               // Width
   int               m_height;                              // Height
   bool              m_movable;                             // Object movability flag
   bool              m_selectable;                          // Object selectability flag

protected:
//--- Set the values to class variables
   void              SetNameObj(const string name)             { this.m_name_obj=name;                            }
   void              SetChartID(const long chart_id)           { this.m_chart_id=chart_id;                        }
   void              SetWindowNum(const int wnd_num)           { this.m_wnd_num=wnd_num;                          }
   void              SetCoordX(const int coord_x)              { this.m_coord_x=coord_x;                          }
   void              SetCoordY(const int coord_y)              { this.m_coord_y=coord_y;                          }
   void              SetWidth(const int width)                 { this.m_width=width;                              }
   void              SetHeight(const int height)               { this.m_height=height;                            }
   void              SetMovable(const bool flag)               { this.m_movable=flag;                             }
   void              SetSelectable(const bool flag)            { this.m_selectable=flag;                          }
   
public:
//--- Return the values of class variables
   string            NameObj(void)                       const { return this.m_name_obj;                          }
   long              ChartID(void)                       const { return this.m_chart_id;                          }
   int               WindowNum(void)                     const { return this.m_wnd_num;                           }
   int               CoordX(void)                        const { return this.m_coord_x;                           }
   int               CoordY(void)                        const { return this.m_coord_y;                           }
   int               Width(void)                         const { return this.m_width;                             }
   int               Height(void)                        const { return this.m_height;                            }
   int               RightEdge(void)                     const { return this.m_coord_x+this.m_width;              }
   int               BottomEdge(void)                    const { return this.m_coord_y+this.m_height;             }
   bool              Movable(void)                       const { return this.m_movable;                           }
   bool              Selectable(void)                    const { return this.m_selectable;                        }
   
//--- The virtual method returning the object type
   virtual int       Type(void)                          const { return this.m_type;                              }

//--- Constructor/destructor
                     CGBaseObj();
                    ~CGBaseObj();
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CGBaseObj::CGBaseObj() : m_chart_id(::ChartID()),
                         m_type(WRONG_VALUE),
                         m_wnd_num(0),
                         m_coord_x(0),
                         m_coord_y(0),
                         m_width(0),
                         m_height(0),
                         m_movable(false),
                         m_selectable(false)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CGBaseObj::~CGBaseObj()
  {
  }
//+------------------------------------------------------------------+

CObject基本オブジェクトクラスは、オブジェクトの型を返す仮想Type()メソッドを備えています(オブジェクトを型で識別するため)。元のメソッドは常にゼロを返します。

   //--- method of identifying the object
   virtual int       Type(void)                                    const { return(0);      }

子孫でメソッドを再定義することにより、m_type変数に設定されたオブジェクト型を返します。
グラフィカルオブジェクトタイプは、オブジェクトクラスを作成するときに後続の記事で設定されます。その間、メソッドは-1を返します(これはクラスコンストラクタの初期化リストで設定した値です)。


グラフィック要素のフォームオブジェクトのクラス

フォームオブジェクトは、CCanvasクラスに基づいてライブラリのグラフィック要素の残りのクラスを作成するための基礎です。さまざまなオブジェクトに必要なデータを描画したり、他の要素を配置したりするための「キャンバス」として使用され、最終的には既製のオブジェクトが表示されます。

今のところ、これは基本的なパラメータと機能(カーソルの操作に使用されるアクティブ領域を設定する機能)、およびチャートに沿って移動する機能を備えた単純なフォームになります。

\MQL5\Include\DoEasy\Objects\Graph\で、CFormクラスのForm.mqhファイルを作成します。
クラスは、すべてのライブラリグラフィカルオブジェクトの基本オブジェクトの子孫である必要があります。したがって、基本グラフィカルオブジェクトのファイルマウスプロパティオブジェクトクラスを含める必要があります。

//+------------------------------------------------------------------+
//|                                                         Form.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Canvas\Canvas.mqh>
#include "GBaseObj.mqh"
#include "..\..\Services\MouseState.mqh"
//+------------------------------------------------------------------+
//| Class of the base object of the library graphical objects        |
//+------------------------------------------------------------------+
class CForm : public CGBaseObj
  {
  }

クラスのprotectedセクションで、 CCanvas標準ライブラリクラスCPauseおよびCMouseStateライブラリクラスオブジェクトマウスステータス値を格納するための変数マウスステータスビットフラグを格納するための変数オブジェクトプロパティを格納するための変数を宣言します。

//+------------------------------------------------------------------+
//| Class of the base object of the library graphical objects        |
//+------------------------------------------------------------------+
class CForm : public CGBaseObj
  {
protected:
   CCanvas              m_canvas;                              // CCanvas class object
   CPause               m_pause;                               // Pause class object
   CMouseState          m_mouse;                               // "Mouse status" class object
   ENUM_MOUSE_FORM_STATE m_mouse_state;                        // Mouse status relative to the form
   ushort               m_mouse_state_flags;                   // Mouse status flags
   
   int                  m_act_area_left;                       // Left border of the active area (offset from the left border inward)
   int                  m_act_area_right;                      // Right border of the active area (offset from the right border inward)
   int                  m_act_area_top;                        // Upper border of the active area (offset from the upper border inward)
   int                  m_act_area_bottom;                     // Lower border of the active area (offset from the lower border inward)
   uchar                m_opacity;                             // Opacity
   int                  m_shift_y;                             // Y coordinate shift for the subwindow
   
private:

クラスのprivateセクションで、クラス操作の補助メソッドを宣言します。

private:
//--- Set and return the flags indicating the states of mouse buttons and Shift/Ctrl keys
   ENUM_MOUSE_BUTT_KEY_STATE MouseButtonKeyState(const int id,const long lparam,const double dparam,const string sparam)
                       {
                        return this.m_mouse.ButtKeyState(id,lparam,dparam,sparam);
                       }
//--- Return the cursor position relative to the (1) form and (2) active area
   bool              CursorInsideForm(const int x,const int y);
   bool              CursorInsideActiveArea(const int x,const int y);

public:

MouseButtonKeyState()メソッドは、同じ名前のメソッドによってマウスステータスクラスオブジェクトから返された値を返します。フォームとフォームのアクティブ領域に対するマウスカーソルの位置を定義するには、他の2つのメソッドが必要です。これは後で検討します。

クラスのpublicセクションには、フォームを作成し、設置して、そのパラメータを返すためのメソッドがあります。

public:
//--- Create a form
   bool              CreateForm(const long chart_id,
                                const int wnd_num,
                                const string name,
                                const int x,
                                const int y,
                                const int w,
                                const int h,
                                const color colour,
                                const uchar opacity,
                                const bool movable=true,
                                const bool selectable=true);
                                
//--- Return the pointer to a canvas object
   CCanvas          *CanvasObj(void)                           { return &this.m_canvas;                           }
//--- Set (1) the form update frequency, (2) the movability flag and (3) selectability flag for interaction
   void              SetFrequency(const ulong value)           { this.m_pause.SetWaitingMSC(value);               }
   void              SetMovable(const bool flag)               { CGBaseObj::SetMovable(flag);                     }
   void              SetSelectable(const bool flag)            { CGBaseObj::SetSelectable(flag);                  }
//--- Update the form coordinates (shift the form)
   bool              Move(const int x,const int y,const bool redraw=false);
   
//--- Return the mouse status relative to the form
   ENUM_MOUSE_FORM_STATE MouseFormState(const int id,const long lparam,const double dparam,const string sparam);
//--- Return the flag of the clicked (1) left, (2) right, (3) middle, (4) first and (5) second additional mouse buttons
   bool              IsPressedButtonLeftOnly(void)             { return this.m_mouse.IsPressedButtonLeft();       }
   bool              IsPressedButtonRightOnly(void)            { return this.m_mouse.IsPressedButtonRight();      }
   bool              IsPressedButtonMiddleOnly(void)           { return this.m_mouse.IsPressedButtonMiddle();     }
   bool              IsPressedButtonX1Only(void)               { return this.m_mouse.IsPressedButtonX1();         }
   bool              IsPressedButtonX2Only(void)               { return this.m_mouse.IsPressedButtonX2();         }
//--- Return the flag of the pressed (1) Shift and (2) Ctrl key
   bool              IsPressedKeyShiftOnly(void)               { return this.m_mouse.IsPressedKeyShift();         }
   bool              IsPressedKeyCtrlOnly(void)                { return this.m_mouse.IsPressedKeyCtrl();          }
   
//--- Set the shift of the (1) left, (2) top, (3) right, (4) bottom edge of the active area relative to the form,
//--- (5) all shifts of the active area edges relative to the form and (6) the form opacity
   void              SetActiveAreaLeftShift(const int value)   { this.m_act_area_left=fabs(value);                }
   void              SetActiveAreaRightShift(const int value)  { this.m_act_area_right=fabs(value);               }
   void              SetActiveAreaTopShift(const int value)    { this.m_act_area_top=fabs(value);                 }
   void              SetActiveAreaBottomShift(const int value) { this.m_act_area_bottom=fabs(value);              }
   void              SetActiveAreaShift(const int left_shift,const int bottom_shift,const int right_shift,const int top_shift);
   void              SetOpacity(const uchar value)             { this.m_opacity=value;                            }
//--- Return the coordinate (1) of the left, (2) right, (3) top and (4) bottom edge of the form active area
   int               ActiveAreaLeft(void)                const { return this.CoordX()+this.m_act_area_left;       }
   int               ActiveAreaRight(void)               const { return this.RightEdge()-this.m_act_area_right;   }
   int               ActiveAreaTop(void)                 const { return this.CoordY()+this.m_act_area_top;        }
   int               ActiveAreaBottom(void)              const { return this.BottomEdge()-this.m_act_area_bottom; }
//--- Return (1) the form opacity, coordinate (2) of the right and (3) bottom form edge
   uchar             Opacity(void)                       const { return this.m_opacity;                           }
   int               RightEdge(void)                     const { return CGBaseObj::RightEdge();                   }
   int               BottomEdge(void)                    const { return CGBaseObj::BottomEdge();                  }

//--- Event handler
   void              OnChartEvent(const int id,const long& lparam,const double& dparam,const string& sparam);

//--- Constructors/Destructor
                     CForm(const long chart_id,
                           const int wnd_num,
                           const string name,
                           const int x,
                           const int y,
                           const int w,
                           const int h,
                           const color colour,
                           const uchar opacity,
                           const bool movable=true,
                           const bool selectable=true);
                     CForm(){;}
                    ~CForm();
  };
//+------------------------------------------------------------------+

クラスメソッドについて詳しく考えてみましょう。

パラメトリックコンストラクタで、コンストラクタに渡されたパラメータを使用してフォームオブジェクトを作成します。

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CForm::CForm(const long chart_id,
             const int wnd_num,
             const string name,
             const int x,
             const int y,
             const int w,
             const int h,
             const color colour,
             const uchar opacity,
             const bool movable=true,
             const bool selectable=true) : m_act_area_bottom(0),
                                           m_act_area_left(0),
                                           m_act_area_right(0),
                                           m_act_area_top(0),
                                           m_mouse_state(0),
                                           m_mouse_state_flags(0)
                                          
  {
   if(this.CreateForm(chart_id,wnd_num,name,x,y,w,h,colour,opacity,movable,selectable))
     {
      this.m_shift_y=(int)::ChartGetInteger(chart_id,CHART_WINDOW_YDISTANCE,wnd_num);
      this.SetWindowNum(wnd_num);
      this.m_pause.SetWaitingMSC(PAUSE_FOR_CANV_UPDATE);
      this.m_pause.SetTimeBegin();
      this.m_mouse.SetChartID(chart_id);
      this.m_mouse.SetWindowNum(wnd_num);
      this.m_mouse.ResetAll();
      this.m_mouse_state_flags=0;
      CGBaseObj::SetMovable(movable);
      CGBaseObj::SetSelectable(selectable);
      this.SetOpacity(opacity);
     }
  }
//+------------------------------------------------------------------+

ここでは、最初にコンストラクタ初期化リストのすべての変数を初期化します。次に、フォーム作成メソッドを呼び出します。フォームが正常に作成されたら、コンストラクタに渡されるパラメーターを設定します。

クラスデストラクタで、作成したグラフィカルオブジェクトを削除します。

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CForm::~CForm()
  {
   ::ObjectsDeleteAll(this.ChartID(),this.NameObj());
  }
//+------------------------------------------------------------------+


以下は、グラフィカルフォームオブジェクトを作成するメソッドです。

//+------------------------------------------------------------------+
//| Create the graphical form object                                 |
//+------------------------------------------------------------------+
bool CForm::CreateForm(const long chart_id,
                       const int wnd_num,
                       const string name,
                       const int x,
                       const int y,
                       const int w,
                       const int h,
                       const color colour,
                       const uchar opacity,
                       const bool movable=true,
                       const bool selectable=true)
  {
   if(this.m_canvas.CreateBitmapLabel(chart_id,wnd_num,name,x,y,w,h,COLOR_FORMAT_ARGB_NORMALIZE))
     {
      this.SetChartID(chart_id);
      this.SetWindowNum(wnd_num);
      this.SetNameObj(name);
      this.SetCoordX(x);
      this.SetCoordY(y);
      this.SetWidth(w);
      this.SetHeight(h);
      this.SetActiveAreaLeftShift(1);
      this.SetActiveAreaRightShift(1);
      this.SetActiveAreaTopShift(1);
      this.SetActiveAreaBottomShift(1);
      this.SetOpacity(opacity);
      this.SetMovable(movable);
      this.SetSelectable(selectable);
      this.m_canvas.Erase(::ColorToARGB(colour,this.Opacity()));
      this.m_canvas.Update();
      return true;
     }
   return false;
  }
//+------------------------------------------------------------------+

CCanvasクラスのCreateBitmapLabel()メソッドを使用して、グラフIDとサブウィンドウインデックス(フォームを呼び出す2番目のメソッド)を使用するグラフィカルリソースを作成します。グラフィカルリソースが正常に作成されたら、メソッドに渡されるすべてのパラメータを設定し、フォームに色を追加し、Erase()メソッドを使用して不透明度を設定し、Update()メソッドを使用して画面に変更を表示します

ここで「不透明度」または色濃度という用語を明確にしたいと思います。CCanvasクラスではオブジェクトの透明度を設定できます。0は完全に透明な色を意味し、255は完全に不透明な色を意味します。ここではすべてが逆になっているようです。したがって、0〜255の値は、ゼロ(完全に透明)から255(完全に不透明)への色濃度の増加に正確に対応するため、「不透明度」という用語を使用することにしました。

以下は、CFormクラスのイベントハンドラーです。

//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CForm::OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Get the status of mouse buttons, Shift/Ctrl keys and the state of a mouse relative to the form
   ENUM_MOUSE_BUTT_KEY_STATE mouse_state=this.m_mouse.ButtKeyState(id,lparam,dparam,sparam);
   this.m_mouse_state=this.MouseFormState(id,lparam,dparam-this.m_shift_y,sparam);
//--- Initialize the difference between X and Y coordinates of the form and cursor
   static int diff_x=0;
   static int diff_y=0;
//--- In case of a chart change event, recalculate the shift by Y for the subwindow
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      this.m_shift_y=(int)::ChartGetInteger(this.ChartID(),CHART_WINDOW_YDISTANCE,this.WindowNum());
     }
//--- If the cursor is inside the form, disable chart scrolling, context menu and Crosshair tool
   if((this.m_mouse_state_flags & 0x0100)!=0)
     {
      ::ChartSetInteger(this.ChartID(),CHART_MOUSE_SCROLL,false);
      ::ChartSetInteger(this.ChartID(),CHART_CONTEXT_MENU,false);
      ::ChartSetInteger(this.ChartID(),CHART_CROSSHAIR_TOOL,false);
     }
//--- Otherwise, if the cursor is outside the form, allow chart scrolling, context menu and Crosshair tool
   else
     {
      ::ChartSetInteger(this.ChartID(),CHART_MOUSE_SCROLL,true);
      ::ChartSetInteger(this.ChartID(),CHART_CONTEXT_MENU,true);
      ::ChartSetInteger(this.ChartID(),CHART_CROSSHAIR_TOOL,true);
     }
//--- If the mouse movement event and the cursor are located in the form active area
   if(id==CHARTEVENT_MOUSE_MOVE && m_mouse_state==MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED)
     {
      //--- If only the left mouse button is being held and the form is moved,
      //--- set the new parameters of moving the form relative to the cursor
      if(IsPressedButtonLeftOnly() && this.Move(this.m_mouse.CoordX()-diff_x,this.m_mouse.CoordY()-diff_y))
        {
         diff_x=this.m_mouse.CoordX()-this.CoordX();
         diff_y=this.m_mouse.CoordY()-this.CoordY();
        }
     }
//--- In any other cases, set the parameters of shifting the form relative to the cursor
   else
     {
      diff_x=this.m_mouse.CoordX()-this.CoordX();
      diff_y=this.m_mouse.CoordY()-this.CoordY();
     }
//--- Test display of mouse states on the chart
   Comment(EnumToString(mouse_state),"\n",EnumToString(this.m_mouse_state));
  }
//+------------------------------------------------------------------+

ロジック全体はコメントで明確にされています。このメソッドは、プログラムのOnChartEvent()標準ハンドラから呼び出す必要があり、まったく同じパラメータを持っています。

MouseFormState()メソッドに渡される専用の計算について説明します。フォームがメインチャートウィンドウにある場合、m_shift_y変数はゼロに等しく、式dparam-this.m_shift_yは正確なYカーソル座標を返します。ただし、フォームがチャートサブウィンドウにある場合、m_shift_y変数のシフトがゼロを超えて、Yカーソル座標がサブウィンドウ座標に調整されます。したがって、m_shift_yで設定されたシフトを持つY座標もカーソル座標の計算方法に渡す必要があります。それ以外の場合、オブジェクトの座標は、変数で指定されたシフトのピクセル数だけ実際よりも高くなります。

以下は、フォームに対するカーソル位置を返すメソッドです。

//+------------------------------------------------------------------+
//| Return the cursor position relative to the form                  |
//+------------------------------------------------------------------+
bool CForm::CursorInsideForm(const int x,const int y)
  {
   return(x>=this.CoordX() && x<this.RightEdge() && y>=this.CoordY() && y<=this.BottomEdge());
  }
//+------------------------------------------------------------------+

このメソッドは、カーソルのX座標とY座標を受け取ります。

次の場合

  • (カーソルのX座標がフォームのX座標以上である、および、カーソルのX座標がフォームの右端の座標以下である)、および
  • (カーソルのY座標がフォームのY座標以上である、および、カーソルのY座標がフォームの下端の座標以下である)

trueが返されます(カーソルはフォームオブジェクト内にあります)

以下は、フォームのアクティブ領域に対するカーソル位置を返すメソッドです。

//+------------------------------------------------------------------+
//| Return the cursor position relative to the form active area      |
//+------------------------------------------------------------------+
bool CForm::CursorInsideActiveArea(const int x,const int y)
  {
   return(x>=this.ActiveAreaLeft() && x<this.ActiveAreaRight() && y>=this.ActiveAreaTop() && y<=this.ActiveAreaBottom());
  }
//+------------------------------------------------------------------+

このメソッドは、カーソルのX座標とY座標を受け取ります。

次の場合

  • (カーソルのX座標がフォームのアクティブ領域のX座標以上である、および、カーソルのX座標がフォームのアクティブ領域の右端の座標以下である)、および
  • (カーソルのY座標がフォームのアクティブ領域のY座標以上である、および、カーソルのY座標がフォームのアクティブ領域の下端の座標以下である)

trueが返されます(カーソルはフォームオブジェクトのアクティブ領域内にあります)

以下は、フォームに対するマウスのステータスを返すメソッドです。

//+------------------------------------------------------------------+
//| Return the mouse status relative to the form                     |
//+------------------------------------------------------------------+
ENUM_MOUSE_FORM_STATE CForm::MouseFormState(const int id,const long lparam,const double dparam,const string sparam)
  {
//--- Get the mouse status relative to the form, as well as the states of mouse buttons and Shift/Ctrl keys
   ENUM_MOUSE_FORM_STATE form_state=MOUSE_FORM_STATE_NONE;
   ENUM_MOUSE_BUTT_KEY_STATE state=this.MouseButtonKeyState(id,lparam,dparam,sparam);
//--- Get the mouse status flags from the CMouseState class object and save them in the variable
   this.m_mouse_state_flags=this.m_mouse.GetMouseFlags();
//--- If the cursor is inside the form
   if(this.CursorInsideForm(m_mouse.CoordX(),m_mouse.CoordY()))
     {
      //--- Set bit 8 responsible for the "cursor inside the form" flag
      this.m_mouse_state_flags |= (0x0001<<8);
      //--- If the cursor is inside the active area, set bit 9 "cursor inside the active area"
      if(CursorInsideActiveArea(m_mouse.CoordX(),m_mouse.CoordY()))
         this.m_mouse_state_flags |= (0x0001<<9);
      //--- otherwise, release the bit "cursor inside the active area"
      else this.m_mouse_state_flags &=0xFDFF;
      //--- If one of the mouse buttons is clicked, check the cursor location in the active area and
      //--- return the appropriate value of the pressed key (in the active area or the form area)
      if((this.m_mouse_state_flags & 0x0001)!=0 || (this.m_mouse_state_flags & 0x0002)!=0 || (this.m_mouse_state_flags & 0x0010)!=0)
         form_state=((m_mouse_state_flags & 0x0200)!=0 ? MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED : MOUSE_FORM_STATE_INSIDE_PRESSED);
      //--- otherwise, check the cursor location in the active area and
      //--- return the appropriate value of the unpressed key (in the active area or the form area)
      else
         form_state=((m_mouse_state_flags & 0x0200)!=0 ? MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED : MOUSE_FORM_STATE_INSIDE_NOT_PRESSED);
     }
   return form_state;
  }
//+------------------------------------------------------------------+

各コード文字列は、コードコメントで明確にされています。簡単に言うと、マウスステータスクラスオブジェクトから既製のマウスステータスを取得し、それを m_mouse_state_flags変数に書き込みます。次に、フォームに対するカーソルの位置に応じて、マウスステータスビットフラグに新しいデータを追加し、記事の冒頭で前述したENUM_MOUSE_FORM_STATE列挙形式でマウスステータスを返します。

以下は、フォームの座標を更新するメソッド(チャート上でフォームをシフトする)です。

//+------------------------------------------------------------------+
//| Update the form coordinates                                      |
//+------------------------------------------------------------------+
bool CForm::Move(const int x,const int y,const bool redraw=false)
  {
//--- If the form is not movable, leave
   if(!this.Movable())
      return false;
//--- If new values are successfully set into graphical object properties
   if(::ObjectSetInteger(this.ChartID(),this.NameObj(),OBJPROP_XDISTANCE,x) &&
      ::ObjectSetInteger(this.ChartID(),this.NameObj(),OBJPROP_YDISTANCE,y))
     {
      //--- set the new values of X and Y coordinate properties
      this.SetCoordX(x);
      this.SetCoordY(y);
      //--- If the update flag is activated, redraw the chart.
      if(redraw)
         ::ChartRedraw(this.ChartID());
      //--- Return 'true'
      return true;
     }
//--- Something is wrong...
   return false;
  }
//+------------------------------------------------------------------+

このメソッドは、フォームオブジェクトをシフトする座標を受け取ります。新しい座標パラメータがグラフィカルフォームオブジェクトに正常に設定されたら、これらの座標をオブジェクトプロパティに書き込み、再描画フラグ(メソッドにも渡されます)がアクティブになっている場合にのみグラフを再描画します。グラフィカルオブジェクトが多くのフォームで構成されている場合、複数のチャートの再描画を回避するには、フラグ値による再描画が必要です。この場合、最初に1つのオブジェクトのすべてのフォームを移動する必要があります。各フォームが新しい座標を受け取ったら、グラフを1回更新します。

以下は、フォームに対するアクティブ領域のすべてのシフトを設定するメソッドです。

//+------------------------------------------------------------------+
//| Set all shifts of the active area relative to the form           |
//+------------------------------------------------------------------+
void CForm::SetActiveAreaShift(const int left_shift,const int bottom_shift,const int right_shift,const int top_shift)
  {
   this.SetActiveAreaLeftShift(left_shift);
   this.SetActiveAreaBottomShift(bottom_shift);
   this.SetActiveAreaRightShift(right_shift);
   this.SetActiveAreaTopShift(top_shift);
  }
//+------------------------------------------------------------------+

アクティブ領域の境界を個別に設定するメソッドがあります。ただし、1つのメソッドの1回の呼び出しですべての境界線を設定する必要がある場合があります。これはまさにメトッドが行うことです。適切なメソッドの呼び出しを使用して、フォームの端からオフセットされたアクティブ領域の境界の新しい値を設定します。

これで、フォームオブジェクトの最初のバージョンの作成が完了しました。結果をテストしてみましょう。

検証

テストを実行するには、グラフ上に単一のフォームオブジェクトを作成し、カーソルを使用して移動してみましょう。さらに、マウスボタンとCtrl/Shiftキーの状態、およびアクティブ領域のフォームと境界線に対するカーソルのステータスを表示します。

\MQL5\Experts\TestDoEasy\Part73\で、新しいEAファイルTestDoEasyPart73.mq5を作成します。

EAファイルを作成するときに、bool型のInpMovable入力と初期のtrue値が必要であることを指定します。


次に、追加のOnChartEvent()ハンドラが必要であることを指定します。


その結果、次のEAワークピースが得られます。

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart73.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//--- input parameters
input bool     InpMovable=true;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   
  }
//+------------------------------------------------------------------+

新しく作成されたフォームオブジェクトクラスをEAファイルにインクルードし、2つのグローバル変数(オブジェクト名プレフィックスCFormクラスオブジェクト)を宣言します。

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart73.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//--- includes
#include <DoEasy\Objects\Graph\Form.mqh>
//--- input parameters
sinput   bool  InpMovable  = true;  // Movable flag
//--- global variables
string         prefix;
CForm          form;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

OnInit()ハンドラで、マウスカーソルの移動とマウスのスクロールイベントを送信する権限を有効にし、オブジェクト名のプレフィックスの値を(ファイル名)+ "_"に設定して、チャート上にフォームオブジェクトを作成します。作成後、アクティブゾーンの境界に10ピクセルのオフセットを設定します。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set the permissions to send cursor movement and mouse scroll events
   ChartSetInteger(ChartID(),CHART_EVENT_MOUSE_MOVE,true);
   ChartSetInteger(ChartID(),CHART_EVENT_MOUSE_WHEEL,true);
//--- Set EA global variables
   prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_";
//--- If the form is created, set an active area for it with the offset of 10 pixels from the edges
   if(form.CreateForm(ChartID(),0,prefix+"Form_01",300,20,100,70,clrSilver,200,InpMovable))
     {
      form.SetActiveAreaShift(10,10,10,10);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

後は、EAのOnChartEvent()ハンドラからフォームオブジェクトのOnChartEvent()ハンドラを呼び出すだけです。

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   form.OnChartEvent(id,lparam,dparam,sparam);
  }
//+------------------------------------------------------------------+

EAをコンパイルし、銘柄チャートで起動します。


ご覧のとおり、ボタンとカーソルの状態が正しく表示されています。フォームオブジェクトは、アクティブ領域内でマウスでつかまれた場合にのみ移動します。

フォーム内でマウスの右ボタンと中ボタンをクリックしても、コンテキストメニューと十字ツールはアクティブになりません。ここで、おかしイ問題に直面します。ウィンドウの外側で十字線ツールを有効にしてから、フォームのアクティブな領域にカーソルを合わせると(マウスの左ボタンを押したまま)、シフトが始まります。この動作は正しくありません。しかし、これはほんの始まりに過ぎません。今後の記事では、フォームオブジェクトを改善し、新しい機能を追加します。

次の段階

次の記事では、フォームオブジェクトクラスの開発を続けます。

ライブラリの現在のバージョンのすべてのファイルは、テストおよびダウンロードできるように、MQL5のテストEAファイルと一緒に以下に添付されています。
質問や提案はコメント欄にお願いします。

目次に戻る

*これまでの連載の最終記事:

DoEasyライブラリでのその他のクラス(第72部): コレクション内のチャートオブジェクトパラメータの追跡と記録

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/9442

添付されたファイル |
MQL5.zip (3954.84 KB)
取引のための組合せ論と確率論(第I部):基本 取引のための組合せ論と確率論(第I部):基本
この連載では、確率論の実用的応用を見つけて、取引と価格設定のプロセスの説明を試みます。最初の記事では、組合せ論と確率の基礎を調べ、確率論の枠組みでフラクタルを適用する方法の最初の例を分析します。
パターンと例(第I部): マルチトップ パターンと例(第I部): マルチトップ
これは、アルゴリズム取引の枠組みにおける反転パターンに関連する連載の最初の記事です。まず、最も興味深いパターンファミリーから始めます。これは、ダブルトップパターンとダブルボトムパターンに由来するものです。
DoEasyライブラリのグラフィックス(第74部): CCanvasクラスを使用した基本的グラフィック要素 DoEasyライブラリのグラフィックス(第74部): CCanvasクラスを使用した基本的グラフィック要素
本稿では、前の記事からのグラフィカルオブジェクトを構築するという概念を作り直し、標準ライブラリCCanvasクラスを利用したライブラリのすべてのグラフィカルオブジェクトの基本クラスを準備します。
DoEasyライブラリでのその他のクラス(第72部): コレクション内のチャートオブジェクトパラメータの追跡と記録 DoEasyライブラリでのその他のクラス(第72部): コレクション内のチャートオブジェクトパラメータの追跡と記録
本稿では、チャートオブジェクトクラスとそのコレクションの操作を完成します。また、チャートプロパティとそのウィンドウの変更の自動追跡を実装し、オブジェクトプロパティに新しいパラメータを保存します。このような変更により、を将来チャートコレクション全体のイベント機能実装できるようになります。