ライブラリ: EasyAndFastGUIグラフィックインターフェース作成ライブラリ - ページ 11

 
Anatoli Kazharski:

当初は、GUIを作成した後に要素を移動させるというような作業はありませんでした。すべては、各要素がすでに必要な動作をすべて実装しているという考えに基づいていた。

反対の質問なぜ要素を動かす必要があるのですか?何をしたいのか?GUIとインタラクトするとき、どのような挙動を得たいのか?

何かが壊れるかどうかを理解するためには、基本クラスを変更するたびにすべての要素をテストする必要がある。それをすぐに言うのはもう難しい。久しぶりに深く調べてみた。

ライブラリの全要素でテストGUIを作り、変更後にテストする。

例えば、展開可能なリスト。クリックすると、一部の要素が非表示になり、下のものがすべて引き上げられる。また、その逆もあります。

テストGUIはいいアイデアだ。)

ちなみに、同じCElement::Moving.Elementで、バインディングがある場合は、その要素は非表示になる

//--- バインディングが右側にある場合
   if(m_anchor_right_window_side)
     {
      //--- 要素フィールドに座標を保存する
      CElementBase::X(m_main.X2()-XGap());
      //--- 座標をオブジェクト・フィールドに保存する
      m_canvas.X(m_main.X2()-m_canvas.XGap());
     }
   else
     {
      CElementBase::X(m_main.X()+XGap());
      m_canvas.X(m_main.X()+m_canvas.XGap());
     }
//--- バインディングが以下のものである場合
   if(m_anchor_bottom_window_side)
     {
      CElementBase::Y(m_main.Y2()-YGap());
      m_canvas.Y(m_main.Y2()-m_canvas.YGap());
     }
   else
     {
      CElementBase::Y(m_main.Y()+YGap());
      m_canvas.Y(m_main.Y()+m_canvas.YGap());
     }

バインディングがあれば、要素はキャンバスと一緒に移動する。だから、理論的には何も壊れることはないはずだ :)

 

そのライブラリを使用してコンボボックスを作成し、その中の要素を変更しようとした人はいますか?

私はコンボボックスを作成し、すべてが動作します。次に、次の関数を使用して要素で埋めます:

void CPresenter::setCombobox(CComboBox *cb_ptr,CArrayString &arr)
  {
   CListView *lv_ptr=cb_ptr.GetListViewPointer();
   lv_ptr.Clear(true);
   
   cb_ptr.ItemsTotal(arr.Total());
   for(int i=0;i<arr.Total();i++)
      cb_ptr.SetValue(i,arr[i]);
   lv_ptr.SelectItem(0,true);
   cb_ptr.SelectItem(0);
   cb_ptr.Update(true);
   cb_ptr.GetButtonPointer().Update(true);
  }

すべてうまくいきます。例えば、3番目の値を選択し、ボタンをクリックすると、一連の動作の結果、コンボボックスがオーバーフローします。その結果、コンボボックスがオーバーフローしてしまいます。そして、1つの値で再充填します(例えば、最初は20の項目がありましたが、ボタンをクリックした後は1つの項目しか残っていません!)。

そして、ここで興味深いエラーが発生しました。(上記の関数を使用して)すべてが上書きされた後、コンボボックスを開こうとしたのですが、Array out of rangeというエラーが出てしまい、開くことができません!
このエラーは、次のメソッドで発生しました:
void CListView::RedrawItemsByMode(const bool is_selected_item=false)。

1364行目。
1) リストの3番目のアイテムを選択するとき(ボタンを押す前) - 変数
m_prev_item_index_focusは、インデックスが3に等しい値で満たされる。

そして、このインデックスは、変数prev_item_indexを通じて、1357行目の配列
indexes

。その結果(1364行目)、
m_itemsの配列から、インデックス#2(インデックス#3に対応)の値が選択される。

のインデックス#2(最後に選択された要素に対応するインデックス)から値が選択された。




。論理的には、CListViewクラスの Clearメソッドでクリアされるはずで、それを使ってすべてのアイテムをクリアしたのだが、残念ながらそのようなメソッドは見つからなかった。



1) ライブラリのバグでしょうか、それとも私の値の更新が間違っているのでしょうか?
2) この問題を回避する最善の方法は何でしょうか?

 
私の質問に対する最低限の再現可能なコード:

//+------------------------------------------------------------------+
//|TestCombobox.mq5
//| Copyright 2018, MetaQuotes Software Corp.
//|https://www.mql5.com
//+------------------------------------------------------------------+

#include <EasyAndFastGUI\WndEvents.mqh>
#include <Arrays/ArrayString.mqh>
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CWindowManager : public CWndEvents
  {
public:
   void              OnDeinitEvent(const int reason){CWndEvents::Destroy();};
   //--- グラフ・イベント・ハンドラ
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);//

   //--- プログラムのグラフィカル・インターフェースを作成する。
   bool              CreateGUI(void);

private:
   CComboBox         m_cb;
   CButton           m_btn;

   void              Btn_Click(int id,long lparam);

   bool              CreateComboBox(const string comboBox_name,
                                    const string &items_text[],
                                    const int x_gap,
                                    const int y_gap,
                                    const int x_size,
                                    const int y_size,
                                    CComboBox &comboBox_link,
                                    int x_ButtonSize=0);
   bool              CreateButton(const string text,
                                  const int x_gap,
                                  const int y_gap,
                                  const int x_size,
                                  const int y_size,
                                  CButton &btn_link);
   bool              CreateWindow(const string text);

   void              setCombobox(CComboBox *cb_ptr,CArrayString &arr);
   //--- メイン・ウィンドウ
   CWindow           m_window;
   //--- チャート・ウィンドウのIDと番号
   long              m_chart_id;
   int               m_subwin;
  };

CWindowManager _window;
//+------------------------------------------------------------------+
//| エキスパート初期化関数|
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!_window.CreateGUI())
     {
      Print(__FUNCTION__," > GUIの作成に失敗しました!");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
|エキスパート初期化関数|
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   _window.OnDeinitEvent(reason);
  }
//+------------------------------------------------------------------+
//| エキスパートティック機能|
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnChartEvent(const int    id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   _window.ChartEvent(id,lparam,dparam,sparam);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void CWindowManager::setCombobox(CComboBox *cb_ptr,CArrayString &arr)
  {
   CListView *lv_ptr=cb_ptr.GetListViewPointer();

   lv_ptr.Clear(true);
   cb_ptr.ItemsTotal(arr.Total());
   for(int i=0;i<arr.Total();i++)
      cb_ptr.SetValue(i,arr[i]);
   lv_ptr.SelectItem(0,true);
   cb_ptr.SelectItem(0);
   cb_ptr.Update(true);
   cb_ptr.GetButtonPointer().Update(true);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateWindow(const string text)
  {
//--- ウィンドウ配列にウィンドウ・ポインタを追加する。
   CWndContainer::AddWindow(m_window);
//--- 座標
   int x=(m_window.X()>0) ? m_window.X() : 1;
   int y=(m_window.Y()>0) ? m_window.Y() : 1;
//--- プロパティ
   m_window.XSize(300);
   m_window.YSize(300);
   m_window.Alpha(200);
   m_window.IconXGap(3);
   m_window.IconYGap(2);
   m_window.IsMovable(true);
   m_window.ResizeMode(false);
   m_window.CloseButtonIsUsed(true);
   m_window.FullscreenButtonIsUsed(false);
   m_window.CollapseButtonIsUsed(true);
   m_window.TooltipsButtonIsUsed(false);
   m_window.RollUpSubwindowMode(true,true);
   m_window.TransparentOnlyCaption(true);

//--- ツールチップの設定
   m_window.GetCloseButtonPointer().Tooltip("Close");
   m_window.GetCollapseButtonPointer().Tooltip("Collapse/Expand");
//--- フォームの作成
   if(!m_window.CreateWindow(m_chart_id,m_subwin,text,x,y))
      return(false);
//---
   return(true);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateButton(const string text,
                                  const int x_gap,
                                  const int y_gap,
                                  const int x_size,
                                  const int y_size,
                                  CButton &btn_link)
  {
//--- メイン要素へのポインタを保存する
   btn_link.MainPointer(m_window);
//--- プロパティ
   btn_link.XSize(x_size);
   btn_link.YSize(y_size);
   btn_link.IconXGap(3);
   btn_link.IconYGap(3);
   btn_link.IsCenterText(true);
//--- コントロールの作成
   if(!btn_link.CreateButton(text,x_gap,y_gap))
      return(false);
//--- ベースの要素へのポインタを追加する。
   CWndContainer::AddToElementsArray(0,btn_link);
   return(true);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateComboBox(const string comboBox_name,
                                    const string &items_text[],
                                    const int x_gap,
                                    const int y_gap,
                                    const int x_size,
                                    const int y_size,
                                    CComboBox &comboBox_link,
                                    int x_lableXSize)
  {
//--- メイン要素へのポインタを保存する
   comboBox_link.MainPointer(m_window);

   if(x_lableXSize==0)
      x_lableXSize=x_size;

   int items_total=ArraySize(items_text);

//--- 作成前にプロパティを設定する
   comboBox_link.XSize(x_size);
   comboBox_link.YSize(y_size);
   comboBox_link.ItemsTotal(items_total);
   comboBox_link.AnchorRightWindowSide(false);
   comboBox_link.GetButtonPointer().YSize(y_size);

   if(StringCompare(comboBox_name,"")==0)
     {
      comboBox_link.GetButtonPointer().XSize(x_size);
      comboBox_link.GetButtonPointer().AnchorRightWindowSide(true);
     }
   else
     {
      comboBox_link.GetButtonPointer().XSize(x_lableXSize);
      comboBox_link.GetButtonPointer().AnchorRightWindowSide(false);
     }

//--- コンボボックスのリストに項目の値を保存する
   for(int i=0;i<items_total;i++)
      comboBox_link.SetValue(i,items_text[i]);

//--- リストポインタを取得する
   CListView *lv=comboBox_link.GetListViewPointer();

//--- リストのプロパティを設定する
   lv.YSize((int)MathMin(items_total*y_size,150));
   lv.LightsHover(true);
   lv.SelectItem(lv.SelectedItemIndex()==WRONG_VALUE ? 0 : lv.SelectedItemIndex());

//--- コントロールの作成
   if(!comboBox_link.CreateComboBox(comboBox_name,x_gap,y_gap))
      return false;

   CWndContainer::AddToElementsArray(0,comboBox_link);
   return true;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateGUI(void)
  {
   if(!CreateWindow("Combobox Bug ???? "))
      return(false);
   string cb_arr[20];
   for(int i=0;i<20;i++)
      cb_arr[i]=IntegerToString(i+1);
   if(!CreateComboBox("",cb_arr,100,100,100,20,m_cb))
      return false;
   if(!CreateButton("Action",100,130,50,20,m_btn))
      return false;

// ウィンドウを表示する
   CWndEvents::CompletedGUI();
   return true;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void CWindowManager::Btn_Click(int id,long lparam)
  {
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_btn.Id())
     {
      CArrayString s;
      s.Add("new value");
      setCombobox(&m_cb,s);
     }
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void CWindowManager::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   Btn_Click(id,lparam);
  }
//+------------------------------------------------------------------+



今のところ、私が見つけたすべての解決策は、ライブラリーのコードを編集する(新たに3行のコードを追加する)ことに行き着くのですが、他人のコードをいじるという考えは好きではありません...。

 
Andrey Azatskiy:
私の質問に対する最低限の再現可能なコード:

...

今のところ、私が見つけたすべての解決策は、ライブラリのコードを編集する(新しい3行のコードを追加する)ことに行き着くのですが、他人のコードをいじるという考えは好きではありません...。

メッセージをありがとう。

CListView クラスのメソッドに ちょっとした追加をしてみてください。以下の ように、補助フィールドをゼロにする必要があります:

//+------------------------------------------------------------------+
//| リストをクリア(全項目を削除)する。
//+------------------------------------------------------------------+
void CListView::Clear(const bool redraw=false)
  {
//--- 補助フィールドをゼロにリセットする
   m_item_index_focus      =WRONG_VALUE;
   m_prev_selected_item    =WRONG_VALUE;
   m_prev_item_index_focus =WRONG_VALUE;
//--- サイズをゼロに設定する
   ListSize(0);
//--- 新しいリストサイズを計算し、設定する
   RecalculateAndResizeList(redraw);
  }
 
Anatoli Kazharski:

メッセージをありがとう。

CListView クラスのメソッドに ちょっとした追加をしてみてください。以下の ように補助フィールドをゼロにする必要があります:

ご返信ありがとうございます。

 
Anatoli Kazharski:

bitbucketにリポジトリを作って、アクティブなライブラリユーザーからのコミットを受け入れるのはどうだろう?

一緒に早く完成させましょう ;)

 

ウィンドウを閉じるボタンを正しく処理する方法を教えてください。

ExpertAdvisor(例えばExampleEAF.ex5)とインジケータをチャートの下の別のウィンドウに置いています(最小限のコードでは空のウィンドウしか表示されません)。そして、これらのアプリケーションのウィンドウを閉じるボタンをクリックすると、両方とも閉じられます(チャートから削除されます)。

これは正しい動作ではありません。同じチャート上で同時に動作している異なるアプリケーションのイベントを区別する方法はありますか?他のイベントも重なっている疑いがあります。

 
Andrey Khatimlianskii:

bitbucketにリポジトリを作り、アクティブなライブラリーユーザーからのコミットを受け入れるというのはどうだろう?

一緒に早く完成させましょう ;)

私はすでにアクセス権を与えられています。私は多くの編集に疑問を持っています。

これらやこれらの変更には正当な理由がありません。ここのフォーラムで議論する方が簡単だ。

もし何か変更を加えるのであれば、例やテスト結果を示し、なぜそれがより良くなるのかを説明する必要がある。

 
dmyger:

ウィンドウを閉じるボタンを正しく処理する方法を教えてください。

ExpertAdvisor(例えばExampleEAF.ex5)とインジケータをチャートの下の別のウィンドウに置いています(最小限のコードでは空のウィンドウしか表示されません)。その後、これらのアプリケーションのウィンドウを閉じるボタンをクリックすると、両方とも閉じられます(チャートから削除されます)。

これは正しい動作ではありません。同じチャート上で同時に動作している異なるアプリケーションのイベントを区別する方法はありますか?他のイベントも重なっているのではないかと思います。

時間があるときにテストして、結果をここに報告します。

 

Andrey Khatimlianskii:

Как на счет репозитория на битбакете и принятия коммитов от активных пользователей библиотеки?

Вместе быстрее допилим ;)

アナトリ・カザルスキー

...

もし何か変更を加えるのであれば、例とテスト結果を示し、なぜそれがより良いのかを説明する必要がある。

少なくとも簡潔に。例えば

CListView クラスの修正。Clear()メソッドでは、クラスの他のメソッドが配列の 外に出ないように、いくつかの補助フィールドをゼロにする必要がある。