記事「指標やEAのデータを表示するダッシュボードの作成」についてのディスカッション

 

新しい記事「指標やEAのデータを表示するダッシュボードの作成」はパブリッシュされました:

この記事では、指標とEAで使用するダッシュボードクラスを作成します。これは、エキスパートアドバイザー(EA)に標準指標を含めて使用するためのテンプレートを含む短い連載の紹介記事です。まず、MetaTrader 5データウィンドウに似たパネルを作成します。

今回は開発者が指定したデータを表示できるダッシュボードを作成してみます。デバッガーで値を追跡するよりもパネル上で必要な値を確認する方が便利であるため、このようなパネルは、チャート上にデータを視覚的に表示したり、視覚的にデバッグしたりするのに便利です。いくつかのデータ値に応じて戦略がデバッグされている場合のことです。

ターミナルデータウィンドウのプロトタイプの形式でパネルを作成し、同じデータを入力します。


図1:データウィンドウとダッシュボード

カスタムパネルを使用すると、必要な量の必要なデータをパネルに追加したり、署名したり、プログラムコードの読み取り値を表示および更新したりすることができます。

マウスを使用してチャート上でパネルを移動したり、希望のチャート位置にドッキングしたり、折りたたんだり展開したりできる必要があります。パネル上にデータを配置する際に便利なように、指定した行数と列数で表を表示できるようになります。このテーブルのデータはジャーナル(各テーブルセルのX座標とY座標)に表示され、このデータが配置される行と列のインデックスを示すためにプログラムで取得できます。または、テキストやデータを表示するときに、単純に座標を出力し、必要な座標をコードに入力できます。最初の方法は完全に自動化されているため、より便利です。パネルにはアクティブな[閉じる]ボタンもありますが、その処理は制御プログラムに委任します。閉じるボタンの押下にどのように反応するかを決定するのはプログラム開発者のみです。ボタンをクリックすると、カスタムイベントがプログラムイベントハンドラに送信されます。開発者は独自の判断で処理できます。

作者: Artyom Trishkin

 

シェアしてくれてありがとう。

このクラスを継承する必要がある場合、この実装には大きな欠点がある。

1.デフォルトのコンストラクタがなく、パラメトリックなものは重要なパラメータをサイズごとに設定する。例えば、クラスの子孫のパラメータに基づいてパネルのサイズを計算する必要がある場合、このロジックはクラスの外部で実装するか、クラスの内部で実装するが、計算を別の関数で行う必要があります。おそらく、より良い解決策は、コンストラクタからクラス関数に初期化を移すことでしょう。

2.パラメーターを持つセクションはprivateとして宣言されているため、子孫クラスが例えば異なる配色を実装したり、ヘッダーのサイズを変更したりすることができません。

3.作業が終わっていないことは理解していますが、SetButtonClose(On/Off)、SetButtonMinimize(On/Off)など、実装されていない関数があります。

ソースコードがあるので、最終的には問題ないのですが、それでも...。

 
Evgeny #:

シェアしてくれてありがとう。

このクラスを継承する必要がある場合、この実装には大きな欠点がある。

1.デフォルトのコンストラクタがなく、パラメトリックなものは重要なパラメータをサイズごとに設定します。例えば、クラスの子孫のパラメータに基づいてパネルのサイズを計算する必要がある場合、このロジックはクラスの外部で実装するか、クラスの内部で実装する必要がありますが、計算は別の関数で行う必要があります。おそらく、より良い解決策は、コンストラクタからクラス関数に初期化を移すことでしょう。

2.パラメーターを持つセクションはprivateとして宣言されているため、子孫クラスが例えば異なる配色を実装したり、ヘッダーのサイズを変更したりすることができません。

3.作業がまだ終わっていないことは承知していますが、SetButtonClose(On/Off)、SetButtonMinimize(On/Off)など、いくつかの関数が実装されていません。

ソースコードがあるので、最終的には問題ないのですが、それでも...。

この記事はチュートリアルです。その中で、パネルは最低限必要なものをカバーしている。

1.子孫はそれ自身のコンストラクタを持ち、その初期化リストには親のコンストラクタを指定する。その中で必要な寸法を指定する。

2.配色はまだ考えていません)ヘッダーのサイズも同様です。

3.このようなメソッドはpublicセクションで宣言される。実装されていないのは不思議だ。その有効・無効をテストしていたのをよく覚えているのだが......。というのも、このクラスの最初のバージョンは、ディスクの空き容量がなくなったときにWindowsによって破壊されてしまったからだ。その時に復元するのを忘れてしまったんだ。ありがとう。

そう、ソースコードが利用できるようになったことで、すべてのカードは読者の手の中にある。チュートリアルの記事はそれを目的としている。

 
Artyom Trishkin #:

この記事は指導的なものだ。その中で、パネルは最低限必要なことをカバーしている。

1.子孫はそれ自身のコンストラクタを持ち、その初期化リストには親のコンストラクタが含まれていなければならない。その中で必要な寸法を指定する。

2.配色は考えていません)ヘッダーのサイズと同様に。

3.このようなメソッドはpublicセクションで宣言される。実装されていないのは不思議だ。その有効・無効をテストしていたのをよく覚えているのだが......。というのも、このクラスの最初のバージョンは、ディスクの空き容量がなくなったときにWindowsによって破壊されてしまったからだ。その時に復元するのを忘れてしまったんだ。ありがとう。

そう、ソースコードが利用できるようになったことで、すべてのカードは読者の手の中にある。チュートリアルの記事はそれを目的としている。

1.しかし、単純に初期化リストの 中で祖先コンストラクタが呼び出されたとき、そこに渡されるパラメータの計算をどこかで行わなければならない。特にそれが最も原始的なものでない場合は。

例えば、右下隅の初期表示のためのX、Y位置の計算、テーブルの予想行数に応じた高さの計算......。これは3つのクラス関数を追加する必要があり、そのすべてをコンストラクタ内の1つのコードにまとめることはできず、その後に祖先コンストラクタを呼び出す必要がある。 これは、動作はするものの、むしろ松葉杖のように見える。クラス・アーキテクチャをもっと変更に対応できるようにすればいいのだが。(もちろん、これは完璧主義者のメモからの発言である)。

2.小さな装飾は製品をより質的にする。しかし、あなたのコードは全般的に美しく、解決策も興味深い。

3.データの損失は常に非常に不快なので、信頼できるバックアップは私たちのすべてです。

ありがとうございます。

 

とても素晴らしいチュートリアルをありがとう


私はそれをダークルックに変更し、さらにタイトルとデータの色も変更したいと考えています。

また、簡単な方法でテキストを追加する関数を作成しました。

void DrawData(int cell, string title, string data, color clr ) {
   dashboard.DrawText(title,  dashboard.CellX(cell,0)+2,   dashboard.CellY(cell,0)+2, clr);
   dashboard.DrawText(data,   dashboard.CellX(cell,1)+2,   dashboard.CellY(cell,1)+2,90, clr);
   ChartRedraw(ChartID());
}

しかし、これらのテキストの色を変更するのが難しいことに気づきました。色がくすんで見えるので、何が間違っているのかわかりません。

//+------------------------------------------------------------------+
//| 指定された座標にテキストメッセージを表示する。
//+------------------------------------------------------------------+
void CDashboard::DrawText(const string text,const int x,const int y,const color clr,const int width=WRONG_VALUE,const int height=WRONG_VALUE)
  {
//--- テキストの幅と高さを記録する変数を宣言する。
   int w=width;
   int h=height;
//--- メソッドに渡されたテキストの幅と高さがゼロの場合、
//--- その後、作業空間全体が透明色を使って完全にクリアされる。
   if(width==0 && height==0)
      this.m_workspace.Erase(0x00FFFFFF);
//--- そうでなければ
   else
     {
      //--- 渡された幅と高さがデフォルト値 (-1) の場合、テキストから幅と高さを取得します。
      if(width==WRONG_VALUE && height==WRONG_VALUE)
         this.m_workspace.TextSize(text,w,h);
      //--- そうでなければ
      else
        {
         //--- メソッドに渡された幅がデフォルト値 (-1) の場合、テキストから幅を取得します。
         //--- メソッドに渡された幅の値が0より大きい場合は、メソッドに渡された幅を使う。
         //--- メソッドに渡された幅の値がゼロの場合、幅には値1を使用する。
         w=(width ==WRONG_VALUE ? this.m_workspace.TextWidth(text)  : width>0  ? width  : 1);
         //--- メソッドに渡された高さがデフォルト値 (-1) の場合は、テキストから高さを取得します。
         //--- メソッドに渡された高さの値が0より大きい場合は、メソッドに渡された高さを使います。
         //--- メソッドに渡された高さがゼロの場合、高さには値1を使用する。
         h=(height==WRONG_VALUE ? this.m_workspace.TextHeight(text) : height>0 ? height : 1);
        }
      //--- 指定された座標と、その結果得られる幅と高さに従って、空間を透明色で塗りつぶす(前のエントリを消去する)
      this.m_workspace.FillRectangle(x,y,x+w,y+h,0x00FFFFFF);
     }
//--- 以前のテキストがクリアされたスペースにテキストを表示し、画面を再描画せずに作業スペースを更新する。
   this.m_workspace.TextOut(x,y,text,::ColorToARGB(clr,this.m_alpha));
   this.m_workspace.Update(false);
  }
 

Arpit T # :

//--- 前のテキストがクリアされたスペースにテキストを表示し、画面を再描画せずに作業スペースを更新する。
   this .m_workspace. TextOut (x,y,text,:: ColorToARGB (clr, this .m_alpha ));
   this .m_workspace.Update( false );

ハイライトされた色は、テキストではなくパネル自体の透明度です。テキストについては、透明度(というか不透明度)をデフォルト値の255に設定するのがよい。しかし、this.m_alphaの代わりに0から255までの通常の数値を入力することで、不透明度の値を「弄る」ことができます。0は完全に透明な色で、255は完全に不透明な色です。

 
Artyom Trishkin #:

ハイライトされた色は、テキストではなくパネル自体の透明度です。テキストについては、透明度(というか不透明度)をデフォルト値の255に設定するのがよい。しかし、this.m_alphaの代わりに0から255までの通常の数値を入力することで、不透明度の値を「弄る」ことができます。0は完全に透明な色で、255は完全に不透明な色です。

ありがとうございます。


void DrawData(int cell, string title, string data, color clr ) {
   dashboard.DrawText(title,  dashboard.CellX(cell,0)+2,   dashboard.CellY(cell,0)+2, clr);
   dashboard.DrawText(data,   dashboard.CellX(cell,1)+2,   dashboard.CellY(cell,1)+2,90, clr);
   ChartRedraw(ChartID());
}

ハイライトされているコードが問題を起こしていたので、削除してすべて解決しました。

 
よくできた作品だ。
 
VIKRAM SINGH #:
よくできた仕事だ。

ありがとう

このテーマを使いたい場合は、dashboard.mqhのダークルック用のコンストラクタを変更してください。

//+------------------------------------------------------------------+
//| コンストラクタ|
//+------------------------------------------------------------------+
CDashboard::CDashboard(const uint id,const int x,const int y, const int w,const int h,const int wnd=-1) : 
                        m_id(id),
                        m_chart_id(::ChartID()),
                        m_program_type((ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE)),
                        m_program_name(::MQLInfoString(MQL_PROGRAM_NAME)),
                        m_wnd(wnd==-1 ? GetSubWindow() : wnd),
                        m_chart_w((int)::ChartGetInteger(m_chart_id,CHART_WIDTH_IN_PIXELS,m_wnd)),
                        m_chart_h((int)::ChartGetInteger(m_chart_id,CHART_HEIGHT_IN_PIXELS,m_wnd)),
                        m_mouse_state(MOUSE_STATE_NOT_PRESSED),
                        m_x(x),
                        m_y(::ChartGetInteger(m_chart_id,CHART_SHOW_ONE_CLICK) ? (y<79 ? 79 : y) : y),
                        m_w(w),
                        m_h(h),
                        m_x_dock(m_x),
                        m_y_dock(m_y),
                        m_header(true),
                        m_butt_close(true),
                        m_butt_minimize(true),
                        m_butt_pin(true),
                        m_header_h(18),
                        
                        //--- パネルヘッダの実装
                        m_header_alpha(255),
                        m_header_alpha_c(m_header_alpha),
                        m_header_back_color(clrBlack),
                        m_header_back_color_c(m_header_back_color),
                        m_header_fore_color(clrSnow),
                        m_header_fore_color_c(m_header_fore_color),
                        m_header_border_color(clrSnow),
                        m_header_border_color_c(m_header_border_color),
                        m_title("Dashboard"),
                        m_title_font("Calibri"),
                        m_title_font_size(-100),
                        
                        //--- 閉じるボタン
                        m_butt_close_back_color(clrBlack),
                        m_butt_close_back_color_c(m_butt_close_back_color),
                        m_butt_close_fore_color(clrSnow),
                        m_butt_close_fore_color_c(m_butt_close_fore_color),
                        
                        //--- 折りたたみ/展開ボタン
                        m_butt_min_back_color(clrBlack),
                        m_butt_min_back_color_c(m_butt_min_back_color),
                        m_butt_min_fore_color(clrSnow),
                        m_butt_min_fore_color_c(m_butt_min_fore_color),
                        
                        //--- ピンボタン
                        m_butt_pin_back_color(clrBlack),
                        m_butt_pin_back_color_c(m_butt_min_back_color),
                        m_butt_pin_fore_color(clrSnow),
                        m_butt_pin_fore_color_c(m_butt_min_fore_color),
                        
                        //--- パネルの実装
                        m_alpha(255),
                        m_alpha_c(m_alpha),
                        m_fore_alpha(255),
                        m_fore_alpha_c(m_fore_alpha),
                        m_back_color(clrBlack),
                        m_back_color_c(m_back_color),
                        m_fore_color(clrSnow),
                        m_fore_color_c(m_fore_color),
                        m_border_color(clrSnow),
                        m_border_color_c(m_border_color),
                        m_font("Calibri"),
                        m_font_size(-100),
                        
                        m_minimized(false),
                        m_movable(true)
  {
//--- チャートがマウスの移動やボタンを押したイベントに関するメッセージを送信する許可を設定する、
//--- マウスのスクロールイベント、グラフィカルオブジェクトの作成/削除
   ::ChartSetInteger(this.m_chart_id,CHART_EVENT_MOUSE_MOVE,true);
   ::ChartSetInteger(this.m_chart_id,CHART_EVENT_MOUSE_WHEEL,true);
   ::ChartSetInteger(this.m_chart_id,CHART_EVENT_OBJECT_CREATE,true);
   ::ChartSetInteger(this.m_chart_id,CHART_EVENT_OBJECT_DELETE,true);
   
//--- パネル座標、折りたたみ/展開状態、ピン留めを格納するグローバルターミナル変数の名前を設定する。
   this.m_name_gv_x=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_X";
   this.m_name_gv_y=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Y";
   this.m_name_gv_m=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Minimize";
   this.m_name_gv_u=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Unpin";
   
//--- グローバル変数が存在しない場合は、それを作成し、現在の値を書き込む、
//--- そうでなければ、端末のグローバル変数から値を読み込む。
//--- X座標
   if(!::GlobalVariableCheck(this.m_name_gv_x))
      ::GlobalVariableSet(this.m_name_gv_x,this.m_x);
   else
      this.m_x=(int)::GlobalVariableGet(this.m_name_gv_x);
//--- Y座標
   if(!::GlobalVariableCheck(this.m_name_gv_y))
      ::GlobalVariableSet(this.m_name_gv_y,this.m_y);
   else
      this.m_y=(int)::GlobalVariableGet(this.m_name_gv_y);
//--- 折りたたみ/拡大
   if(!::GlobalVariableCheck(this.m_name_gv_m))
      ::GlobalVariableSet(this.m_name_gv_m,this.m_minimized);
   else
      this.m_minimized=(int)::GlobalVariableGet(this.m_name_gv_m);
//--- 折りたたまれている/いない
   if(!::GlobalVariableCheck(this.m_name_gv_u))
      ::GlobalVariableSet(this.m_name_gv_u,this.m_movable);
   else
      this.m_movable=(int)::GlobalVariableGet(this.m_name_gv_u);

//--- パネルのサイズがチャート・ウィンドウのサイズを超える場合のフラグを設定する。
   this.m_higher_wnd=this.HigherWnd();
   this.m_wider_wnd=this.WiderWnd();

//--- パネル・グラフィカル・リソースが作成された場合、
   if(this.m_canvas.CreateBitmapLabel(this.m_chart_id,this.m_wnd,"P"+(string)this.m_id,this.m_x,this.m_y,this.m_w,this.m_h,COLOR_FORMAT_ARGB_NORMALIZE))
     {
      //--- キャンバスのフォントを設定し、キャンバスを透明色で塗りつぶす
      this.m_canvas.FontSet(this.m_title_font,this.m_title_font_size,FW_BOLD);
      this.m_canvas.Erase(0x00FFFFFF);
     }
//--- そうでない場合は、オブジェクトの作成に失敗したことをジャーナルに報告します。
   else
      ::PrintFormat("%s: Error. CreateBitmapLabel for canvas failed",(string)__FUNCTION__);

//--- グラフィカル・リソースのワーキング・スペースが作成された場合、
   if(this.m_workspace.CreateBitmapLabel(this.m_chart_id,this.m_wnd,"W"+(string)this.m_id,this.m_x+1,this.m_y+this.m_header_h,this.m_w-2,this.m_h-this.m_header_h-1,COLOR_FORMAT_ARGB_NORMALIZE))
     {
      //--- 作業領域のフォントを設定し、透明色で塗りつぶす。
      this.m_workspace.FontSet(this.m_font,this.m_font_size);
      this.m_workspace.Erase(0x00FFFFFF);
     }
//--- そうでない場合は、オブジェクトの作成に失敗したことをジャーナルに報告します。
   else
      ::PrintFormat("%s: Error. CreateBitmapLabel for workspace failed",(string)__FUNCTION__);
  }
 
Artemさん、こんにちは!インフォメーションパネルの作り方を勉強しているのですが、一つも理解できません!私はプロではないので...。一般的には、CDashboard * dashboard =NULL; クラスのインスタンスを作成しました。そして、NULLを代入する。その後、oninitでディスクリプタを代入する... dashboard = new CDashboard(InpUniqID, InpPanelX, InpPanelY, 500, 700); なぜこうなるのか?このCDashboard dashboardのようにはならないのか?それともオブジェクトではこうなるのか?頭が混乱しています!もしよければ.わかりやすく説明してください.ありがとうございました!
 
Igor Bakhrushen NULL; クラスのインスタンスを作成しました。そして、NULLを代入する。その後、oninitでディスクリプタを代入する... dashboard = new CDashboard(InpUniqID, InpPanelX, InpPanelY, 500, 700); なぜこうなるのか?このCDashboard dashboardのようにはならないのか?それともオブジェクトではこうなるのか?頭が混乱しています!もしよければ.わかりやすく説明してください.ありがとうございました!

こんにちは。

このように

CDashboard  *dashboard = NULL;

将来、動的に生成される新しいクラスのオブジェクトへのポインタ変数が宣言され、すぐに値NULLで 初期化されます。


そして、クラスのインスタンスがこのように宣言されます:

CDashboard   dashboard;

このクラスには、正式なパラメータを持たないコンストラクタがありません。

したがって、この方法でインスタンスを宣言する場合は、クラスのコンストラクタに渡すクラス・オブジェクトの必要なパラメータをすべて指定しなければなりません:

CDashboard   dashboard(InpUniqID, InpPanelX, InpPanelY, 200, 250);

------------------------

クラスを扱う例では、まずインジケータに未来のオブジェクトへの空のポインタが作成され、次に OnInit() でパネル・オブジェクトが作成され、作成されたオブジェクトへのポインタがポインタ変数に書き込まれます:

//--- パネル・オブジェクトの作成
   dashboard=new CDashboard(InpUniqID,InpPanelX,InpPanelY,200,250);
   if(dashboard==NULL)
     {
      Print("Error. Failed to create dashboard object");
      return INIT_FAILED;
     }


その後、OnDeinit() で、このポインタを使用してオブジェクトがメモリから削除されます:

//--- パネル・オブジェクトが存在する場合は、それを削除する。
   if(dashboard!=NULL)
      delete dashboard;

作成されたオブジェクトへのポインターを変数に書き込まずに、単にnew 演算子で新しい オブジェクトを作成した場合、そのオブジェクトを後で削除することができず、メモリー・リークになります。

つまり、簡単に言うと、記事の例では

  1. 未来のクラス・オブジェクトへの変数ポインタを宣言し、NULL 値で初期化する、
  2. 新しいクラス・オブジェクトを作成し、そのポインタを先に作成したダッシュボード変数に書き込みます、
  3. 作成されたオブジェクトにアクセスするときは、ポインタ変数とポイント ( dashboard.AnyMethod() ) を使用します。
  4. 作業終了時に、ポインタによって動的に作成されたクラス・オブジェクトを削除します。

もしクラスの必要なインスタンス(CDashboard dashboard)がすぐに作成されていたら、それへのポインタは必要なかったでしょう。ターミナル・サブシステムが勝手に削除してくれるからだ。しかし、このクラスのインスタンスはプログラム内でこれだけとなる。

動的生成では、必要なクラスの新しいオブジェクトをその場で作成し、ポインタで参照することができる。これが、この例でクラス・オブジェクトの動的生成が使われた理由だ。簡略化され、いくつかの点をカバーしていない。