
DoEasyライブラリのグラフィックス(第73部): グラフィック要素のフォームオブジェクト
内容
概念
最新のプログラム、特に分析プログラムは、計算に大量のデータを使用することができます。しかし、視覚化なしで何かを理解することは難しいでしょう。また、明確で便利なインターフェイスなしでプログラムを最大限に使用することは非常に難しいでしょう。当然のことながら、グラフィックを操作する機能は、私たちのライブラリにとっても必須です。したがって、この記事では、グラフィック要素の操作に関する大きなセクションを開始します。
私の目的は、さまざまなグラフィカルオブジェクトを作成するための便利な機能を作成し、すべてのメインライブラリクラスがカスタムグラフィカルオブジェクトを使用してグラフィックをインタラクティブに操作できるようにし、複雑なコンポーネント階層を特徴とするグラフィカルオブジェクトを作成することです。
CCanvas標準ライブラリクラスに基づくグラフィッカルオブジェクトから始めます。このクラスを使用すると、カスタム画像を簡単に作成し、それらを基礎として使用して、より複雑なオブジェクトを作成できます。既製の画像を使用することも、作成したキャンバスにカスタム画像を描画することもできます。個人的には、後者のオプションの方がエキサイティングだと思うので、グラフィカルオブジェクトの設計に広く使用することにします。
単一のオブジェクトの階層は常に次のようになります。
- CObjectクラスに基づくすべてのライブラリグラフィック要素の基本オブジェクト。CCanvasクラスオブジェクトはその中で宣言されています。さらに、幅、高さ、チャートの座標、オブジェクトの右と下の境界線など、グラフィック要素に共通するすべてのパラメータが含まれています。
- グラフィック要素のオブジェクト形式 - グラフィカルオブジェクトの基礎(キャンバス)を表します。複合オブジェクトの他のすべての要素を含めます。そのパラメータを使用すると、グラフィカルオブジェクト全体のパラメータを設定できます。マウスステータス(カーソル座標と押されたボタン)を操作するメソッドを提供するクラスのオブジェクトもここで宣言されます。
階層は、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ファイルと一緒に以下に添付されています。
質問や提案はコメント欄にお願いします。
*これまでの連載の最終記事:
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/9442





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索