【MQL5】OnChartEvent関数について

MQL5リファレンス
スポンサーリンク

OnChartEvent関数の働き・役割

OnChartEvent関数は、チャート上で発生するさまざまなイベントを処理するための関数です。この関数は、ユーザーの操作やプログラムによって生成されたイベントに応答します。
具体的には、マウスクリックやキーボード入力、オブジェクトの作成や削除などのイベントをキャッチして処理します。

OnChartEvent関数の引数について

OnChartEvent関数引数構成は以下の通りです。

void OnChartEvent(
   const int id,         // イベントID
   const long &lparam,   // long型イベントパラメータ
   const double &dparam, // double型イベントパラメータ
   const string &sparam  // string型イベントパラメータ
);

各引数の説明

id
イベントの識別子です。ENUM_CHART_EVENT列挙型の値の一つで、イベントの種類を示します。

lparam
イベントの詳細情報を含むlong型のパラメータです。イベントの種類によって異なる情報を保持します。

dparam
イベントの詳細情報を含むdouble型のパラメータです。lparam同様、イベントの種類によって異なる情報を保持します。

sparam
イベントの詳細情報を含むstring型のパラメータです。イベントの種類によって異なる情報を保持します。

OnChartEvent関数のパラメータ(id, lparam, dparam, sparam)は、特定のイベントの詳細を伝えるために使用されます。各イベントによって、これらのパラメータが異なる意味を持つことがあります。以下に主要なチャートイベントとそれぞれのパラメータの意味について説明します。

CHARTEVENT_KEYDOWN

id: CHARTEVENT_KEYDOWN
lparam: 押されたキーのコード
dparam: 繰り返し回数(キーの長押しによる繰り返し回数)
sparam: キーボードボタンの状態を記述するビットマスク文字列

CHARTEVENT_CLICK

id: CHARTEVENT_CLICK
lparam: マウスクリックのX座標
dparam: マウスクリックのY座標
sparam: 空(使用されない)

CHARTEVENT_OBJECT_CLICK

id: CHARTEVENT_OBJECT_CLICK
lparam: クリックされたオブジェクトの名前
dparam: マウスクリックのY座標
sparam: オブジェクト名

CHARTEVENT_MOUSE_MOVE

id: CHARTEVENT_MOUSE_MOVE
lparam: マウスのX座標
dparam: マウスのY座標
sparam: 空(使用されない)

CHARTEVENT_OBJECT_DRAG

id: CHARTEVENT_OBJECT_DRAG
lparam: ドラッグされたオブジェクトの名前
dparam: ドラッグの終了時のY座標
sparam: オブジェクト名

CHARTEVENT_OBJECT_CREATE

id: CHARTEVENT_OBJECT_CREATE
lparam: 作成されたオブジェクトの名前
dparam: オブジェクトのタイプ
sparam: オブジェクト名

CHARTEVENT_OBJECT_DELETE

id: CHARTEVENT_OBJECT_DELETE
lparam: 削除されたオブジェクトの名前
dparam: オブジェクトのタイプ
sparam: オブジェクト名

各イベントによって、これらのパラメータが異なる意味を持つため、特定のイベントを処理する際には、対応するパラメータの意味を理解することが重要です。

詳細は↓ENUM_CHART_EVENT列挙体の記事をご参照ください。

OnChartEvent関数の戻り値について

OnChartEvent関数void型であり、戻り値はありません。この関数はイベントが発生したときに自動的に呼び出され、必要な処理を行います。

OnChartEvent関数を使う際の注意点

  • OnChartEvent関数は、チャートに直接表示されるインジケータエキスパートアドバイザーEA)に対してのみ呼び出されます。プログラムで作成されたインジケータiCustom関数IndicatorCreate関数を使用)にはイベントが伝達されません。
  • ストラテジーテスターではOnChartEvent関数は呼び出されません。これは、テスト中のイベント処理が制限されているためです。
  • 同期的にイベントが処理されるため、大量のイベントが短時間で発生すると、処理が遅延する可能性があります。
  • MQL5OnChartEvent関数を使用して処理できるイベントには、事前定義された11種類のイベントがあります。
    これらのイベントは、チャート上で発生するさまざまなアクションに対応しています。例えば、キーボード入力やマウスクリック、グラフィカルオブジェクトの作成や削除などです。
    これらの事前定義されたイベントに加えて、MQL5ではカスタムイベントを作成して処理することもできます。カスタムイベントの識別子(ID)はCHARTEVENT_CUSTOMからCHARTEVENT_CUSTOM_LASTまでの範囲(65535種類)で提供されています。これにより、ユーザーは独自のイベントを定義して発生させ、OnChartEvent関数内でそれを処理することができます。
    カスタムイベントを作成するには、EventChartCustom関数を使用します。この関数を呼び出すことで、指定したカスタムイベントをチャートに対して発生させることができます。発生させたカスタムイベントは、OnChartEvent関数で捕捉され、処理されます。
    ※詳細は下記のEventChartCustom関数の記事をご覧ください。
  • MQL5プログラムは、メインのアプリケーションスレッド(メインアプリケーションの実行を管理する単位)とは別の独立スレッド(並行して処理を行うための実行単位)で実行されます。
    メインのアプリケーションスレッドは、Windowsシステムから送られてくるすべてのメッセージを処理します。この処理の結果として、メインスレッドは独自のアプリケーション用メッセージを生成します。
    例えば、ユーザーがチャート上でマウスを動かすと、WM_MOUSE_MOVEというシステムイベントが発生します。
    メインスレッドはこのイベントを受け取り、その結果としてエキスパートアドバイザーEA)やインジケータに対して内部的なメッセージ(=WM_MOUSE_MOVE)を送信します。これにより、EAやインジケータはユーザーのマウス操作に応じた処理を行います。
    この時、メインアプリケーションスレッドがWM_PAINTシステムメッセージをまだ処理していない場合があります。
    WM_PAINTとは、Windowsシステムにおける描画要求を示すシステムメッセージです。このメッセージは、ウィンドウの一部または全体が再描画(レンダリング)される必要があるときに送信されます。例えば、ウィンドウが最小化から復元されたときや、ウィンドウの内容が変更されたときに発生します。
    具体的には、ユーザーがマウスを動かしてチャートに変化が生じた場合、EAやインジケータはその変化に応じた処理を行いますが、メインスレッドがWM_PAINTメッセージを処理してチャートを再描画する前にその処理を終えてしまう可能性があります。つまり、EAやインジケータはマウス移動イベントに基づく処理を行っているが、メインスレッドがまだその結果を画面に描画していない状況です。このため、チャートのプロパティ(例えば、CHART_FIRST_VISIBLE_BAR)は、実際にチャートが再描画された後でのみ変更されます。

OnChartEvent関数を使ったサンプルコード

以下は、OnChartEvent関数を使用してチャート上でのマウスクリックイベントやキーストロークイベントを処理するサンプルコードです

// OnChartEvent関数は、チャート上で発生するイベントを処理します
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
    // キーボードのキーが押されたイベント
    if(id == CHARTEVENT_KEYDOWN)
    {
        PrintFormat("キーが押されました: %d", lparam);
    }
    // チャート上でマウスがクリックされたイベント
    else if(id == CHARTEVENT_CLICK)
    {
        PrintFormat("チャート上でマウスがクリックされました: x = %d, y = %f", lparam, dparam);
    }
    // グラフィックオブジェクトがクリックされたイベント
    else if(id == CHARTEVENT_OBJECT_CLICK)
    {
        PrintFormat("グラフィックオブジェクト '%s' がクリックされました", sparam);
    }
}

サンプルコードに使われた関数や文法要素の簡単な解説

OnChartEvent関数

OnChartEvent関数は、チャート上で発生するイベントをキャッチして処理するための関数です。引数としてイベントの種類(id)、およびイベントに関連する詳細情報(lparam, dparam, sparam)を受け取ります。

PrintFormat関数

PrintFormat関数は、指定されたフォーマットに従って文字列を作成し、エキスパートログに出力する関数です。引数としてフォーマット文字列と可変数の引数を指定します。

このサンプルコードでは、チャート上でのマウスクリックやキーボード入力、グラフィックオブジェクトのクリックイベントをキャッチし、その情報をエキスパートログに出力します。

公式リファレンスのサンプルコードについて

公式リファレンスのOnChartEvent関数についてのサンプルコードは以下の通りです。

//+------------------------------------------------------------------+
//|                                          OnChartEvent_Sample.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link     "https://www.mql5.com"
#property version   "1.00"
#property description "Sample chart event listener and custom events generator"
//--- サービスキーID
#define KEY_NUMPAD_5       12
#define KEY_LEFT           37
#define KEY_UP             38
#define KEY_RIGHT          39
#define KEY_DOWN           40
#define KEY_NUMLOCK_DOWN   98
#define KEY_NUMLOCK_LEFT  100
#define KEY_NUMLOCK_5     101
#define KEY_NUMLOCK_RIGHT 102
#define KEY_NUMLOCK_UP    104
//+------------------------------------------------------------------+
//| エキスパート初期化関数                                                 |
//+------------------------------------------------------------------+
int OnInit()
 {
//--- CHARTEVENT_CUSTOM定数値を表示する
  Print("CHARTEVENT_CUSTOM=",CHARTEVENT_CUSTOM);
//---
  Print("Launched the EA ",MQLInfoString(MQL_PROGRAM_NAME));
//--- チャートオブジェクト作成イベントの受信フラグを設定する
  ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_CREATE,true);
//--- チャートオブジェクト削除イベントの受信フラグを設定する
  ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_DELETE,true);
//--- マウスホイールスクロールメッセージの有効化
  ChartSetInteger(0,CHART_EVENT_MOUSE_WHEEL,1);
//--- チャートプロパティの強制更新により、イベント処理の準備が整う
  ChartRedraw();
//---
  return(INIT_SUCCEEDED);
 }
//+------------------------------------------------------------------+
//| エキスパートティック関数                                                 |
//+------------------------------------------------------------------+
void OnTick()
 {
//--- カスタムイベント生成のためのティックカウンタ
  static int tick_counter=0;
//--- 累積されたティックをこの値で除算する
  int simple_number=113;
//---
  tick_counter++;
//--- ティックカウンタがsimple_numberの倍数である場合、カスタムイベントを送信する
  if(tick_counter%simple_number==0)
    {
    //--- カスタムイベントIDを0〜65535で形成する
    ushort custom_event_id=ushort(tick_counter%65535);
    //---  カスタムイベントを送信し、パラメータを記入する
    EventChartCustom(ChartID(),custom_event_id,tick_counter,SymbolInfoDouble(Symbol(),SYMBOL_BID),__FUNCTION__);
    //--- 結果例を分析するためにログに追加する
    Print(__FUNCTION__,": Sent a custom event ID=",custom_event_id);
    }
//---    
 }
//+------------------------------------------------------------------+
//| ChartEvent 関数                                                   |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                const long &lparam,
                const double &dparam,
                const string &sparam)
 {
//--- キーの押下
  if(id==CHARTEVENT_KEYDOWN)
    {
    switch((int)lparam)
       {
        case KEY_NUMLOCK_LEFT: Print("Pressed KEY_NUMLOCK_LEFT");   break;
        case KEY_LEFT:         Print("Pressed KEY_LEFT");           break;
        case KEY_NUMLOCK_UP:   Print("Pressed KEY_NUMLOCK_UP");     break;
        case KEY_UP:           Print("Pressed KEY_UP");             break;
        case KEY_NUMLOCK_RIGHT: Print("Pressed KEY_NUMLOCK_RIGHT"); break;
        case KEY_RIGHT:         Print("Pressed KEY_RIGHT");         break;
        case KEY_NUMLOCK_DOWN: Print("Pressed KEY_NUMLOCK_DOWN");   break;
        case KEY_DOWN:         Print("Pressed KEY_DOWN");           break;
        case KEY_NUMPAD_5:     Print("Pressed KEY_NUMPAD_5");       break;
        case KEY_NUMLOCK_5:     Print("Pressed KEY_NUMLOCK_5");     break;
        default:               Print("Pressed unlisted key");
       }
    }
//--- チャートの左クリック
  if(id==CHARTEVENT_CLICK)
    Print("Mouse click coordinates on a chart: x = ",lparam,"  y = ",dparam);
//--- グラフィックオブジェクトのクリック
  if(id==CHARTEVENT_OBJECT_CLICK)
    Print("Clicking a mouse button on an object named '"+sparam+"'");
//--- オブジェクト削除
  if(id==CHARTEVENT_OBJECT_DELETE)
    Print("Removed object named ",sparam);
//--- オブジェクト作成
  if(id==CHARTEVENT_OBJECT_CREATE)
    Print("Created object named ",sparam);
//--- オブジェクト変更
  if(id==CHARTEVENT_OBJECT_CHANGE)
    Print("Changed object named ",sparam);
//--- オブジェクト移動またはアンカーポイント座標変更
  if(id==CHARTEVENT_OBJECT_DRAG)
    Print("Changing anchor points of object named ",sparam);
//--- Editグラフィックオブジェクトのテキスト編集
  if(id==CHARTEVENT_OBJECT_ENDEDIT)
    Print("Changed text in Edit object ",sparam,"  id=",id);
//--- マウス移動イベント
  if(id==CHARTEVENT_MOUSE_MOVE)
    Comment("POINT: ",(int)lparam,",",(int)dparam,"\n",MouseState((uint)sparam));
  if(id==CHARTEVENT_MOUSE_WHEEL)
    {
    //--- このイベントのマウスボタンとホイールの状態を考察する
    int flg_keys = (int)(lparam>>32);         // Ctrlキー、Shiftキー、マウスボタンの状態のフラグ
    int x_cursor = (int)(short)lparam;         // マウスホイールイベントが発生したX座標
    int y_cursor = (int)(short)(lparam>>16);   // マウスホイールイベントが発生したY座標
    int delta    = (int)dparam;               // マウススクロールの合計値(+120または -120 が越されるとトリガされる)
    //--- フラグの処理
    string str_keys="";
    if((flg_keys&0x0001)!=0)
        str_keys+="LMOUSE ";
    if((flg_keys&0x0002)!=0)
        str_keys+="RMOUSE ";
    if((flg_keys&0x0004)!=0)
        str_keys+="SHIFT ";
    if((flg_keys&0x0008)!=0)
        str_keys+="CTRL ";
    if((flg_keys&0x0010)!=0)
        str_keys+="MMOUSE ";
    if((flg_keys&0x0020)!=0)
        str_keys+="X1MOUSE ";
    if((flg_keys&0x0040)!=0)
        str_keys+="X2MOUSE ";
 
    if(str_keys!="")
        str_keys=", keys='"+StringSubstr(str_keys,0,StringLen(str_keys)-1)+"'";
    PrintFormat("%s: X=%d, Y=%d, delta=%d%s",EnumToString(CHARTEVENT_MOUSE_WHEEL),x_cursor,y_cursor,delta,str_keys);
    }
//--- プロパティダイアログウィンドウでのチャートのサイズおよびプロパティ変更イベント
  if(id==CHARTEVENT_CHART_CHANGE)
    Print("Changing the chart size or properties");
//--- カスタムイベント
  if(id>CHARTEVENT_CUSTOM)
    PrintFormat("Custom event ID=%d, lparam=%d, dparam=%G, sparam=%s",id,lparam,dparam,sparam);
 }
//+------------------------------------------------------------------+
//| マウスの状態                                                        |
//+------------------------------------------------------------------+
string MouseState(uint state)
 {
  string res;
  res+="\nML: "   +(((state& 1)== 1)?"DN":"UP");   // 左ボタン
  res+="\nMR: "   +(((state& 2)== 2)?"DN":"UP");   // 右ボタン
  res+="\nMM: "   +(((state&16)==16)?"DN":"UP");   // 中央ボタン
  res+="\nMX: "   +(((state&32)==32)?"DN":"UP");   // 追加ボタン1
  res+="\nMY: "   +(((state&64)==64)?"DN":"UP");   // 追加ボタン 2
  res+="\nSHIFT: "+(((state& 4)== 4)?"DN":"UP");   // シフト キー
  res+="\nCTRL: " +(((state& 8)== 8)?"DN":"UP");   // control キー
  return(res);
 }

複雑なので、小分けにして解説していきたいと思います。

定数定義部分

//--- サービスキーIDの定義
#define KEY_NUMPAD_5       12   // キーボードのテンキー5キー
#define KEY_LEFT           37   // キーボードの左矢印キー
#define KEY_UP             38   // キーボードの上矢印キー
#define KEY_RIGHT          39   // キーボードの右矢印キー
#define KEY_DOWN           40   // キーボードの下矢印キー
#define KEY_NUMLOCK_DOWN   98   // キーボードのNumLockと下矢印キー
#define KEY_NUMLOCK_LEFT  100   // キーボードのNumLockと左矢印キー
#define KEY_NUMLOCK_5     101   // キーボードのNumLockとテンキー5キー
#define KEY_NUMLOCK_RIGHT 102   // キーボードのNumLockと右矢印キー
#define KEY_NUMLOCK_UP    104   // キーボードのNumLockと上矢印キー

この部分のコードは、特定のキー入力を識別するための定数を定義しています。各キーに対して一意の数値を割り当てることで、後のコードでこれらのキー入力を簡単に検出し、処理できるようにしています。

defineは、定数を定義するために使用されます。KEY_NUMPAD_5などの定数名は、対応するキー入力を意味します。12, 37, 38などの数値は、各キーの仮想キーコードです。仮想キーコードは、キー入力をプログラムが識別するための標準化された数値です。

これにより、プログラム中でキー入力を扱う際に、わかりやすい名前でキーを参照することができます。例えば、KEY_LEFTとして左矢印キーを検出することで、コードの可読性が向上します。

OnInit関数部分

//+------------------------------------------------------------------+
//| エキスパート初期化関数                                                 |
//+------------------------------------------------------------------+
int OnInit()
 {
    //--- CHARTEVENT_CUSTOM定数値を表示する
    Print("CHARTEVENT_CUSTOM=",CHARTEVENT_CUSTOM);

    //--- エキスパートアドバイザーの起動メッセージを表示する
    Print("Launched the EA ", MQLInfoString(MQL_PROGRAM_NAME));

    //--- チャートオブジェクト作成イベントの受信フラグを設定する
    ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_CREATE, true);

    //--- チャートオブジェクト削除イベントの受信フラグを設定する
    ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_DELETE, true);

    //--- マウスホイールスクロールメッセージの有効化
    ChartSetInteger(0, CHART_EVENT_MOUSE_WHEEL, 1);

    //--- チャートプロパティの強制更新により、イベント処理の準備が整う
    ChartRedraw();

    //--- 初期化成功のステータスを返す
    return(INIT_SUCCEEDED);
 }

OnInit関数は、EAがチャートに挿入されたときに最初に実行される関数です。この関数内で、EAの初期設定や必要な準備を行います。

最初に、CHARTEVENT_CUSTOM定数値を表示しています。これはカスタムイベントの識別子であり、デバッグやログ出力のために使用されます。

次に、EAが起動したことを示すメッセージを表示しています。MQLInfoString関数を使って、EAの名前を取得して表示します。
※なお、公式リファレンスのサンプルコードではMQLInfoString関数引数に「MQL5_PROGRAM_NAME」という定数が記述されていますが、このままコンパイルするとエラーになります。正しくは「MQL_PROGRAM_NAME」です。

次に、ChartSetInteger関数を使用して、チャートオブジェクトの作成イベントと削除イベントの受信フラグを設定しています(第1引数に記述されているChartID関数はチャートIDを取得する関数です)。これにより、チャート上でオブジェクトが作成されたり削除されたりしたときに、OnChartEvent関数が呼び出されるようになります。

次に、マウスホイールスクロールメッセージを有効化しています。これにより、チャート上でマウスホイールを使ったスクロール操作が行われたときに、OnChartEvent関数が呼び出されます。

最後に、ChartRedraw関数を呼び出してチャートプロパティを強制的に更新し、イベント処理の準備を整えています。

OnInit関数の最後では、初期化成功のステータスを返すためにINIT_SUCCEEDEDを返しています。これにより、EAの初期化が正常に完了したことを示します。

OnTick関数部分

void OnTick()
{
    //--- カスタムイベント生成のためのティックカウンタ
    static int tick_counter = 0;

    //--- 累積されたティックをこの値で除算する
    int simple_number = 113;

    //--- ティックカウンタを増加
    tick_counter++;

    //--- ティックカウンタがsimple_numberの倍数である場合、カスタムイベントを送信する
    if(tick_counter % simple_number == 0)
    {
        //--- カスタムイベントIDを0〜65535で形成する
        ushort custom_event_id = ushort(tick_counter % 65535);

        //--- カスタムイベントを送信し、パラメータを記入する
        EventChartCustom(ChartID(), custom_event_id, tick_counter, SymbolInfoDouble(Symbol(), SYMBOL_BID), __FUNCTION__);

        //--- 結果例を分析するためにログに追加する
        Print(__FUNCTION__, ": Sent a custom event ID=", custom_event_id);
    }
}

OnTick関数は、新しいティック(価格の変動)が発生するたびに自動的に呼び出される関数です。この関数内で、ティックごとに実行したい処理を記述します。

最初に、ティックカウンタを保持するためのstatic変数tick_counterを定義します。static変数は、関数が呼び出されるたびに値を保持し続けます。

次に、累積されたティックを割るための値としてsimple_numberを定義します。この値は、カウンタが一定のティック数(=113)に達したときにカスタムイベントを生成するために使用されます。

ティックカウンタをインクリメント(増加)します。これにより、ティックが発生するたびにカウンタが1ずつ増加します。

次に、ティックカウンタがsimple_numberの倍数である場合にカスタムイベントを送信します。具体的には、ティックカウンタがsimple_numberで割り切れる場合にカスタムイベントを生成します。

カスタムイベントIDを0から65535の範囲で生成します。ushort型タイプキャストすることで、カウンタの値をカスタムイベントIDに変換します。

EventChartCustom関数を使用して、カスタムイベントを送信します。EventChartCustom関数には、チャートID、カスタムイベントID、カスタムイベントに関するパラメータ(tick_counter, 現在のシンボルのBID価格, 関数名)を渡します。

最後に、カスタムイベントが送信されたことをログに出力します。Print関数を使用して、イベントが送信されたこととそのIDを表示します。

このようにして、OnTick関数ではティックごとにカウンタを増加させ、一定のティック数に達したときにカスタムイベントを生成して送信します。これにより、EAが特定の条件でカスタムイベントをトリガーできるようになります。

OnChartEvent関数部分その1

//+------------------------------------------------------------------+
//| ChartEvent 関数                                                   |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                const long &lparam,
                const double &dparam,
                const string &sparam)

OnChartEvent関数は、チャート上で発生するさまざまなイベントを処理するための関数です。この関数は、ユーザーの操作やプログラムによって生成されたイベントに応答します。引数として、イベントの種類(id)、およびイベントに関連する詳細情報(lparam, dparam, sparam)を受け取ります。

OnChartEvent関数部分その2

{
    //--- キーの押下
    if(id == CHARTEVENT_KEYDOWN)
    {
        switch((int)lparam)
        {
            case KEY_NUMLOCK_LEFT:  Print("Pressed KEY_NUMLOCK_LEFT");   break;
            case KEY_LEFT:          Print("Pressed KEY_LEFT");           break;
            case KEY_NUMLOCK_UP:    Print("Pressed KEY_NUMLOCK_UP");     break;
            case KEY_UP:            Print("Pressed KEY_UP");             break;
            case KEY_NUMLOCK_RIGHT: Print("Pressed KEY_NUMLOCK_RIGHT");  break;
            case KEY_RIGHT:         Print("Pressed KEY_RIGHT");          break;
            case KEY_NUMLOCK_DOWN:  Print("Pressed KEY_NUMLOCK_DOWN");   break;
            case KEY_DOWN:          Print("Pressed KEY_DOWN");           break;
            case KEY_NUMPAD_5:      Print("Pressed KEY_NUMPAD_5");       break;
            case KEY_NUMLOCK_5:     Print("Pressed KEY_NUMLOCK_5");      break;
            default:                Print("Pressed unlisted key");
        }
    }
}

OnChartEvent関数のこの部分では、ユーザーがキーボードのキーを押したときに発生するCHARTEVENT_KEYDOWNイベントを処理しています。分岐処理はswitch文で行っています。

最初に、イベントIDがCHARTEVENT_KEYDOWNであることを確認します。このIDは、キーボードのキーが押されたことを示します。

次に、lparamパラメータを使って押されたキーのコードを取得し、それに応じたメッセージをPrint関数でエキスパートログに出力します。switch文を使用して、特定のキーコードに対して異なるメッセージを出力します。

各ケースでは、あらかじめ定義されたキーコード(KEY_NUMLOCK_LEFT、KEY_LEFT、KEY_NUMLOCK_UPなど)に対応するメッセージを表示します。例えば、ユーザーがNumLockと左矢印キーを押した場合、「Pressed KEY_NUMLOCK_LEFT」というメッセージがログに出力されます。

defaultケースでは、リストにないキーが押された場合に「Pressed unlisted key」というメッセージを表示します。

このようにして、OnChartEvent関数はキーボードのキー入力をキャッチし、それに応じた処理を行います。次のセクションでは、他のイベントの処理について説明します。

OnChartEvent関数部分その3

//--- チャートの左クリック
if(id == CHARTEVENT_CLICK)
    Print("Mouse click coordinates on a chart: x = ", lparam, "  y = ", dparam);

//--- グラフィックオブジェクトのクリック
if(id == CHARTEVENT_OBJECT_CLICK)
    Print("Clicking a mouse button on an object named '", sparam, "'");

//--- オブジェクト削除
if(id == CHARTEVENT_OBJECT_DELETE)
    Print("Removed object named ", sparam);

//--- オブジェクト作成
if(id == CHARTEVENT_OBJECT_CREATE)
    Print("Created object named ", sparam);

//--- オブジェクト変更
if(id == CHARTEVENT_OBJECT_CHANGE)
    Print("Changed object named ", sparam);

//--- オブジェクト移動またはアンカーポイント座標変更
if(id == CHARTEVENT_OBJECT_DRAG)
    Print("Changing anchor points of object named ", sparam);

//--- Editグラフィックオブジェクトのテキスト編集
if(id == CHARTEVENT_OBJECT_ENDEDIT)
    Print("Changed text in Edit object ", sparam, "  id=", id);

//--- マウス移動イベント
if(id == CHARTEVENT_MOUSE_MOVE)
    Comment("POINT: ", (int)lparam, ",", (int)dparam, "\n", MouseState((uint)sparam));

チャートの左クリック
最初に、イベントIDがCHARTEVENT_CLICKであることを確認します。これはチャート上でマウスの左クリックが発生したことを示します。lparamとdparamを使用して、クリック位置のX座標とY座標を取得し、Print関数でログに出力します。

グラフィックオブジェクトのクリック
次に、イベントIDがCHARTEVENT_OBJECT_CLICKであることを確認します。これはグラフィックオブジェクトがクリックされたことを示します。sparamにはクリックされたオブジェクトの名前が含まれており、これをログに出力します。

オブジェクト削除
イベントIDがCHARTEVENT_OBJECT_DELETEである場合、削除されたオブジェクトの名前をsparamから取得し、ログに出力します。

オブジェクト作成
イベントIDがCHARTEVENT_OBJECT_CREATEである場合、新しく作成されたオブジェクトの名前をsparamから取得し、ログに出力します。

オブジェクト変更
イベントIDがCHARTEVENT_OBJECT_CHANGEである場合、変更されたオブジェクトの名前をsparamから取得し、ログに出力します。

オブジェクト移動またはアンカーポイント座標変更
イベントIDがCHARTEVENT_OBJECT_DRAGである場合、移動されたオブジェクトの名前をsparamから取得し、ログに出力します。

Editグラフィックオブジェクトのテキスト編集
イベントIDがCHARTEVENT_OBJECT_ENDEDITである場合、編集が完了したEditオブジェクトの名前をsparamから取得し、idとともにログに出力します。

マウス移動イベント
イベントIDがCHARTEVENT_MOUSE_MOVEである場合、マウスの現在位置のX座標とY座標をlparamとdparamから取得し、Comment関数でチャート上に表示します。MouseState関数を使用して、マウスボタンや修飾キーの状態も表示します。
※MouseState関数はこの後定義されるオリジナルの関数です。

OnChartEvent関数部分その4

if(id == CHARTEVENT_MOUSE_WHEEL)
{
    //--- このイベントのマウスボタンとホイールの状態を考察する
    int flg_keys = (int)(lparam >> 32);        // Ctrlキー、Shiftキー、マウスボタンの状態のフラグ
    int x_cursor = (int)(short)lparam;         // マウスホイールイベントが発生したX座標
    int y_cursor = (int)(short)(lparam >> 16); // マウスホイールイベントが発生したY座標
    int delta    = (int)dparam;                // マウススクロールの合計値(+120または-120が越されるとトリガーされる)
    
    //--- フラグの処理
    string str_keys = ""; // マウスボタンおよび修飾キーの状態を示す文字列を初期化
    if((flg_keys & 0x0001) != 0)
        str_keys += "LMOUSE "; // 左マウスボタンが押されている場合に文字列を追加
    if((flg_keys & 0x0002) != 0)
        str_keys += "RMOUSE "; // 右マウスボタンが押されている場合に文字列を追加
    if((flg_keys & 0x0004) != 0)
        str_keys += "SHIFT ";  // Shiftキーが押されている場合に文字列を追加
    if((flg_keys & 0x0008) != 0)
        str_keys += "CTRL ";   // Ctrlキーが押されている場合に文字列を追加
    if((flg_keys & 0x0010) != 0)
        str_keys += "MMOUSE "; // 中央マウスボタンが押されている場合に文字列を追加
    if((flg_keys & 0x0020) != 0)
        str_keys += "X1MOUSE "; // 第1追加マウスボタンが押されている場合に文字列を追加
    if((flg_keys & 0x0040) != 0)
        str_keys += "X2MOUSE "; // 第2追加マウスボタンが押されている場合に文字列を追加
    
    if(str_keys != "")
        str_keys = ", keys='" + StringSubstr(str_keys, 0, StringLen(str_keys) - 1) + "'"; // 末尾のスペースを削除して文字列を整形
    
    //--- マウスホイールイベントの詳細をログに出力
    PrintFormat("%s: X=%d, Y=%d, delta=%d%s", EnumToString(CHARTEVENT_MOUSE_WHEEL), x_cursor, y_cursor, delta, str_keys);
}

この部分では、イベントIDがCHARTEVENT_MOUSE_WHEELである場合の処理を行います。これは、チャート上でマウスホイールが回転したときに発生するイベントを示します。

最初に、lparamパラメータからマウスボタンとホイールの状態を取得します。これは、Ctrlキー、Shiftキー、マウスボタンの状態を示すフラグです。
※「>>」はビットシフト演算子の一つで、右シフトを行います。詳細は最後に「補足説明ビットシフト演算子「>>」について」というセクションを設けていますので、そちらをご覧ください。

次に、マウスホイールイベントが発生したX座標とY座標をlparamから取得します。lparamの下位16ビットがX座標、次の16ビットがY座標を表します。

dparamからマウススクロールの合計値を取得します。この値は、+120または-120を超えるとトリガーされます。正の値はスクロールアップ、負の値はスクロールダウンを示します。

次に、マウスボタンと修飾キーの状態をフラグとして処理します。各ビットが特定のキーまたはボタンの状態を示します。例えば、flg_keysのビット0が1の場合、左マウスボタンが押されていることを示します。

各フラグを確認し、対応する文字列をstr_keysに追加します。最後に、str_keysが空でない場合、末尾のスペースを削除します。

PrintFormat関数を使用して、マウスホイールイベントの詳細(X座標、Y座標、スクロールの合計値、キーとボタンの状態)をログに出力します。

OnChartEvent関数部分その5

//--- プロパティダイアログウィンドウでのチャートのサイズおよびプロパティ変更イベント
if(id == CHARTEVENT_CHART_CHANGE)
    Print("Changing the chart size or properties");

//--- カスタムイベント
if(id > CHARTEVENT_CUSTOM)
    PrintFormat("Custom event ID=%d, lparam=%d, dparam=%G, sparam=%s", id, lparam, dparam, sparam);

プロパティダイアログウィンドウでのチャートのサイズおよびプロパティ変更イベント
最初に、イベントIDがCHARTEVENT_CHART_CHANGEであることを確認します。このIDは、チャートのサイズやプロパティが変更されたときに発生するイベントを示します。この場合、”Changing the chart size or properties”というメッセージをPrint関数でログに出力します。

カスタムイベント
次に、イベントIDがCHARTEVENT_CUSTOMり大きい場合の処理を行います。CHARTEVENT_CUSTOMはカスタムイベントの識別子の最小値であり、それより大きいIDはすべてカスタムイベントを示します。この場合、PrintFormat関数を使用して、カスタムイベントの詳細(イベントID、lparam、dparam、sparam)をログに出力します。

MouseState関数の定義部分

//+------------------------------------------------------------------+
//| マウスの状態                                                        |
//+------------------------------------------------------------------+
string MouseState(uint state)
{
  string res;
  res += "\nML: "   + (((state & 1) == 1) ? "DN" : "UP");   // 左ボタン
  res += "\nMR: "   + (((state & 2) == 2) ? "DN" : "UP");   // 右ボタン
  res += "\nMM: "   + (((state & 16) == 16) ? "DN" : "UP"); // 中央ボタン
  res += "\nMX: "   + (((state & 32) == 32) ? "DN" : "UP"); // 追加ボタン1
  res += "\nMY: "   + (((state & 64) == 64) ? "DN" : "UP"); // 追加ボタン2
  res += "\nSHIFT: " + (((state & 4) == 4) ? "DN" : "UP");  // シフトキー
  res += "\nCTRL: "  + (((state & 8) == 8) ? "DN" : "UP");  // コントロールキー
  return(res);
}

MouseState関数は、マウスの状態を表すビットフラグを解析し、その状態を文字列として返す関数です。この関数は、各マウスボタンや修飾キーの状態を判定し、その結果を”DN”(押下)または”UP”(離上)として文字列に追加します。

関数引数としてuint stateを受け取り、この引数は各ビットが特定のマウスボタンやキーの状態を表します。

  • 左ボタン(ML): state & 1のビットが1の場合は”DN”、それ以外の場合は”UP”
  • 右ボタン(MR): state & 2のビットが2の場合は”DN”、それ以外の場合は”UP”
  • 中央ボタン(MM): state & 16のビットが16の場合は”DN”、それ以外の場合は”UP”
  • 追加ボタン1(MX): state & 32のビットが32の場合は”DN”、それ以外の場合は”UP”
  • 追加ボタン2(MY): state & 64のビットが64の場合は”DN”、それ以外の場合は”UP”
  • シフトキー(SHIFT): state & 4のビットが4の場合は”DN”、それ以外の場合は”UP”
  • コントロールキー(CTRL): state & 8のビットが8の場合は”DN”、それ以外の場合は”UP”

これらの状態を解析して、対応する文字列resに追加し、最終的にその文字列を返します。これにより、マウスとキーボードの状態を視覚的に確認することができます。

補足説明ビットシフト演算子「>>」について

「>>」はビットシフト演算子の一つで、右シフトを行います。右シフト演算子は、指定されたビット数だけビット列を右にシフトさせる操作を行います。右シフトの効果としては、シフトされたビットはビット列の右端から削除され、左端には0が挿入されます。

例えば、「lparam >> 32」という記述は、lparamのビット列を32ビット右にシフトすることを意味します。具体的には、lparamの下位32ビットが削除され、上位32ビットが新しい値として取得されます。

右シフト演算子はビットマスクやビット操作を行う際に非常に便利です。たとえば、特定のビット範囲を抽出したり、フラグの状態を確認したりする場合に使用されます。

具体例

  • lparamの値が0x123456789ABCDEF0である場合、これを32ビット右にシフトすると、結果は0x12345678になります。
  • シフト前のビット列: 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 0000
  • 32ビット右シフト後: 0000 0000 0000 0000 0000 0000 0000 0000 0001 0010 0011 0100 0101 0110 0111 1000

この演算子を使うと、特定のビット範囲を簡単に抽出したり、操作したりすることができます。

コメント

タイトルとURLをコピーしました