記事"グラフィカルインタフェースX: 標準チャートコントロール(ビルド4)"についてのディスカッション - ページ 2

 
Artyom Trishkin:

アナトリー、エラーの原因を教えてください。

2016.10.19 03:09:04.993 TestTable (EURUSD,H1)   invalid pointer access in 'Scrolls.mqh' (698,10)

このアップデートの前はすべてうまくいっていました。今、CTableテーブルを構築するときに、このエラーがポップアップします。

どこが間違っているのか教えてください - すべての行をすでに印刷しました - インターフェイスは構築されていますが、どこかでつまずいた後、....エラー。

アーカイブ内の例のファイル。

CCanvasTable クラスで先に行ったので、訂正するのを忘れていました。

CTable クラスでは、現在のバージョンのCreateScrollV() メソッドとCreateScrollH() メソッドを以下のリストに示すものに置き換える必要があります:

//+------------------------------------------------------------------+
//|| 垂直スクロールバーを作成する。
//+------------------------------------------------------------------+
bool CTable::CreateScrollV(void)
  {
//--- フォーム・ポインタを保存する
   m_scrollv.WindowPointer(m_wnd);
//--- 座標
   int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth();
   int y=CElement::Y();
//--- 寸法を設定する
   m_scrollv.Id(CElement::Id());
   m_scrollv.IsDropdown(CElement::IsDropdown());
   m_scrollv.XSize(m_scrollv.ScrollWidth());
   m_scrollv.YSize((m_columns_total>m_visible_columns_total)? m_y_size-m_scrollv.ScrollWidth()+1 : m_y_size);
   m_scrollv.AnchorRightWindowSide(m_anchor_right_window_side);
   m_scrollv.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- スクロールバーの作成
   if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total))
      return(false);
//--- 今必要なければ隠す
   if(m_rows_total<=m_visible_rows_total)
      m_scrollv.Hide();
//---
   return(true);
  }
//+------------------------------------------------------------------+
//|| 水平スクロールバーを作成する。
//+------------------------------------------------------------------+
bool CTable::CreateScrollH(void)
  {
//--- フォーム・ポインタを保存する
   m_scrollh.WindowPointer(m_wnd);
//--- 座標
   int x=CElement::X();
   int y=(m_anchor_bottom_window_side)? m_y-m_area.Y_Size()+m_scrollh.ScrollWidth() : CElement::Y2()-m_scrollh.ScrollWidth();
//--- 寸法を設定する
   m_scrollh.Id(CElement::Id());
   m_scrollh.IsDropdown(CElement::IsDropdown());
   m_scrollh.XSize((m_rows_total>m_visible_rows_total)? m_area.XSize()-m_scrollh.ScrollWidth()+1 : m_area.XSize());
   m_scrollh.YSize(m_scrollh.ScrollWidth());
   m_scrollh.AnchorRightWindowSide(m_anchor_right_window_side);
   m_scrollh.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- スクロールバーの作成
   if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total))
      return(false);
//--- 今必要なければ隠す
   if(m_columns_total<=m_visible_columns_total)
      m_scrollh.Hide();
//---
   return(true);
  }


//---

同様の変更をCLabelsTable クラスでも行う必要があります。修正は次回の更新で行います。

 
Anatoli Kazharski:

先にCCanvasTable クラスで行ったので、修正するのを忘れていました。

CTable クラスでは、現在のバージョンのCreateScrollV() メソッドとCreateScrollH() メソッドを以下のリストに示すものに置き換える必要があります:

...
//---

同様の変更をCLabelsTable クラスでも行う必要があります。修正は次回のアップデートで行います。

О!ありがとうございました!
 
Anatoli Kazharski:

先にCCanvasTable クラスで行ったので、修正するのを忘れていました。

CTable クラスでは、現在のバージョンのCreateScrollV() メソッドとCreateScrollH() メソッドを以下のリストに示すものに置き換える必要があります:

//+------------------------------------------------------------------+
//|| 垂直スクロールバーを作成する。
//+------------------------------------------------------------------+
bool CTable::CreateScrollV(void)
  {
//--- フォーム・ポインタを保存する
   m_scrollv.WindowPointer(m_wnd);
//--- 座標
   int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth();
   int y=CElement::Y();
//--- 寸法を設定する
   m_scrollv.Id(CElement::Id());
   m_scrollv.IsDropdown(CElement::IsDropdown());
   m_scrollv.XSize(m_scrollv.ScrollWidth());
   m_scrollv.YSize((m_columns_total>m_visible_columns_total)? m_y_size-m_scrollv.ScrollWidth()+1 : m_y_size);
   m_scrollv.AnchorRightWindowSide(m_anchor_right_window_side);
   m_scrollv.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- スクロールバーの作成
   if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total))
      return(false);
//--- 今必要なければ隠す
   if(m_rows_total<=m_visible_rows_total)
      m_scrollv.Hide();
//---
   return(true);
  }
//+------------------------------------------------------------------+
//|| 水平スクロールバーを作成する。
//+------------------------------------------------------------------+
bool CTable::CreateScrollH(void)
  {
//--- フォーム・ポインタを保存する
   m_scrollh.WindowPointer(m_wnd);
//--- 座標
   int x=CElement::X();
   int y=(m_anchor_bottom_window_side)? m_y-m_area.Y_Size()+m_scrollh.ScrollWidth() : CElement::Y2()-m_scrollh.ScrollWidth();
//--- 寸法を設定する
   m_scrollh.Id(CElement::Id());
   m_scrollh.IsDropdown(CElement::IsDropdown());
   m_scrollh.XSize((m_rows_total>m_visible_rows_total)? m_area.XSize()-m_scrollh.ScrollWidth()+1 : m_area.XSize());
   m_scrollh.YSize(m_scrollh.ScrollWidth());
   m_scrollh.AnchorRightWindowSide(m_anchor_right_window_side);
   m_scrollh.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- スクロールバーの作成
   if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total))
      return(false);
//--- 今必要なければ隠す
   if(m_columns_total<=m_visible_columns_total)
      m_scrollh.Hide();
//---
   return(true);
  }


//---

同様の変更をCLabelsTable クラスでも行う必要があります。次の更新で修正する予定です。

Anatoly、変更は行われました。MQL5Indicatorsの例を取って、Program.mqhのテーブルを修正して、行数が可視行数と一致するか、列数が可視列数と一致するか、両方一致するようにしてください。例えば

//+------------------------------------------------------------------+
//|| テーブルの作成|
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
  {
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL    (15)
//--- フォームへのポインタを保存する
   m_table.WindowPointer(m_window1);
//--- 座標
   int x=m_window1.X()+TABLE1_GAP_X;
   int y=m_window1.Y()+TABLE1_GAP_Y;
//--- 見える列と行の数
   int visible_columns_total =6;
   int visible_rows_total    =15;
//--- 作成前にプロパティを設定する
   m_table.XSize(600);
   m_table.RowYSize(20);
   m_table.FixFirstRow(true);
   m_table.FixFirstColumn(true);
   m_table.LightsHover(true);
   m_table.SelectableRow(true);
   m_table.TextAlign(ALIGN_CENTER);
   m_table.HeadersColor(C'255,244,213');
   m_table.HeadersTextColor(clrBlack);
   m_table.CellColorHover(clrGold);
   m_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
   m_table.VisibleTableSize(visible_columns_total,visible_rows_total);
//--- コントロールの作成
   if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- テーブルを埋めてみよう:
// 最初のセルは空
   m_table.SetValue(0,0,"-");
//--- 列の見出し
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=0; r<1; r++)
         m_table.SetValue(c,r,"SYMBOL "+string(c));
     }
//--- 行の見出し、テキストの整列方法 - 右寄せ
   for(int c=0; c<1; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,"PARAMETER "+string(r));
         m_table.TextAlign(c,r,ALIGN_RIGHT);
        }
     }
//--- データと表のフォーマット(背景色とセルの色)
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,string(c)+":"+string(r));
         m_table.TextColor(c,r,(c%2==0)? clrRed : clrRoyalBlue);
         m_table.CellColor(c,r,(r%2==0)? clrWhiteSmoke : clrWhite);
        }
     }
//--- 変更を示すためにテーブルを更新する
   m_table.UpdateTable();
//--- オブジェクト・グループの共通配列にオブジェクトを追加する。
   CWndContainer::AddToElementsArray(0,m_table);
   return(true);
  }
//+------------------------------------------------------------------+

コンパイルしてサンプルを実行し、表の一番下の行をクリックします(すべて正常です)。2回目のクリックでエラーがポップアップします:

2016.10.24 03:37:16.407 ChartWindow02 (USDCHF,H1)       array out of range in 'Table.mqh' (1091,86)

どうすればいいのでしょうか?

 
Artyom Trishkin:

Anatoly、変更しました。MQL5Indicatorsの例を取って、Program.mqhのテーブルを修正して、行の数が見える行の数と一致するか、列の数が見える列の数と一致するか、あるいは両方一致するようにしてください。例えばこのように:

...

コンパイルしてサンプルを実行し、表の一番下の行をクリックして(すべて正常)、もう一度クリックしてください。2回目のクリックでエラーが表示されます:

2016.10.24 03:37:16.407 ChartWindow02 (USDCHF,H1)       array out of range in 'Table.mqh' (1091,86)

どうすればいいのでしょうか?

CScrollH クラスと CScrollV クラスのScrollBarControl() メソッドで、以下のリストに示す ように、要素の可視性に関する追加チェックを追加する必要があります:

//+------------------------------------------------------------------+
//| スクロール・コントロール|
//+------------------------------------------------------------------+
bool CScrollH::ScrollBarControl(const int x,const int y,const bool mouse_state)
  {
//--- フォームへのポインタがない場合は終了する。
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
      return(false);
//--- フォームが他の要素によってブロックされたら終了する。
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return(false);
//--- アイテムが非表示の場合は終了する
   if(!CElement::IsVisible())
     return(false);

//--- スライダーのフォーカスをチェックする
   m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
                      y>m_thumb.Y() && y<m_thumb.Y2());
//--- マウスボタンの状態をチェックし、記憶する。
   CScroll::CheckMouseButtonState(mouse_state);
//--- リストのスクロールバーの色を変更する。
   CScroll::ChangeObjectsColor();
//--- コントロールがスクロール・バーに渡される場合は、スライダーの位置を定義する。
   if(CScroll::ScrollState())
     {
      //--- スライダーを動かす
      OnDragThumb(x);
      //--- スライダーの位置番号を変更する
      CalculateThumbPos();
      return(true);
     }
   return(false);
  }

//---

この修正は、次のライブラリの更新で利用できるようになります。

 
Anatoli Kazharski:

CScrollH クラスとCScrollV クラスのScrollBarControl() メソッドでは、以下のリストに示す ように、要素の可視性のチェックを追加する必要があります:

...

この修正は、次のライブラリの更新で利用できるようになります。

ありがとうございます。Scrolls.mqhファイルのCScrollHクラスと CScrollVクラスに行を追加しました:

//+------------------------------------------------------------------+
//| スライダー・コントロール|
//+------------------------------------------------------------------+
bool CScrollV::ScrollBarControl(const int x,const int y,const bool mouse_state)
  {
//--- フォームへのポインタがない場合は終了する。
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
      return(false);
//--- フォームがロックされておらず、識別子が一致する場合
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return(false);
//--- アイテムが非表示の場合は終了する
   if(!CElement::IsVisible())
     return(false);

//--- スライダーのフォーカスをチェックする
   m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
                      y>m_thumb.Y() && y<m_thumb.Y2());
//--- マウスボタンの状態をチェックし、記憶する。
   CScroll::CheckMouseButtonState(mouse_state);
//--- スライダーの色を変更する
   CScroll::ChangeObjectsColor();
//--- コントロールがスクロール・バーに渡される場合は、スライダーの位置を定義する。
   if(CScroll::ScrollState())
     {
      //--- スライダーを動かす
      OnDragThumb(y);
      //--- スライダーの位置番号を変更する
      CalculateThumbPos();
      return(true);
     }
//---
   return(false);
  }
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| スクロール・コントロール|
//+------------------------------------------------------------------+
bool CScrollH::ScrollBarControl(const int x,const int y,const bool mouse_state)
  {
//--- フォームへのポインタがない場合は終了する。
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
      return(false);
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return(false);
//--- アイテムが非表示の場合は終了する
   if(!CElement::IsVisible())
     return(false);

//--- スライダーのフォーカスをチェックする
   m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
                      y>m_thumb.Y() && y<m_thumb.Y2());
//--- マウスボタンの状態をチェックし、記憶する。
   CScroll::CheckMouseButtonState(mouse_state);
//--- リストのスクロールバーの色を変更する。
   CScroll::ChangeObjectsColor();
//--- コントロールがスクロール・バーに渡される場合は、スライダーの位置を定義する。
   if(CScroll::ScrollState())
     {
      //--- スライダーを動かす
      OnDragThumb(x);
      //--- スライダーの位置番号を変更する
      CalculateThumbPos();
      return(true);
     }
   return(false);
  }
//+------------------------------------------------------------------+

Program.mqhの テーブル作成関数を変更して、すべての列と行の数が表示される列と行の数と一致するようにしました:

//+------------------------------------------------------------------+
//|| テーブルの作成|
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
  {
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL    (15)
//--- フォームへのポインタを保存する
   m_table.WindowPointer(m_window1);
//--- 座標
   int x=m_window1.X()+TABLE1_GAP_X;
   int y=m_window1.Y()+TABLE1_GAP_Y;
//--- 見える列と行の数
   int visible_columns_total =6;
   int visible_rows_total    =15;
//--- 作成前にプロパティを設定する
   m_table.XSize(600);
   m_table.RowYSize(20);
   m_table.FixFirstRow(true);
   m_table.FixFirstColumn(true);
   m_table.LightsHover(true);
   m_table.SelectableRow(true);
   m_table.TextAlign(ALIGN_CENTER);
   m_table.HeadersColor(C'255,244,213');
   m_table.HeadersTextColor(clrBlack);
   m_table.CellColorHover(clrGold);
   m_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
   m_table.VisibleTableSize(visible_columns_total,visible_rows_total);
//--- コントロールの作成
   if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- テーブルを埋めてみよう:
// 最初のセルは空
   m_table.SetValue(0,0,"-");
//--- 列の見出し
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=0; r<1; r++)
         m_table.SetValue(c,r,"SYMBOL "+string(c));
     }
//--- 行の見出し、テキストの整列方法は右揃え
   for(int c=0; c<1; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,"PARAMETER "+string(r));
         m_table.TextAlign(c,r,ALIGN_RIGHT);
        }
     }
//--- データと表のフォーマット(背景色とセルの色)
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,string(c)+":"+string(r));
         m_table.TextColor(c,r,(c%2==0)? clrRed : clrRoyalBlue);
         m_table.CellColor(c,r,(r%2==0)? clrWhiteSmoke : clrWhite);
        }
     }
//--- 変更を示すためにテーブルを更新する
   m_table.UpdateTable();
//--- オブジェクト・グループの共通配列にオブジェクトを追加する。
   CWndContainer::AddToElementsArray(0,m_table);
   return(true);
  }
//+------------------------------------------------------------------+

ChartWindow02.ex5をコンパイルして実行する。

表の一番下の行を何度かクリックすると、配列の外に飛んでしまいます:

2016.10.25 01:39:22.899 ChartWindow02 (USDCHF,H1)       array out of range in 'Table.mqh' (1096,86)
何も変わっていないように見えますか?
 
Artyom Trishkin:

...

何も変わっていないのですか?

私が行った変更の後、それはもう再生されません。他にも変更を加えたかもしれないが、覚えていない。細かい編集の履歴は持っていません。

念のため、CScroll::Show()メソッドとCScroll::Hide()メソッドを以下のバージョンに置き換えてみてください:

//+------------------------------------------------------------------+
//| メニュー項目を表示|
//+------------------------------------------------------------------+
void CScroll::Show(void)
  {
//--- リストアイテムの数がリストの可視部分の数より大きくない場合は終了する
   if(m_items_total<=m_visible_items_total)
      return;
//---
   m_area.Timeframes(OBJ_ALL_PERIODS);
   m_bg.Timeframes(OBJ_ALL_PERIODS);
   m_inc.Timeframes(OBJ_ALL_PERIODS);
   m_dec.Timeframes(OBJ_ALL_PERIODS);
   m_thumb.Timeframes(OBJ_ALL_PERIODS);
//--- オブジェクトの位置を更新する
   Moving(m_wnd.X(),m_wnd.Y(),true);
//--- 視認性の状態
   CElement::IsVisible(true);
  }
//+------------------------------------------------------------------+
//| メニュー項目を隠す|
//+------------------------------------------------------------------+
void CScroll::Hide(void)
  {
   m_area.Timeframes(OBJ_NO_PERIODS);
   m_bg.Timeframes(OBJ_NO_PERIODS);
   m_inc.Timeframes(OBJ_NO_PERIODS);
   m_dec.Timeframes(OBJ_NO_PERIODS);
   m_thumb.Timeframes(OBJ_NO_PERIODS);
//--- 視認性の状態
   CElement::IsVisible(false);
  }


//---

これで解決しない場合は、次のアップデートを待つ必要があります。

 
Anatoli Kazharski:

しかし、私が行った変更の後、それはもう再生されません。他にも変更を加えたかもしれないが、覚えていない。細かい編集の履歴はマークしていません。

念のため、CScroll::Show()メソッドとCScroll::Hide()メソッドを以下のバージョンに置き換えてみてください:

//+------------------------------------------------------------------+
//| メニュー項目を表示|
//+------------------------------------------------------------------+
void CScroll::Show(void)
  {
//--- リストアイテムの数がリストの可視部分の数より大きくない場合は終了する
   if(m_items_total<=m_visible_items_total)
      return;
//---
   m_area.Timeframes(OBJ_ALL_PERIODS);
   m_bg.Timeframes(OBJ_ALL_PERIODS);
   m_inc.Timeframes(OBJ_ALL_PERIODS);
   m_dec.Timeframes(OBJ_ALL_PERIODS);
   m_thumb.Timeframes(OBJ_ALL_PERIODS);
//--- オブジェクトの位置を更新する
   Moving(m_wnd.X(),m_wnd.Y(),true);
//--- 視認性の状態
   CElement::IsVisible(true);
  }
//+------------------------------------------------------------------+
//| メニュー項目を隠す|
//+------------------------------------------------------------------+
void CScroll::Hide(void)
  {
   m_area.Timeframes(OBJ_NO_PERIODS);
   m_bg.Timeframes(OBJ_NO_PERIODS);
   m_inc.Timeframes(OBJ_NO_PERIODS);
   m_dec.Timeframes(OBJ_NO_PERIODS);
   m_thumb.Timeframes(OBJ_NO_PERIODS);
//--- 視認性の状態
   CElement::IsVisible(false);
  }


//---

これで解決しない場合は、次のアップデートを待つ必要があります。

ありがとうございます。Show()の表示状態に関する行が抜けていました:

//--- 視認性の状態
   CElement::IsVisible(true);

とHide()に表示状態に関する行が抜けていました:

//--- 視認性の状態
   CElement::IsVisible(false);
 
Artyom Trishkin:

ありがとうございます。Show()の中に、表示状態に関する行が抜けていました:

//--- 視認性の状態
   CElement::IsVisible(true);

とHide()に表示状態に関する行が不足していました:

//--- 視認性の状態
   CElement::IsVisible(false);

もうひとつ修正が必要です。可視性は要素の位置を更新する前に設定されるべきです。このように:

...
//--- 視認性の状態
   CElement::IsVisible(true);
//--- オブジェクトの位置を更新する
   Moving(m_wnd.X(),m_wnd.Y(),true);
...
 

タイマーを介して実装されたインターフェイス要素のインタラクティブ性は、奇妙な解決策である。- なぜタイマーを使って(あるいはタイマーを使って)実装しなければならないのか?- もちろん、多くのリソースを消費することになる。

コントロールの状態を制御するのにタイマーはまったく必要ない。

1.配列(マップ)内の全要素の現在座標を記録する。ウィンドウを動かしながら、すべてのフォーム・オブジェクトの位置座標を調整する。

2.座標から要素を見つける関数を作る(ローカライザー)。この関数は、記録された現在の要素座標をループし、現在カーソルの下にある要素を見つけます。

3.CHARTEVENT_MOUSE_MOVE "イベント(カーソル移動イベント)からローカライザーを呼び出します。

4.そこで、ObjectSetInteger()関数が オブジェクトに適用され、強制的に色が変更されます。


ご覧のように、この方式ではタイマーがないので、リソースを無駄に消費することがありません。

 
Реter Konow:

タイマーを介して実装されたインターフェイス要素のインタラクティブ性は、奇妙な解決策である。- なぜタイマーを使って(あるいはタイマーを使って)実装しなければならないのか?- もちろん、多くのリソースを消費することになる。

...

見ての通り、この方式にはタイマーがないので、不必要なリソースの消費はありません。

あなたは間違っている。なぜこのような方式にしたかは、すでに上のコメントで十分詳しく答えている。

今では(Windows 10でも)多くのリソースを消費することはない。記事(コメントも)を読みましたか?

//---

P.S. ところで、異なる端末(MT4/MT5)とOSバージョン(Windows)でのCPUリソース消費は、同じ条件下でも大きく異なります。Windows 7ではMetaTrader 4 ターミナルはMetaTrader 5よりも かなり優れていました。残念ながら、私はすでにWindows 10に 完全に切り替えたので、今はその数字をお伝えすることはできません。

最適化に関しては、私はまだすべてのオプションを使い果たしていません。まだ最適化すべきものがあり、その方法を理解している。