
グラフィカルインタフェースVII: タブコントロール(チャプター2)
コンテンツ
はじめに
シリーズ初めのグラフィカルインタフェース I: ライブラリストラクチャの準備(チャプター 1)稿ではライブラリの目的が詳細に考察されました。記事へのリンクの完全なリストは各章の末尾でみられます。そこではまた、開発の現段階でのライブラリの完全版をダウンロードすることができます。ファイルはアーカイブと同じディレクトリに配置される必要があります。
第七部の最初の章では、テーブルを作成するためのコントロールであるテキストラベルテーブル(CLabelsTable)、エディットボックステーブル(CTable))およびレンダーテーブル(CCanvasTable)の3つのクラスが紹介されました。本稿(チャプター2)ではタブコントロールが考察されます。このコントロールのためには、シンプルなクラスと拡張された機能を持つクラスの2つが提示されます。
タブコントロール
タブは、グラフィカルインターフェースコントロールの事前定義されたセットの表示の制御に使用されます。多機能アプリケーションでは、多くの場合、大量のコントロールをグラフィカルインターフェースのために割り当てられた限られたスペースに収めることが必要となります。タブは、カテゴリによってコントロールをグループ分けして現在必要なグループのみを表示するのを可能にします。これによって、エンドユーザーにとって、インターフェイスがはるかにアクセスしやすくより直感的になります。表面上では、タブは、ラベル(コントロールグループの名前)を持つボタンのグループのように見えます。同時に、1つのみの選択(アクティブ)が可能です。
このコントロールのすべての構成要素を列挙してみましょう。
- コントロールのグループに合わせた背景またはエリア
- タブ
図1。タブコントロールのの複合部分
他のコントロールが配置される領域に相対してタブを配置する上、下、左、右の4つのモードを作成してみましょう。
タブコントロール作成クラスの開発
Tabs.mqhファイルを作成してライブラリのWndContainer.mqhファイルに含みます。
//+------------------------------------------------------------------+ //| WndContainer.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "Tabs.mqh"
CTabsはTabs.mqhファイルに作成されなければなりません。他のコントロールのクラスでもそうですが、このクラスでは、標準的なメソッドの作成に加えて、このコントロールが添付されるフォームへのポインタを格納するためのメソッドの作成が必要です。
//+------------------------------------------------------------------+ //| タブ作成クラス | //+------------------------------------------------------------------+ class CTabs : public CElement { private: //--- 要素が取り付けられるフォームへのポインタ CWindow *m_wnd; //--- public: CTabs(void); ~CTabs(void); //--- (1) フォームポインタを格納し (2) スクロールバーポインタを返す void WindowPointer(CWindow &object) { m_wnd=::GetPointer(object); } //--- public: //--- チャートイベントハンドラ virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- タイマー virtual void OnEventTimer(void); //--- 要素の移動 virtual void Moving(const int x,const int y); //--- (1)表示 (2)非表示 (3)リセット (4)削除 virtual void Show(void); virtual void Hide(void); virtual void Reset(void); virtual void Delete(void); //--- マウスの左クリックの優先順位の(1)設定と(2)リセット virtual void SetZorders(void); virtual void ResetZorders(void); //--- 色をリセットする virtual void ResetColors(void) {} }; //+------------------------------------------------------------------+ //| コンストラクタ | //+------------------------------------------------------------------+ CTabs::CTabs(void) { } //+------------------------------------------------------------------+ //| デストラクタ | //+------------------------------------------------------------------+ CTabs::~CTabs(void) { }
タブのプロパティは、ユニークなものと一般的なものに分けることができます。両方のリストを作ってみましょう。
ユニークなプロパティ
- タブに接続されているコントロールへのポインタの配列
- テキスト
- 幅
ユニークなプロパティのためにはTElements構造体を作成してこの型の動的配列を宣言します。
class CTabs : public CElement { private: //--- プロパティの構造体とコントロールの配列は各タブに取り付けられる struct TElements { CElement *elements[]; string m_text; int m_width; }; TElements m_tab[]; };
共通プロパティ
- タブの整列モード
- エリアの背景色
- Y軸に沿ったタブのサイズ(高さ)
- 異なる状態にあるタブの色
- 異なる状態にあるタブのテキストの色
- タブの境界線の色
- マウスの左クリックの優先順位
整列モードを設定するにはENUM_TABS_POSITION列挙がEnums.mqhファイルに追加される必要があります。
//+------------------------------------------------------------------+ //| タブ整列の列挙 | //+------------------------------------------------------------------+ enum ENUM_TABS_POSITION { TABS_TOP =0, TABS_BOTTOM =1, TABS_LEFT =2, TABS_RIGHT =3 };
フィールドの宣言とプロパティを設定するためのメソッドは以下のコードで提供されています。
class CTabs : public CElement { private: //--- タブの整列 ENUM_TABS_POSITION m_position_mode; //--- 共通エリアの背景色 int m_area_color; //--- Y軸に沿ったタブのサイズ int m_tab_y_size; //--- 異なる状態にあるタブの色 color m_tab_color; color m_tab_color_hover; color m_tab_color_selected; color m_tab_color_array[]; //--- 異なる状態にあるタブのテキストの色 color m_tab_text_color; color m_tab_text_color_selected; //--- タブの境界線の色 color m_tab_border_color; //--- マウスの左クリックの優先順位 int m_zorder; int m_tab_zorder; //--- public: //--- (1) タブポジションを設定する(上下左右)(2) Y軸に沿ったタブのサイズを設定する void PositionMode(const ENUM_TABS_POSITION mode) { m_position_mode=mode; } ENUM_TABS_POSITION PositionMode(void) const { return(m_position_mode); } void TabYSize(const int y_size) { m_tab_y_size=y_size; } //--- (1) 共通の背景の色 (2) 異なる状態でのタブの色 (3)タブの境界の色 void AreaColor(const color clr) { m_area_color=clr; } void TabBackColor(const color clr) { m_tab_color=clr; } void TabBackColorHover(const color clr) { m_tab_color_hover=clr; } void TabBackColorSelected(const color clr) { m_tab_color_selected=clr; } void TabBorderColor(const color clr) { m_tab_border_color=clr; } //--- 異なる状態にあるタブのテキストの色 void TabTextColor(const color clr) { m_tab_text_color=clr; } void TabTextColorSelected(const color clr) { m_tab_text_color_selected=clr; } };
コントロールを作成する前に、表示されるテキストと幅を表示するのに必要な数のタブを追加する必要があります。このためにCTabs::AddTab() メソッドを書きましょう。メソッドの引数のデフォルト値は«»(空の文字列)と 50(幅)です。
class CTabs : public CElement { public: //--- タブを加える void AddTab(const string tab_text="",const int tab_width=50); }; //+------------------------------------------------------------------+ //| タブを加える | //+------------------------------------------------------------------+ void CTabs::AddTab(const string tab_text,const int tab_width) { //--- タブ配列のサイズを設定する int array_size=::ArraySize(m_tabs); ::ArrayResize(m_tabs,array_size+1); ::ArrayResize(m_tab,array_size+1); //--- 受け渡されたプロパティを格納する m_tab[array_size].m_text =tab_text; m_tab[array_size].m_width =tab_width; //--- タブの数を格納する m_tabs_total=array_size+1; }
チャートにMQLアプリケーションが読み込まれる際に事前に特定のタブが選択されなければならない場合は、コントロールを作成する前に CTabs::SelectedTab()メソッドを使用してそのインデックスを指定する必要があります。また、選択されたタブのインデックスが範囲を超えた場合に調整するための CTabs::CheckTabIndex() メソッドが必要になります。
class CTabs : public CElement { private: //--- 選択されたタブのインデックス int m_selected_tab; //--- public: //--- 選択されたタブを (1) 格納して (2) そのインデックスを返す void SelectedTab(const int index) { m_selected_tab=index; } int SelectedTab(void) const { return(m_selected_tab); } //--- private: //--- 選択されたタブのインデックスを確認する void CheckTabIndex(void); }; //+------------------------------------------------------------------+ //| 選択されたタブのインデックスを確認する | //+------------------------------------------------------------------+ void CTabs::CheckTabIndex(void) { //--- 配列サイズの超過を確認する int array_size=::ArraySize(m_tab); if(m_selected_tab<0) m_selected_tab=0; if(m_selected_tab>=array_size) m_selected_tab=array_size-1; }
コントロールの作成には3つのプライベートメソッドと1つのパブリックメソッドが必要です。
class CTabs : public CElement { private: //--- 要素作成オブジェクト CRectLabel m_main_area; CRectLabel m_tabs_area; CEdit m_tabs[]; //--- public: //--- タブ作成メソッド bool CreateTabs(const long chart_id,const int subwin,const int x,const int y); //--- private: bool CreateMainArea(void); bool CreateTabsArea(void); bool CreateButtons(void); };
コントロールが取り付けられる前にタブが追加されていない場合、CTabs::CreateTabs() パブリックメソッドの呼び出しはグラフィカルインターフェイスの作成を停止して次のメッセージをログに出力します。
//--- グループにタブがない場合は報告する if(m_tabs_total<1) { ::Print(__FUNCTION__," > This method is to be called, " "if a group contains at least one tab!Use the CTabs::AddTab() method"); return(false); }
コントロールのコンポーネントオブジェクトの座標の決意と計算も選択されたタブの整列モードによって異なります。これらの計算にはCTabs::SumWidthTabs() メソッドが必要で、それはすべてのタブの幅の合計を返します。左(TABS_LEFT)と右(TABS_RIGHT)タブ整列モードでは、1番目のタブの幅が返されます。上(TABS_TOP)と下(TABS_BOTTOM)モードでは、すべてのタブの幅が加算されます。
class CTabs : public CElement { private: //--- タブの整列 ENUM_TABS_POSITION m_position_mode; //--- private: //--- すべてのタブの幅 int SumWidthTabs(void); }; //+------------------------------------------------------------------+ //| すべてのタブの幅の合計 | //+------------------------------------------------------------------+ int CTabs::SumWidthTabs(void) { int width=0; //--- タブが右か左に整列されている場合、1番目のタブの幅を返す if(m_position_mode==TABS_LEFT || m_position_mode==TABS_RIGHT) return(m_tab[0].m_width); //--- すべてのタブの幅を加算する for(int i=0; i<m_tabs_total; i++) width=width+m_tab[i].m_width; //--- 1画素オーバーレイを考慮 width=width-(m_tabs_total-1); return(width); }
CTabs::CreateMainArea() メソッドは、コントロールのグループが配置される領域を作成するために設計されています。座標とオブジェクトサイズの計算は下記の通りです(メソッドの短縮版)。
//+------------------------------------------------------------------+ //| 共通エリアの背景色を作成する | //+------------------------------------------------------------------+ bool CTabs::CreateMainArea(void) { //--- オブジェクト名の形成 string name=CElement::ProgramName()+"_tabs_main_area_"+(string)CElement::Id(); //--- 座標 int x=0; int y=0; //--- サイズ int x_size=0; int y_size=0; //--- タブの位置に相対した座標とサイズの計算 switch(m_position_mode) { case TABS_TOP : x =CElement::X(); y =CElement::Y()+m_tab_y_size-1; x_size =CElement::XSize(); y_size =CElement::YSize()-m_tab_y_size; break; case TABS_BOTTOM : x =CElement::X(); y =CElement::Y(); x_size =CElement::XSize(); y_size =CElement::YSize()-m_tab_y_size; break; case TABS_RIGHT : x =CElement::X(); y =CElement::Y(); x_size =CElement::XSize()-SumWidthTabs()+1; y_size =CElement::YSize(); break; case TABS_LEFT : x =CElement::X()+SumWidthTabs()-1; y =CElement::Y(); x_size =CElement::XSize()-SumWidthTabs()+1; y_size =CElement::YSize(); break; } //--- オブジェクトの作成 if(!m_main_area.Create(m_chart_id,name,m_subwin,x,y,x_size,y_size)) return(false); //--- プロパティの設定 //--- 端からのマージン //--- サイズを格納する //--- 座標を格納する //--- オブジェクトポインタを格納する //... return(true); }
以下は CTabs::CreateTabsArea() メソッドで指定された整列モードに応じたタブの座標と背景のサイズの計算です。
//+------------------------------------------------------------------+ //| タブの背景を作成する | //+------------------------------------------------------------------+ bool CTabs::CreateTabsArea(void) { //--- オブジェクト名の形成 string name=CElement::ProgramName()+"_tabs_area_"+(string)CElement::Id(); //--- 座標 int x=CElement::X(); int y=CElement::Y(); //--- サイズ int x_size=SumWidthTabs(); int y_size=0; //--- タブの位置に相対したサイズの計算 if(m_position_mode==TABS_TOP || m_position_mode==TABS_BOTTOM) { y_size=m_tab_y_size; } else { y_size=m_tab_y_size*m_tabs_total-(m_tabs_total-1); } //--- タブを下と右で位置決めするために座標を調整する if(m_position_mode==TABS_BOTTOM) { y=CElement::Y2()-m_tab_y_size-1; } else if(m_position_mode==TABS_RIGHT) { x=CElement::X2()-x_size; } //--- オブジェクトの作成 if(!m_tabs_area.Create(m_chart_id,name,m_subwin,x,y,x_size,y_size)) return(false); //--- プロパティの設定 //--- 端からのマージン //--- サイズを格納する //--- 座標を格納する //--- オブジェクトポインタを格納する //... return(true); }
CTabs::CreateButtons() メソッドはタブの作成に座標の計算のみを必要にします。幅はコントロールが作成される前にアプリケーションのカスタムクラスで設定されています。そうでない場合は、デフォルト値(幅)が使用されます。下記はメソッドの短縮版です。
//+------------------------------------------------------------------+ //| タブを作成する | //+------------------------------------------------------------------+ bool CTabs::CreateButtons(void) { //--- 座標 int x =CElement::X(); int y =CElement::Y(); //--- タブの位置に相対した座標の計算 if(m_position_mode==TABS_BOTTOM) y=CElement::Y2()-m_tab_y_size-1; else if(m_position_mode==TABS_RIGHT) x=CElement::X2()-SumWidthTabs(); //--- 選択されたタブのインデックスを確認する CheckTabIndex(); //--- タブを作成する for(int i=0; i<m_tabs_total; i++) { //--- オブジェクト名の形成 string name=CElement::ProgramName()+"_tabs_edit_"+(string)i+"__"+(string)CElement::Id(); //--- 個々のタブでのタブの位置に相対した座標計算 if(m_position_mode==TABS_TOP || m_position_mode==TABS_BOTTOM) x=(i>0) ?x+m_tab[i-1].m_width-1 : CElement::X(); else y=(i>0) ?y+m_tab_y_size-1 : CElement::Y(); //--- オブジェクトの作成 if(!m_tabs[i].Create(m_chart_id,name,m_subwin,x,y,m_tab[i].m_width,m_tab_y_size)) return(false); //--- プロパティの設定 //--- パネルの端からのマージン //--- 座標 //--- サイズ //--- グラデーション配列を初期化する //--- オブジェクトポインタを格納する } //--- return(true); }
特定のタブに任意のコントロールを接続するためにCTabs::AddToElementsArray() メソッドを書きましょう。これには (1) コントロールが取り付けられるタブのインデックスと (2) ポインタがタブコントロールの配列に格納されるコントロールへの参照 の2つの引数があります。
class CTabs : public CElement { public: //--- コントロールをタブ配列に追加する void AddToElementsArray(const int tab_index,CElement &object); }; //+------------------------------------------------------------------+ //| コントロールを指定されたタブの配列に追加する | //+------------------------------------------------------------------+ void CTabs::AddToElementsArray(const int tab_index,CElement &object) { //--- 配列サイズの超過を確認する int array_size=::ArraySize(m_tab); if(array_size<1 || tab_index<0 || tab_index>=array_size) return; //--- 受け渡されたコントロールへのポインタを指定されたタブの配列に追加する int size=::ArraySize(m_tab[tab_index].elements); ::ArrayResize(m_tab[tab_index].elements,size+1); m_tab[tab_index].elements[size]=::GetPointer(object); }
タブを切り替えるときは、1つ前のタブのコントロールを非表示にし、新たに選択されたタブのコントロールを表示する必要があります。このためにCTabs::ShowTabElements() メソッドを作成しましょう。コントロールの可視性のチェックは、メソッドの先頭にあります。コントロールが表示されていない場合、プログラムはメソッドを終了します。次に、アクティブなタブのインデックスを確認し、必要であれば、それを調整します。そして、ループ内ですべてのタブをチェックしてメソッドの主なタスクを実行します。
class CTabs : public CElement { public: //--- 選択されたタブのコントロールのみを表示する void ShowTabElements(void); }; //+------------------------------------------------------------------+ //| 選択されたタブのコントロールのみを表示する | //+------------------------------------------------------------------+ void CTabs::ShowTabElements(void) { //--- タブが非表示の場合は終了する if(!CElement::IsVisible()) return; //--- 選択されたタブのインデックスを確認する CheckTabIndex(); //--- for(int i=0; i<m_tabs_total; i++) { //--- タブに取りつけられているコントロールの数を取得する int tab_elements_total=::ArraySize(m_tab[i].elements); //--- このタブが選択された場合 if(i==m_selected_tab) { //--- タブコントロールを表示する for(int j=0; j<tab_elements_total; j++) m_tab[i].elements[j].Show(); } //--- アクティブでないタブのコントロールを隠す else { for(int j=0; j<tab_elements_total; j++) m_tab[i].elements[j].Hide(); } } }
CTabs::OnClickTab() メソッドはタブ押下の処理に使用されます。プログラムは初めに(1) 押下されたオブジェクトの名前に基づいた条件 (2) CTabs::IdFromObjectName()メソッドを使ってオブジェクト名から取得されたコントロールの識別子に基づいた条件の2つの条件を満たす必要があります。条件が満たされた場合、プログラムは(1)ループで押下されたタブを見つけ(2)そのインデックスを格納し(3)対応する色を設定します。CTabs::ShowTabElements() メソッドの一番最後では、アクティブなタブのコントロールのみが表示されるようになります。
class CTabs : public CElement { private: //--- タブの押下の処理 bool OnClickTab(const string pressed_object); //--- オブジェクト名から識別子を取得する | int IdFromObjectName(const string object_name); }; //+------------------------------------------------------------------+ //| グループでのタブの押下 | //+------------------------------------------------------------------+ bool CTabs::OnClickTab(const string clicked_object) { //--- 押されたのがテーブルセルでなかった場合は終了する if(::StringFind(clicked_object,CElement::ProgramName()+"_tabs_edit_",0)<0) return(false); //--- オブジェクト名から識別子を取得する | int id=IdFromObjectName(clicked_object); //--- 識別子が一致しない場合は終了する if(id!=CElement::Id()) return(false); //--- for(int i=0; i<m_tabs_total; i++) { //--- このタブがクリックされた場合 if(m_tabs[i].Name()==clicked_object) { //--- 選択されたタブのインデックスを格納する SelectedTab(i); //--- 色を設定する m_tabs[i].Color(m_tab_text_color_selected); m_tabs[i].BackColor(m_tab_color_selected); } else { //--- アクティブでないタブの色を設定する m_tabs[i].Color(m_tab_text_color); m_tabs[i].BackColor(m_tab_color); } } //--- 選択されたタブのコントロールのみを表示する ShowTabElements(); return(true); }
この場合のCTabs::OnEvent() メインイベントハンドラのコードは下記のとおりです。
//+------------------------------------------------------------------+ //| チャートイベントハンドラ | //+------------------------------------------------------------------+ void CTabs::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- カーソル移動イベントの処理 if(id==CHARTEVENT_MOUSE_MOVE) { //--- 要素が隠れている場合は終了する if(!CElement::IsVisible()) return; //--- 座標 int x=(int)lparam; int y=(int)dparam; for(int i=0; i<m_tabs_total; i++) m_tabs[i].MouseFocus(x>m_tabs[i].X() && x<m_tabs[i].X2() && y>m_tabs[i].Y() && y<m_tabs[i].Y2()); //--- return; } //--- オブジェクトのマウス左クリックイベントの処理 if(id==CHARTEVENT_OBJECT_CLICK) { //--- タブの押下 if(OnClickTab(sparam)) return; } }
CTabsクラスのメソッドはすべて考察されました。その動作を検証してみましょう。
タブコントロールの検証
検証のためには、シリーズの前の部分で使われたEAを使用し、そのグラフィカルインターフェースからメインメニューとステータスバー以外のすべてを削除しましょう。すべてのタブ整列モード(上/下/左/右)ならびにそれらのサイズ(高さ)を調整しやすくしましょう。この目的のためには、カスタムクラスを持ったProgram.mqh でEAに 外部パラメータを追加します。
//--- エキスパートアドバイザーの外部パラメータ input ENUM_TABS_POSITION TabsPosition =TABS_TOP; // タブの位置 input int TabsHeight =20; // タブの高さ
次に、アプリケーションのカスタムクラス(CProgram)で、CTabsクラスのインスタンスと、フォームの端からインデントされたタブコントロールを作成するメソッドを宣言します。
class CProgram : public CWndEvents { private: //--- タブ CTabs m_tabs; //--- private: //--- タブ #define TABS1_GAP_X (4) #define TABS1_GAP_Y (45) bool CreateTabs(void); };
タブは全部で4つあります。表示されたテキストとタブの幅は配列の初期化で調整可能で、その要素値はCTabs::AddTab() メソッドを使ってループに受け渡されます。タブの高さと位置は外部パラメータで設定されます。デフォルトでは2番目のタブ(インデックス1)が選択されます(プログラムがチャートに読み込まれるとき)。CProgram::CreateTabs() メソッドの完全なコードは下に見られます。
//+------------------------------------------------------------------+ //| タブのある領域を作成する | //+------------------------------------------------------------------+ bool CProgram::CreateTabs(void) { #define TABS1_TOTAL 4 //--- パネルオブジェクトを受け渡す m_tabs.WindowPointer(m_window1); //--- 座標 int x=m_window1.X()+TABS1_GAP_X; int y=m_window1.Y()+TABS1_GAP_Y; //--- タブのテキストと幅を持った配列 string tabs_text[]={"Tab 1","Tab 2","Tab 3","Tab 4"}; int tabs_width[]={90,90,90,90}; //--- 作成前にプロパティを設定する m_tabs.XSize(596); m_tabs.YSize(243); m_tabs.TabYSize(TabsHeight); m_tabs.PositionMode(TabsPosition); m_tabs.SelectedTab((m_tabs.SelectedTab()==WRONG_VALUE) ?1 : m_tabs.SelectedTab()); m_tabs.AreaColor(clrWhite); m_tabs.TabBackColor(C'225,225,225'); m_tabs.TabBackColorHover(C'240,240,240'); m_tabs.TabBackColorSelected(clrWhite); m_tabs.TabBorderColor(clrSilver); m_tabs.TabTextColor(clrGray); m_tabs.TabTextColorSelected(clrBlack); //--- 指定されたプロパティを持つタブを追加する for(int i=0; i<TABS1_TOTAL; i++) m_tabs.AddTab(tabs_text[i],tabs_width[i]); //--- コントロールを作成する if(!m_tabs.CreateTabs(m_chart_id,m_subwin,x,y)) return(false); //--- オブジェクトをオブジェクトグループの共通配列に追加する CWndContainer::AddToElementsArray(0,m_tabs); return(true); }
メソッドは、アプリケーションのグラフィカルインターフェース(以下のメソッドの短縮版を参照)を作成するためのメインメソッドで呼び出される必要があります。
//+------------------------------------------------------------------+ //| エキスパートパネルを作成する | //+------------------------------------------------------------------+ bool CProgram::CreateExpertPanel(void) { //--- コントロールのフォーム1 の作成 //--- コントロールの作成 // メインメニュー //--- コンテキストメニュー //--- タブ if(!CreateTabs()) return(false); //--- チャートの再描画 m_chart.Redraw(); return(true); }
コードをコンパイルしてプログラムをチャートに読み込みます。タブの整列モードは外部パラメータで連続的に変化されます(下のスクリーンショットを参照)。
図2。タブ整列モード — «上».
図3。タブ整列モード — «下»
図4。タブ整列モード — — «左»
図5。タブ整列モード — — «右»
ここで、各タブに接続されているコントロールのグループがどのように機能するかを検証してみましょう。これを行うには、同じEAの別のコピーを作成し、そこから外部パラメータを削除します。ここでは、タブはワークスペースの最上部(TABS_TOP)に置かれます。
- テキストラベルテーブルは最初のタブに取り付けられます。
- エディットボックステーブルは2番目のものに取り付けられます。
- 3番目はレンダーテーブルです。
- 4番目には下記を含むコントロールのグループが取り付けられます。
- 4つのチェックボックス
- 4つのエディットボックス付きのチェックボックス
- 4つのチェックボックス付きのコンボボックス
- 1本の区切り線
テストアプリケーションのカスタムクラス(CProgram)で (1) コントロールのインスタンス(2) それらの作成メソッド (3) フォームの端からのマージンを宣言します(下のコードを参照)。
class CProgram : public CWndEvents { private: //--- テキストラベルテーブル CLabelsTable m_labels_table; //--- エディットボックステーブル CTable m_table; //--- レンダーテーブル CCanvasTable m_canvas_table; //--- チェックボックス CCheckBox m_checkbox1; CCheckBox m_checkbox2; CCheckBox m_checkbox3; CCheckBox m_checkbox4; //--- エディットボックス付きのチェックボックス CCheckBoxEdit m_checkboxedit1; CCheckBoxEdit m_checkboxedit2; CCheckBoxEdit m_checkboxedit3; CCheckBoxEdit m_checkboxedit4; //--- チェックボックス付きのコンボボックス CCheckComboBox m_checkcombobox1; CCheckComboBox m_checkcombobox2; CCheckComboBox m_checkcombobox3; CCheckComboBox m_checkcombobox4; //--- 区切り線 CSeparateLine m_sep_line; //--- private: //--- テキストラベルテーブル #define TABLE1_GAP_X (5) #define TABLE1_GAP_Y (65) bool CreateLabelsTable(void); //--- エディットボックステーブル #define TABLE2_GAP_X (5) #define TABLE2_GAP_Y (65) bool CreateTable(void); //--- レンダーテーブル #define TABLE3_GAP_X (5) #define TABLE3_GAP_Y (65) bool CreateCanvasTable(void); //--- 区切り線 #define SEP_LINE_GAP_X (300) #define SEP_LINE_GAP_Y (70) bool CreateSepLine(void); //--- チェックボックス #define CHECKBOX1_GAP_X (18) #define CHECKBOX1_GAP_Y (75) bool CreateCheckBox1(const string text); #define CHECKBOX2_GAP_X (18) #define CHECKBOX2_GAP_Y (175) bool CreateCheckBox2(const string text); #define CHECKBOX3_GAP_X (315) #define CHECKBOX3_GAP_Y (75) bool CreateCheckBox3(const string text); #define CHECKBOX4_GAP_X (315) #define CHECKBOX4_GAP_Y (175) bool CreateCheckBox4(const string text); //--- エディットボックス付きのチェックボックス #define CHECKBOXEDIT1_GAP_X (40) #define CHECKBOXEDIT1_GAP_Y (105) bool CreateCheckBoxEdit1(const string text); #define CHECKBOXEDIT2_GAP_X (40) #define CHECKBOXEDIT2_GAP_Y (135) bool CreateCheckBoxEdit2(const string text); #define CHECKBOXEDIT3_GAP_X (337) #define CHECKBOXEDIT3_GAP_Y (105) bool CreateCheckBoxEdit3(const string text); #define CHECKBOXEDIT4_GAP_X (337) #define CHECKBOXEDIT4_GAP_Y (135) bool CreateCheckBoxEdit4(const string text); //--- チェックボックス付きのコンボボックス #define CHECKCOMBOBOX1_GAP_X (40) #define CHECKCOMBOBOX1_GAP_Y (205) bool CreateCheckComboBox1(const string text); #define CHECKCOMBOBOX2_GAP_X (40) #define CHECKCOMBOBOX2_GAP_Y (235) bool CreateCheckComboBox2(const string text); #define CHECKCOMBOBOX3_GAP_X (337) #define CHECKCOMBOBOX3_GAP_Y (205) bool CreateCheckComboBox3(const string text); #define CHECKCOMBOBOX4_GAP_X (337) #define CHECKCOMBOBOX4_GAP_Y (235) bool CreateCheckComboBox4(const string text); };
以前の記事では、コントロールを作成してフォームに取り付ける方法が繰り返して示されました。したがって、タブにコントロールを取り付ける方法を示すために、ここではこれらの方法のうち1つだけのコードが表示されます。例としてはこれらのコントロールのうちで最も単純な区切り線が十分でしょう。下記のコードではCTabs::AddToElementsArray() メソッドを呼び出す行が黄色で強調表示されています。1番目の引数はコントロールが取り付けられるべきタブのインデックスです。ここではインデックスは3で、つまりタブは4番目のものです。2番目の引数は、指定したタブに取り付けられなければならないコントロールのオブジェクトです。
//+------------------------------------------------------------------+ //| 区切り線を作成する | //+------------------------------------------------------------------+ bool CProgram::CreateSepLine(void) { //--- ウィンドウポインタを格納する m_sep_line.WindowPointer(m_window1); //--- 1番目のタブグループの4番目のタブに取り付ける m_tabs.AddToElementsArray(3,m_sep_line); //--- 座標 int x=m_window1.X()+SEP_LINE_GAP_X; int y=m_window1.Y()+SEP_LINE_GAP_Y; //--- サイズ int x_size=2; int y_size=210; //--- 作成前にプロパティを設定する m_sep_line.DarkColor(C'213,223,229'); m_sep_line.LightColor(clrWhite); m_sep_line.TypeSepLine(V_SEP_LINE); //--- 要素の作成 if(!m_sep_line.CreateSeparateLine(m_chart_id,m_subwin,0,x,y,x_size,y_size)) return(false); //--- 要素ポインタをベースに追加する CWndContainer::AddToElementsArray(0,m_sep_line); return(true); }
アプリケーションのグラフィカルインターフェースが作成された後は、アクティブなタブのコントロールのみを表示するためにCTabs::ShowTabElements() メソッドが呼ばれなければなりません(下記の短縮版を参照)。それが行われていない場合は、すべてのタブのすべてのコントロールが表示されます。
//+------------------------------------------------------------------+ //| エキスパートパネルを作成する | //+------------------------------------------------------------------+ bool CProgram::CreateExpertPanel(void) { //--- コントロールのフォーム1 の作成 //--- コントロールの作成 //--- メインメニュー //--- コンテキストメニュー //--- ステータスバー //--- タブ //... //--- テキストラベルテーブル if(!CreateLabelsTable()) return(false); //--- エディットボックステーブル if(!CreateTable()) return(false); //--- レンダーテーブルを作成する if(!CreateCanvasTable()) return(false); //--- 区切り線 if(!CreateSepLine()) return(false); //--- チェックボックス if(!CreateCheckBox1("Checkbox 1")) return(false); if(!CreateCheckBox2("Checkbox 2")) return(false); if(!CreateCheckBox3("Checkbox 3")) return(false); if(!CreateCheckBox4("Checkbox 4")) return(false); //--- エディットボックス付きのチェックボックス if(!CreateCheckBoxEdit1("Checkbox Edit 1:")) return(false); if(!CreateCheckBoxEdit2("Checkbox Edit 2:")) return(false); if(!CreateCheckBoxEdit3("Checkbox Edit 3:")) return(false); if(!CreateCheckBoxEdit4("Checkbox Edit 4:")) return(false); //--- チェックボックス付きのコンボボックス if(!CreateCheckComboBox1("CheckCombobox 1:")) return(false); if(!CreateCheckComboBox2("CheckCombobox 2:")) return(false); if(!CreateCheckComboBox3("CheckCombobox 3:")) return(false); if(!CreateCheckComboBox4("CheckCombobox 4:")) return(false); //--- アクティブなタブのコントロールのみを表示する m_tabs.ShowTabElements(); //--- チャートの再描画 m_chart.Redraw(); return(true); }
結果は以下のスクリーンショットのようなはずです。
図6。1番目のタブのコントロール
図7。2番目のタブのコントロール
図8 3番目のタブのコントロール
図9 4番目のタブのコントロール
すべてが設計どおり動作します。グラフィカルインタフェースを作成するためのライブラリに捧げられた本シリーズの第七部はこれでしめることができます。補足として、本稿の添付ファイルに提供されている拡張機能を持つタブを作成するあと1つのクラスのコード(CIconTabs)のダウンロードが可能です。CTabsクラスと違ってCIconTabs型のコントロールでは各タブに調整可能なアイコンがあります。これによって、必要に応じてグラフィカルインターフェースをよりユーザーフレンドリーにすることができます。
アイコンと表示されたテキストは、特別なメソッドを用いて正確に各タブの端に相対して配置することができます(コードは以下を参照)。
//+------------------------------------------------------------------+ //| アイコンタブ作成クラス | //+------------------------------------------------------------------+ class CIconTabs : public CElement { private: //--- ラベルの余白 int m_icon_x_gap; int m_icon_y_gap; //--- テキストラベルのマージン int m_label_x_gap; int m_label_y_gap; //--- public: //--- ラベルの余白 void IconXGap(const int x_gap) { m_icon_x_gap=x_gap; } void IconYGap(const int y_gap) { m_icon_y_gap=y_gap; } //--- テキストラベルのマージン void LabelXGap(const int x_gap) { m_label_x_gap=x_gap; } void LabelYGap(const int y_gap) { m_label_y_gap=y_gap; } };
アイコンタブコントロールの外観の一例は以下のスクリーンショットに表示されています。
図10 アイコンタブコントロール
このエキスパートのコードも本稿の添付ファイルからダウンロードできます。
おわりに
グラフィカルインタフェースを作成するためのライブラリーの概略は現在以下の通りに見えます。
図11 開発の現段階でのライブラリの構造
テーブルとタブコントロールはMetaTrader取引プラットフォームでのグラフィカルインターフェースの作成についてのシリーズの第七部で考察されました。テーブル作成には3つのクラス(CLabelsTable、CTable、CCanvasTable)、タブ作成には2つのクラス(CTabsとCIconTabs)が提供されました。
シリーズの次の部分(第八部)は下記のコントロールを考察します。
- 静的なドロップダウンカレンダー
- ツリービュー
- ファイルナビゲータ
シリーズ第七部の資料はすべてファイルからダウンロードして動作を検証することができます。これらのファイルに含まれている資料の使用についてご質問がある場合は、以下のリストにある記事のいずれかでライブラリの開発の詳細をご参照になるか、本稿へのコメント欄でご質問ください。
第七部の記事(チャプター)のリストは下記の通りです。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/2503





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