
グラフィカルインタフェースVI:スライダーとデュアルスライダーコントロール(チャプター 2)
コンテンツ
はじめに
シリーズ第一弾のグラフィカルインタフェース I: ライブラリストラクチャの準備(チャプター 1)ではライブラリの目的を詳細に考察します。記事へのリンクの完全なリストは各章の末尾でみられます。そこではまた、開発の現段階でのライブラリの完全版をダウンロードすることができます。ファイルはアーカイブと同じディレクトリに配置される必要があります。
前回の記事では、チェックボックス、編集コントロールやチェックボックスやコンボボックスを持つ編集コントロールの4つの頻繁にグラフィカルインタフェースで使用されるコントロールでライブラリを改良しました。第六部の第2章は、スライダーとデュアルスライダーコントロールに専念されます。 .
スライダーコントロール
スライダーは、最小値と最大値によって制限される範囲を含むタイプの編集コントロールです。前回の記事で詳細に検討された編集コントロールとは異なり、スライダには入力フィールドの値を変更するためのボタンがありません。そのためには、それに沿ってスライダを移動させることができる線があります。このようなインタフェース要素は、一定の範囲内の近似値が必要であり正確な値が必要でない場合のみに適しています。しかし、正確な値を入力する可能性が依然として存在します。
この要素は、6グラフィカルオブジェクトで構成されます。それらは:
- 背景
- キャプション(テキストラベル)
- 入力フィールド
- スライダーライン
- スライダーランナー
- スライダーインディケータ
図1。スライダーコントロールの複合部分
このコントロールのクラスの詳細を検討してみましょう。
スライダーコントロール作成クラスの開発
Slider.mqhファイルを作成してWndContainer.mqhファイルに含みます。
//+------------------------------------------------------------------+ //| WndContainer.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "Slider.mqh"
Slider.mqhファイルで開発中のライブラリのそれぞれのコントロールに必要なメソッドのセットを持ったCSliderクラスを作成します。含まれているElement.mqhとWindow.mqhに加えて区切り線作成のためのCSeparateLineクラスを持つSeparateLine.mqhを含みます。CSeparateLineクラスはすでにグラフィカルインタフェース II: 区切り線とコンテキストメニュー要素(チャプター 2)稿で検討されたのでここではぬかします。思い出すべき唯一のことは、高さが2ピクセルよりも大きい場合には、2つの描かれた線の間に空きスペースがあることです。視覚的には、スライダーのランナーが移動されるスライダーライン(スリットまたはスロット)を作成するのに適している中空のように見えます。
//+------------------------------------------------------------------+ //| Slider.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "Element.mqh" #include "Window.mqh" #include "SeparateLine.mqh" //+------------------------------------------------------------------+ //| 編集つきのスライダーを作成するクラス | //+------------------------------------------------------------------+ class CSlider : public CElement { private: //--- 要素が取り付けられているフォームのポインタ CWindow *m_wnd; public: CSlider(void); ~CSlider(void); //--- public: //--- フォームのポインタを格納する 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); //--- Reset the color virtual void ResetColors(void); };
ライブラリユーザは、スライダーコントロールが構成されているすべてのオブジェクトのプロパティを設定できる必要があります。これらのプロパティは以下のとおりです。
- 要素の背景色
- スライダーを記述するためのテキスト
- 異なる状態にあるテキストラベルの色
- 入力フィールドの現在値
- 入力フィールドの大きさ
- 異なる状態にある入力フィールドの色
- 異なる状態にある入力フィールドのテキストの色
- 異なる状態にある入力フィールドのフレームの色
- Y軸(高さ)に沿ったスリットのサイズ
- スリットラインの色
- 異なる状態にあるスライダーインディケータの色
- スライダーランナーの大きさ
- スライダーランナーの色
- マウスの左クリックの優先順位
上記のオブジェクトのフィールドおよび要素のクラスのメソッドのコードは次のとおりです。
class CSlider : public CElement { private: //--- 要素の背景色 color m_area_color; //--- スライダーを記述するテキスト string m_label_text; //--- 異なる状態でのテキストラベルの色 color m_label_color; color m_label_color_hover; color m_label_color_locked; color m_label_color_array[]; //--- 入力フィールドの大きさ int m_edit_x_size; int m_edit_y_size; //--- 異なる状態での入力フィールドの色 color m_edit_color; color m_edit_color_locked; //--- 異なる状態での入力フィールドのテキストの色 color m_edit_text_color; color m_edit_text_color_locked; //--- 異なる状態での入力フィールドのフレームの色 color m_edit_border_color; color m_edit_border_color_hover; color m_edit_border_color_locked; color m_edit_border_color_array[]; //--- スリットサイズ int m_slot_y_size; //--- スリットの色 color m_slot_line_dark_color; color m_slot_line_light_color; //--- 異なる状態でのインディケータの色 color m_slot_indicator_color; color m_slot_indicator_color_locked; //--- スライダーランナーのサイズ int m_thumb_x_size; int m_thumb_y_size; //--- スライダーランナーの色 color m_thumb_color; color m_thumb_color_hover; color m_thumb_color_locked; color m_thumb_color_pressed; //--- マウスの左ボタンの優先順位 int m_zorder; int m_area_zorder; int m_edit_zorder; //--- public: //--- (1) 背景色 (2) テキストラベルの色 void AreaColor(const color clr) { m_area_color=clr; } void LabelColor(const color clr) { m_label_color=clr; } void LabelColorHover(const color clr) { m_label_color_hover=clr; } void LabelColorLocked(const color clr) { m_label_color_locked=clr; } //--- (1) 入力フィールドと (2) スリットのサイズ void EditXSize(const int x_size) { m_edit_x_size=x_size; } void EditYSize(const int y_size) { m_edit_y_size=y_size; } void SlotYSize(const int y_size) { m_slot_y_size=y_size; } //--- 異なる状態での入力フィールドの色 void EditColor(const color clr) { m_edit_color=clr; } void EditColorLocked(const color clr) { m_edit_color_locked=clr; } //--- 異なる状態での入力フィールドのテキストの色 void EditTextColor(const color clr) { m_edit_text_color=clr; } void EditTextColorLocked(const color clr) { m_edit_text_color_locked=clr; } //--- 異なる状態での入力フィールドのフレームの色 void EditBorderColor(const color clr) { m_edit_border_color=clr; } void EditBorderColorHover(const color clr) { m_edit_border_color_hover=clr; } void EditBorderColorLocked(const color clr) { m_edit_border_color_locked=clr; } //--- 区切り線(スリット)の(1) 濃い (2) 薄い色 void SlotLineDarkColor(const color clr) { m_slot_line_dark_color=clr; } void SlotLineLightColor(const color clr) { m_slot_line_light_color=clr; } //--- 異なる状態でのスライダーインディケータの色 void SlotIndicatorColor(const color clr) { m_slot_indicator_color=clr; } void SlotIndicatorColorLocked(const color clr) { m_slot_indicator_color_locked=clr; } //--- スライダーランナーの大きさ void ThumbXSize(const int x_size) { m_thumb_x_size=x_size; } void ThumbYSize(const int y_size) { m_thumb_y_size=y_size; } //--- スライダーランナーの色 void ThumbColor(const color clr) { m_thumb_color=clr; } void ThumbColorHover(const color clr) { m_thumb_color_hover=clr; } void ThumbColorLocked(const color clr) { m_thumb_color_locked=clr; } void ThumbColorPressed(const color clr) { m_thumb_color_pressed=clr; } };
以前のリストのプロパティは主に要素オブジェクトの色やサイズに関連します。範囲とスライダ入力フィールドのプロパティは個別のグループを作成します。これらのプロパティは、次のとおりです。
- 最小値
- 最大値
- 入力フィールドの値変化のステップ
- テキストの配置モード
- 小数点以下の桁数
class CSlider : public CElement { private: //--- (1) 最小値 (2) 最大値 (3) 値変更のステップ double m_min_value; double m_max_value; double m_step_value; //--- 小数点以下の桁数 int m_digits; //--- テキスト配置のモード ENUM_ALIGN_MODE m_align_mode; //--- public: //--- 最小値 double MinValue(void) const { return(m_min_value); } void MinValue(const double value) { m_min_value=value; } //--- 最大値 double MaxValue(void) const { return(m_max_value); } void MaxValue(const double value) { m_max_value=value; } //--- 値変更のステップ double StepValue(void) const { return(m_step_value); } void StepValue(const double value) { m_step_value=(value<=0)?1 : value; } //--- (1) 小数点以下の桁数 (2) テキスト配置のモード void SetDigits(const int digits) { m_digits=::fabs(digits); } void AlignMode(ENUM_ALIGN_MODE mode) { m_align_mode=mode; } };
現在値の取得、またその値を調整して入力フィールドに新しい値を設定するにはCSlider::GetValue()、CSlider::SetValue()、CSlider::ChangeValue() メソッドを使います。
class CSlider : public CElement { private: //--- 入力フィールドの現在値 double m_edit_value; //--- public: //--- 入力フィールドの値を返す/設定する double GetValue(void) const { return(m_edit_value); } bool SetValue(const double value); //--- 入力フィールドの値の変更 void ChangeValue(const double value); }; //+------------------------------------------------------------------+ //| 現在値の設定 | //+------------------------------------------------------------------+ bool CSlider::SetValue(const double value) { //--- 調整 double corrected_value=0.0; //--- ステップを考慮して調整する corrected_value=::MathRound(value/m_step_value)*m_step_value; //--- 最大値と最小値をチェックする if(corrected_value<=m_min_value) corrected_value=m_min_value; if(corrected_value>=m_max_value) corrected_value=m_max_value; //--- 値が変更された場合 if(m_edit_value!=corrected_value) { m_edit_value=corrected_value; return(true); } //--- 値が変更されなかった場合 return(false); } //+------------------------------------------------------------------+ //| 入力フィールドの値の変更 | //+------------------------------------------------------------------+ void CSlider::ChangeValue(const double value) { //--- 確認、調整と新しい値の格納 SetValue(value); //--- 入力フィールドの値の設定 m_edit.Description(::DoubleToString(GetValue(),m_digits)); }
スライダーランナーが移動している場合、入力フィールドの値はX座標と相対して計算されなければなりません。値が手動で入力された場合、スライダーランナーのX座標は入力フィールドの新しい値に相対して算出されます。他の言葉でいうと、要素が開発されているときには逆変換の可能性が許容されるべきです。
正しい計算のためには計算に使用されるクラスの補助フィールド(変数)が必要になります。これらの変数は、要素が作成された直後に一度だけ算出(初期化)される必要があります。以下は、これらの変数の説明です。
- 作業領域内の画素の数(m_pixels_total)。
- 作業領域の値の範囲内のステップの数(m_value_steps_total)。
- 作業領域の幅に相対したステップ(m_position_step)。
これらの値を算出するメソッドを書いてCSlider::CalculateCoefficients()と呼びましょう。
class CSlider : public CElement { private: //--- 作業領域の画素数 int m_pixels_total; //--- 作業領域のステップ数 int m_value_steps_total; //--- 作業領域の変換された幅のステップ double m_position_step; //--- private: //--- 値の算出(ステップと係数) bool CalculateCoefficients(void); }; //+------------------------------------------------------------------+ //| 値の算出(ステップと係数)< | //+------------------------------------------------------------------+ bool CSlider::CalculateCoefficients(void) { //--- 要素の幅がスライダーランナーの幅より小さい場合は終了する if(CElement::XSize()<m_thumb_x_size) return(false); //--- 作業領域の画素数 m_pixels_total=CElement::XSize()-m_thumb_x_size; //--- 作業領域の値の範囲のステップ数 m_value_steps_total=int((m_max_value-m_min_value)/m_step_value); //--- 作業領域の幅と相対したステップ m_position_step=m_step_value*(double(m_value_steps_total)/double(m_pixels_total)); return(true); }
ここで、上記変数の値は、入力フィールドとバックの値に相対したスライダランナーの X 座標を計算するために使用することができます。このためにCSlider::CalculateThumbX()とCSlider::CalculateThumbPos()の2つのメソッドを書きましょう。
CSlider::CalculateThumbX()メソッドの初めに、最小値が負の場合に調整を行うための補助的なローカル変数(neg_range)の値を算出します。その後スライダーランナーのX座標を算出します。スライダーのラインが超えられた場合には、その後、値が調整されます。メソッドの終わりではスライダーランナーのX座標の新しい値が設定され要素が取り付けられているフォームの端からのマージンが再計算されます。
CSlider::CalculateThumbPos()メソッドの冒頭では値の範囲でのスライダーランナーの位置を取得します。最小値が負でm_current_pos_x変数の値が正しい場合は調整が行われます。作業領域が超えられた場合にも、対応する値の調整が行われます。
class CSlider : public CElement { private: //--- スライダーランナーの現在位置: (1) 値 (2) X座標 double m_current_pos; double m_current_pos_x; //--- private: //--- スライダーランナーのX座標の算出 void CalculateThumbX(void); //--- 現在値に相対してスライダーランナーの現在の位置を変更する void CalculateThumbPos(void); }; //+------------------------------------------------------------------+ //| スライダーランナーのX座標の算出 | //+------------------------------------------------------------------+ void CSlider::CalculateThumbX(void) { //--- 最小値が負でありえることを考慮した調整 double neg_range=(m_min_value<0)?::fabs(m_min_value/m_position_step) : 0; //--- スライダーランナーのX座標の算出 m_current_pos_x=m_area.X()+(m_edit_value/m_position_step)+neg_range; //--- 作業領域の左側が超えられた場合 if(m_current_pos_x<m_area.X()) m_current_pos_x=m_area.X(); //--- 作業領域の右側が超えられた場合 if(m_current_pos_x+m_thumb.XSize()>m_area.X2()) m_current_pos_x=m_area.X2()-m_thumb.XSize(); //--- X座標の格納と設定 m_thumb.X(int(m_current_pos_x)); m_thumb.X_Distance(int(m_current_pos_x)); m_thumb.XGap(m_thumb.X()-m_wnd.X()); } //+------------------------------------------------------------------+ //| 値の範囲内スライダーランナーの位置の算出 | //+------------------------------------------------------------------+ void CSlider::CalculateThumbPos(void) { //--- スライダーランナーの位置番号を取得 m_current_pos=(m_thumb.X()-m_area.X())*m_position_step; //--- 最小値が負でありえることを考慮した調整 if(m_min_value<0 && m_current_pos_x!=WRONG_VALUE) m_current_pos+=int(m_min_value); //--- 作業領域の左/右側が超えられたかのチェック if(m_thumb.X2()>=m_area.X2()) m_current_pos=int(m_max_value); if(m_thumb.X()<=m_area.X()) m_current_pos=int(m_min_value); }
スライダーランナーが移動している場合、スライダーインディケータの幅を計算して更新されなければなりません。スライダーインディケーターの右側はスライダーランナーに接続している必要があります。そのためにCSlider::UpdateIndicator()メソッドを書きましょう。
class CSlider : public CElement { private: //--- スライダーインディケータの更新 void UpdateIndicator(void); }; //+------------------------------------------------------------------+ //| スライダーインディケータの更新 | //+------------------------------------------------------------------+ void CSlider::UpdateIndicator(void) { //--- サイズの計算 int x_size=m_thumb.X()-m_indicator.X(); //--- 許容されない値の場合の調整 if(x_size<=0) x_size=1; //--- 新しいサイズの設定 m_indicator.X_Size(x_size); }
スライダーコントロールの作成には6つのprivate及び1つのpublicメソッドが必要です。
class CSlider : public CElement { public: //--- コントロール作成メソッド bool CreateSlider(const long chart_id,const int subwin,const string text,const int x,const int y); //--- private: bool CreateArea(void); bool CreateLabel(void); bool CreateEdit(void); bool CreateSlot(void); bool CreateIndicator(void); bool CreateThumb(void); };
ここでは、検討されたすべての算出メソッドが呼ばれる CSlider::CreateThumb()メソッドのコードのみをお話しします。他のコントロールオブジェクト作成メソッドは、すべてこのシリーズの以前の記事で話されました。
//+------------------------------------------------------------------+ //| スライダーランナーの作成 | //+------------------------------------------------------------------+ bool CSlider::CreateThumb(void) { //--- オブジェクト名の形成 string name=CElement::ProgramName()+"_slider_thumb_"+(string)CElement::Id(); //--- 座標 int x=CElement::X(); int y=m_slot.Y()-((m_thumb_y_size-m_slot_y_size)/2); //--- オブジェクトの設定 if(!m_thumb.Create(m_chart_id,name,m_subwin,x,y,m_thumb_x_size,m_thumb_y_size)) return(false); //--- プロパティの設定 m_thumb.Color(m_thumb_color); m_thumb.BackColor(m_thumb_color); m_thumb.BorderType(BORDER_FLAT); m_thumb.Corner(m_corner); m_thumb.Selectable(false); m_thumb.Z_Order(m_zorder); m_thumb.Tooltip("\n"); //--- サイズの設定(オブジェクトで) m_thumb.XSize(m_thumb.X_Size()); m_thumb.YSize(m_thumb.Y_Size()); //--- 座標を格納 m_thumb.X(x); m_thumb.Y(y); //--- 端からのマージン m_thumb.XGap(x-m_wnd.X()); m_thumb.YGap(y-m_wnd.Y()); //--- 補助的な変数の値の算出 CalculateCoefficients(); //--- 入力フィールドの現在値と相対したスライダーランナーのX座標の計算 CalculateThumbX(); //--- 値の範囲内でのスライダーランナーの位置の計算 CalculateThumbPos(); //--- スライダーインディケータの更新 UpdateIndicator(); //--- オブジェクトポインタの格納 CElement::AddToArray(m_thumb); return(true); }
スライダーランナーを移動するメソッドはCScroll及びCScrollHクラスの名前の似たメソッドと同じです。 これらはグラフィカルインタフェース V:縦横のスクロールバー(チャプター 1)で検討されました。なのでここではそのコードは検討されません。CSliderクラスで宣言するだけにします。
class CSlider : public CElement { private: //--- マウスボタンの状態(押されている/いない) ENUM_THUMB_MOUSE_STATE m_clamping_area_mouse; //--- スライダーランナーの動きのモードの認識 bool m_slider_thumb_state; //--- スライダーランナーの動きに関連した変数 int m_slider_size_fixing; int m_slider_point_fixing; //--- private: //--- スライダーランナーの動きの工程 void OnDragThumb(const int x); //--- スライダーランナーの位置の更新 void UpdateThumb(const int new_x_point); //--- マウスボタンの状態の更新 void CheckMouseButtonState(void); //--- スライダーランナーの動きに関連した変数をゼロ化する void ZeroThumbVariables(void); };
入力フィールドへの入力を処理するには CSlider::OnEvent()イベントハンドラで呼び出されるCSlider::OnEndEdit()メソッドを作成します。
CSlider::OnEndEdit()メソッドの冒頭には、オブジェクト名による、、値がこのスライダーに入力されたかどうかのチェックがあります。続いて入力フィールドの現在値を取得します。その後、許容されない値の入力に対した必須のチェック、調整、スライダーランナー X座標の計算と値の範囲内の位置の計算が続きます。スライダーランナー はこの後で更新されます。メソッドの最後には (1) ON_END_EDITカスタムイベント識別子 (2) 要素識別子 (3) 要素インデックス (4) テキストラベルの記述を持ったメッセージが送信されます。
class CSlider : public CElement { private: //--- 入力フィールドへの入力の処理 bool OnEndEdit(const string object_name); }; //+------------------------------------------------------------------+ //| 入力フィールドへの入力の処理 | //+------------------------------------------------------------------+ bool CSlider::OnEndEdit(const string object_name) { //--- オブジェクト名が違ったら終了する if(object_name!=m_edit.Name()) return(false); //--- 入力値の取得 double entered_value=::StringToDouble(m_edit.Description()); //--- 確認、調整と新しい値の格納 ChangeValue(entered_value); //--- スライダーランナーのX座標の算出 CalculateThumbX(); //--- 値の範囲内の一の計算 CalculateThumbPos(); //--- スライダーランナーの更新 UpdateIndicator(); //--- 関連したメッセージを送信する ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description()); return(true); }
同じカスタムメッセージは、入力フィールドに値を変更するためにスライダーランナーの移動が停止した後に送信される必要があります。これにはCSlider::ZeroThumbVariables() メソッドが最適です。これはマウス左ボタンの押下の領域が追跡されるCSlider::CheckMouseButtonState()メソッドで呼び出されます。CSlider::ZeroThumbVariables()メソッドの呼び出しは左ボタンが離されことを暗示します。スライダーランナーの領域上の押下はスライダーランナーの移動の完了を意味し、入力フィールドの値が変更されたというメッセージが送信しなければなりません。
//+------------------------------------------------------------------+ //| スクロールバーの動きに関連した変数のゼロ化 | //+------------------------------------------------------------------+ void CSlider::ZeroThumbVariables(void) { //--- ここにいるということはマウスの左ボタンが離された // マウスの左ボタンがスライダーランナーの上で押下された場合 if(m_clamping_area_mouse==THUMB_PRESSED_INSIDE) { //--- ... スライダーランナーを持つ入力フィールドの値の変更が完了したとのメッセージを送信する ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description()); } //--- m_slider_size_fixing =0; m_clamping_area_mouse =THUMB_NOT_PRESSED; //--- 要素識別子が活性化識別子と一致する場合 // フォームのブロックを解除し、アクティブにされた要素の識別子をリセットする if(CElement::Id()==m_wnd.IdActivatedElement()) { m_wnd.IsLocked(false); m_wnd.IdActivatedElement(WRONG_VALUE); } }
この場合のCSlider::OnEvent() イベントハンドラの完全なコードは下記の通りです。
//+------------------------------------------------------------------+ //| チャートイベントハンドラ | //+------------------------------------------------------------------+ void CSlider::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; m_mouse_state=(bool)int(sparam); //--- 要素へのフォーカスの確認 CElement::MouseFocus(x>X() && x<X2() && y>Y() && y<Y2()); m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() && y>m_thumb.Y() && y<m_thumb.Y2()); //--- 要素が非表示の場合は終了する if(!m_slider_state) return; //--- マウスボタンの状態を確認して格納する CheckMouseButtonState(); //--- スライダーランナーの色を変える ChangeThumbColor(); //--- 管理がスライダーラインに渡された場合にはその場所を特定する if(m_clamping_area_mouse==THUMB_PRESSED_INSIDE) { //--- スライダーランナーの移動 OnDragThumb(x); //--- 範囲内のスライダーランナーの位置の算出 CalculateThumbPos(); //--- 入力フィールドで新しい値を格納する ChangeValue(m_current_pos); //--- スライダーインディケータの更新 UpdateIndicator(); return; } } //--- 入力フィールドイベントで変化する値の処理 if(id==CHARTEVENT_OBJECT_ENDEDIT) { //--- 値入力の処理 if(OnEndEdit(sparam)) return; } }
スライダ要素を作成および管理するためのメソッドはこれで実装されました。前回の記事でで操作したMQLアプリケーションでそれを検証してみましょう。
スライダーコントロールの検証
前回の記事では、テストアプリケーションで他の要素の可用性を管理する4つのチェックボックスを作成しました。スライダ要素とグラフィカルインタフェースへの可用性を管理するための5番目のチェックボックスを追加します。これにはCProgramカスタムクラスでCCheckBox及びCSliderクラスのインスタンスとこれらのコントロールが取り付けられているフォームの端からのマージンを宣言します。
//+------------------------------------------------------------------+ //| アプリケーション作成クラス | //+------------------------------------------------------------------+ class CProgram : public CWndEvents { private: //--- チェックボックス CCheckBox m_checkbox5; //--- スライダー CSlider m_slider1; //--- private: //--- チェックボックス #define CHECKBOX5_GAP_X (7) #define CHECKBOX5_GAP_Y (200) bool CreateCheckBox5(const string text); //--- スライダー #define SLIDER1_GAP_X (32) #define SLIDER1_GAP_Y (225) bool CreateSlider1(const string text); };
チェックボックスを作成するためのメソッドのコードは前回の記事で検討されたのでCProgram::CreateSlider1() 要素を作成するメソッドに移ります。CSlider::MinValue()とCSlider::MaxValue()メソッドを使って1~1の範囲での値を設定します。ステップを小数点以下8桁(0.00000001)まで設定します。その可用性は5番目のチェックボックスの現在の状態に依存します。
//+------------------------------------------------------------------+ //| スライダー1を作成する | //+------------------------------------------------------------------+ bool CProgram::CreateSlider1(const string text) { //--- ウィンドウポインタを格納する m_slider1.WindowPointer(m_window1); //--- 座標 int x=m_window1.X()+SLIDER1_GAP_X; int y=m_window1.Y()+SLIDER1_GAP_Y; //--- 値 double v=(m_slider1.GetValue()==WRONG_VALUE) ?0.84615385 : m_slider1.GetValue(); //--- 作成前にプロパティを設定する m_slider1.XSize(264); m_slider1.YSize(40); m_slider1.EditXSize(87); m_slider1.MaxValue(1); m_slider1.StepValue(0.00000001); m_slider1.MinValue(-1); m_slider1.SetDigits(8); m_slider1.SetValue(v); m_slider1.AreaColor(clrWhiteSmoke); m_slider1.LabelColor(clrBlack); m_slider1.LabelColorLocked(clrSilver); m_slider1.EditColorLocked(clrWhiteSmoke); m_slider1.EditBorderColor(clrSilver); m_slider1.EditBorderColorLocked(clrSilver); m_slider1.EditTextColorLocked(clrSilver); m_slider1.SlotLineDarkColor(clrSilver); m_slider1.SlotLineLightColor(clrWhite); m_slider1.SlotYSize(4); m_slider1.ThumbColorLocked(clrLightGray); m_slider1.ThumbColorPressed(clrSilver); m_slider1.SlotIndicatorColor(C'85,170,255'); m_slider1.SlotIndicatorColorLocked(clrLightGray); //--- コントロールの作成 if(!m_slider1.CreateSlider(m_chart_id,m_subwin,text,x,y)) return(false); //--- 可用性は5番目のチェックボックスの状態に依存する m_slider1.SliderState(m_checkbox5.CheckButtonState()); //--- オブジェクトをオブジェクトグループの共通配列に追加する CWndContainer::AddToElementsArray(0,m_slider1); return(true); }
要素を作成するための新しいメソッドは、グラフィカルインターフェースを作成するためのメインメソッドで呼び出さなければなりません。下記はメソッドの短縮版です。
//+------------------------------------------------------------------+ //| 取引パネルを作成する | //+------------------------------------------------------------------+ bool CProgram::CreateTradePanel(void) { //--- コントロールのためのフォーム1を作成する //--- コントロールの作成: // メインメニュー //--- コンテキストメニュー //--- ステータスバーの作成 //--- チェックボックス if(!CreateCheckBox5("Checkbox 5")) return(false); //--- スライダー if(!CreateSlider1("Slider 1:")) return(false); //--- チャートの再描画 m_chart.Redraw(); return(true); }
アプリケーションのCProgram::OnEvent()イベントハンドラでは、スライダーの可用性を制御する5番目のチェックボックスの状態の変化を追跡します。ON_END_EDITカスタム識別子を持ったイベントは入力フィールドの値の変化を示します。
//+------------------------------------------------------------------+ //| イベントハンドラ | //+------------------------------------------------------------------+ void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- テキストラベル押下イベント if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL) { ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam); //--- 5番目のチェックボックスがクリックされた場合 if(lparam==m_checkbox5.Id()) { //--- 1番目のスライダーの状態を設定する m_slider1.SliderState(m_checkbox5.CheckButtonState()); } } //--- The end of entering the value in the entry field event if(id==CHARTEVENT_CUSTOM+ON_END_EDIT) { ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam); } }
ここで、プログラムはコンパイルされチャート上に読み込まれることができます。アプリケーションのグラフィカルインターフェースのコントロールと対話してみてください。すべてが正しく行われた場合は、下のスクリーンショットのように結果が表示されます。
図2。スライダーコントロールの検証
デュアルスライダーコントロール
デュアルスライダーと単純なスライダとーの間の違いは、前者はユーザによって設定された値の範囲内で選択可能だということです。そのため、スライダーのライン上には2つのスライダーランナーがあります。左側のスライドランナーは、スライダーラインの左側から右のスライダランナーに移動することができます。右のスライダーランナーは、スライダーラインの右側から左のスライダーランナーに移動させることができます。<デュアルスライダーはスライダーラインのスライダーランナーの位置に相対した値を反映した2つの入力フィールドを持ちます。値は手動でこれらの入力フィールドに入力することができます。これは、スライダランナーの位置を変更します。
このコントロールは8つのグラフィカルオブジェクトで構成されます。それらは:
- 背景
- キャプション(テキストラベル)
- 左入力フィールド
- 右入力フィールド
- スライダーライン
- 左スライダーランナー
- 右スライダーランナー
- スライダーインディケータ
図3。デュアルスライダーコントロールの複合部分
デュアルスライダーのクラスを検討し単純なスライダーからの違いに注意しましょう。
デュアルスライダーコントロール作成クラスの開発
コントロールのCDualSliderを持つDualSlider.mqhファイルをWndContainer.mqhファイルに含みます。
//+------------------------------------------------------------------+ //| WndContainer.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "DualSlider.mqh"
コントロールプロパティの面ではCDualSliderクラスはCSliderクラスと全く同じです。ここでの唯一の違いは、左右の入力フィールドとスライダーランナーは別々のフィールドやメソッドを必要とすることです。これらの2つのメソッドの違いは軽微なのでここでそのコードを議論するつもりはありません。コードはこの記事に添付されたファイルで参照できます。
class CDualSlider : public CElement { private: //--- 入力フィールドの現在値(左と右) double m_left_edit_value; double m_right_edit_value; //--- スライダーランナーの現在位置(左と右) double m_left_current_pos; double m_left_current_pos_x; double m_right_current_pos; double m_right_current_pos_x; //--- スライダーランナー(左と右)のマウスボタンの状態(/押されている/押されていない) ENUM_THUMB_MOUSE_STATE m_clamping_mouse_left_thumb; ENUM_THUMB_MOUSE_STATE m_clamping_mouse_right_thumb; //--- public: //--- 入力フィールドの値を返す/設定する(左と右) double GetLeftValue(void) const { return(m_left_edit_value); } double GetRightValue(void) const { return(m_right_edit_value); } bool SetLeftValue(double value); bool SetRightValue(double value); //--- 入力フィールドの値を変える(左と右) void ChangeLeftValue(const double value); void ChangeRightValue(const double value); //--- private: //--- スライダーランナーの移動の工程(左と右) void OnDragLeftThumb(const int x); void OnDragRightThumb(const int x); //--- スライダーランナーの位置の更新(左と右) void UpdateLeftThumb(const int new_x_point); void UpdateRightThumb(const int new_x_point); //--- スライダーランナー上のマウスの左ボタンの状態をチェック void CheckMouseOnLeftThumb(void); void CheckMouseOnRightThumb(void); //--- スライダーのX座標を計算(左と右) void CalculateLeftThumbX(void); void CalculateRightThumbX(void); //--- 値に相対した左側のスライドランナーの位置の変更(左と右) void CalculateLeftThumbPos(void); void CalculateRightThumbPos(void); };
ここでは、2入力フィールドとスライダのランナーが考慮されているメソッドのコードのみを紹介します。下記はCDualSlider::OnEndEdit() メソッドの構成です。
class CDualSlider : public CElement { private: //--- 入力フィールドへの値入力の処理 bool OnEndEdit(const string object_name); }; //+------------------------------------------------------------------+ //| 値入力の終わり | //+------------------------------------------------------------------+ bool CDualSlider::OnEndEdit(const string object_name) { //--- 値が左入力フィールドに入力された場合 if(object_name==m_left_edit.Name()) { //--- 値を取得する double entered_value=::StringToDouble(m_left_edit.Description()); //--- 新しい値を確認、調整、格納する ChangeLeftValue(entered_value); //--- スライダーランナーのX座標を算出する CalculateLeftThumbX(); //--- スライダーランナーの位置を更新する UpdateLeftThumb(m_left_thumb.X()); //--- 値の範囲内の位置を算出する CalculateLeftThumbPos(); //--- 新しい値を確認、調整、格納する ChangeLeftValue(m_left_current_pos); //--- スライダーインディケータを更新する UpdateIndicator(); //--- それについてのメッセージを送信する ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description()); return(true); } //--- 値が右入力フィールドに入力された場合 if(object_name==m_right_edit.Name()) { //--- 入力された値を取得する double entered_value=::StringToDouble(m_right_edit.Description()); //--- 新しい値を確認、調整、格納する ChangeRightValue(entered_value); //--- スライダーランナーのX座標を算出する CalculateRightThumbX(); //--- スライダーランナーの位置を更新する UpdateRightThumb(m_right_thumb.X()); //--- 値の範囲内の位置を算出する CalculateRightThumbPos(); //--- 新しい値を確認、調整、格納する ChangeRightValue(m_right_current_pos); //--- スライダーインディケータを更新する UpdateIndicator(); //--- それについてのメッセージを送信する ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),CElement::Index(),m_label.Description()); return(true); } //--- return(false); }
左と右スライダーランナーの移動も同様です。CDualSlider::OnEvent()イベントハンドラはそれぞれ別々のチェックとコードを含みます。
//+------------------------------------------------------------------+ //| チャートイベントハンドラ | //+------------------------------------------------------------------+ void CDualSlider::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; m_mouse_state=(bool)int(sparam); //--- 要素のフォーカスの確認 CElement::MouseFocus(x>X() && x<X2() && y>Y() && y<Y2()); m_left_thumb.MouseFocus(x>m_left_thumb.X() && x<m_left_thumb.X2() && y>m_left_thumb.Y() && y<m_left_thumb.Y2()); m_right_thumb.MouseFocus(x>m_right_thumb.X() && x<m_right_thumb.X2() && y>m_right_thumb.Y() && y<m_right_thumb.Y2()); //--- 要素がブロックされている場合は終了する if(!m_slider_state) return; //--- マウスボタンの状態を確認して保存する CheckMouseOnLeftThumb(); CheckMouseOnRightThumb(); //--- スライダーランナーの色を変える ChangeThumbColor(); //--- 管理がスライダーラインに渡された場合(左と右) if(m_clamping_mouse_left_thumb==THUMB_PRESSED_INSIDE) { //--- スライダーランナーの移動 OnDragLeftThumb(x); //--- 位置の範囲内のスライダーランナーの位置の算出 CalculateLeftThumbPos(); //--- 入力フィールドでの新しい値の設定 ChangeLeftValue(m_left_current_pos); //--- スライダーインディケータの更新 UpdateIndicator(); return; } //--- 管理がスクロールに渡された場合(右スライダーランナー) if(m_clamping_mouse_right_thumb==THUMB_PRESSED_INSIDE) { //--- Moving the slider runner OnDragRightThumb(x); //--- Calculation of the slider runner position in the value range CalculateRightThumbPos(); //--- Setting a new value in the entry field ChangeRightValue(m_right_current_pos); //--- Update the slider indicator UpdateIndicator(); return; } } }
本稿に添付されたファイルをダウンロードしてCDualSliderクラスのコードの繊細が自学できます。
デュアルスライダーコントロールの検証
テストアプリケーションのグラフィカルインターフェースにデュアルスライダーコントロールを追加します。アプリケーションのCProgram カスタムクラスでCDualSliderクラスインスタンスとフォームの端からのマージンのメソッドを宣言します。
//+------------------------------------------------------------------+ //| アプリケーション作成クラス | //+------------------------------------------------------------------+ class CProgram : public CWndEvents { private: //--- スライダー CDualSlider m_dual_slider1; //--- private: //--- スライダー #define DUALSLIDER1_GAP_X (32) #define DUALSLIDER1_GAP_Y (275) bool CreateDualSlider1(const string text); };
下記のコードはCProgram::CreateDualSlider1()メソッドの構成を示します。-2000~1000の範囲で値を設定します。このコントロールの可用性は、本稿前半で作成された単純なスライダーに似て、5番目ののチェックボックスの現在の状態に依存します。
//+------------------------------------------------------------------+ //| デュアルスライダー1の作成 | //+------------------------------------------------------------------+ bool CProgram::CreateDualSlider1(const string text) { //--- ウィンドウポインタを格納する m_dual_slider1.WindowPointer(m_window1); //--- 座標 int x=m_window1.X()+DUALSLIDER1_GAP_X; int y=m_window1.Y()+DUALSLIDER1_GAP_Y; //--- 値 double v1=(m_dual_slider1.GetLeftValue()==WRONG_VALUE) ?0 : m_dual_slider1.GetLeftValue(); double v2=(m_dual_slider1.GetRightValue()==WRONG_VALUE) ?500 : m_dual_slider1.GetRightValue(); //--- 作成の前にプロパティを設定する m_dual_slider1.XSize(264); m_dual_slider1.YSize(40); m_dual_slider1.EditXSize(87); m_dual_slider1.MaxValue(1000); m_dual_slider1.StepValue(1); m_dual_slider1.MinValue(-2000); m_dual_slider1.SetDigits(0); m_dual_slider1.SetLeftValue(v1); m_dual_slider1.SetRightValue(v2); m_dual_slider1.AreaColor(clrWhiteSmoke); m_dual_slider1.LabelColor(clrBlack); m_dual_slider1.LabelColorLocked(clrSilver); m_dual_slider1.EditColorLocked(clrWhiteSmoke); m_dual_slider1.EditBorderColor(clrSilver); m_dual_slider1.EditBorderColorLocked(clrSilver); m_dual_slider1.EditTextColorLocked(clrSilver); m_dual_slider1.SlotLineDarkColor(clrSilver); m_dual_slider1.SlotLineLightColor(clrWhite); m_dual_slider1.SlotYSize(4); m_dual_slider1.ThumbColorLocked(clrLightGray); m_dual_slider1.ThumbColorPressed(clrSilver); m_dual_slider1.SlotIndicatorColor(C'85,170,255'); m_dual_slider1.SlotIndicatorColorLocked(clrLightGray); //--- コントロールの作成 if(!m_dual_slider1.CreateSlider(m_chart_id,m_subwin,text,x,y)) return(false); //--- 可用性は5番目のチェックボックスの現在の状態に依存する m_dual_slider1.SliderState(m_checkbox5.CheckButtonState()); //--- オブジェクトをオブジェクトグループの共通配列に追加する CWndContainer::AddToElementsArray(0,m_dual_slider1); return(true); }
以下のコードの短縮版で実証されているように、グラフィカルインタフェースを作成するためのメインメソッドに新しいコントロールのメソッドの呼び出しを配置することを忘れないでください。
//+------------------------------------------------------------------+ //| 取引パネルの作成 | //+------------------------------------------------------------------+ bool CProgram::CreateTradePanel(void) { //--- コントロールのフォーム1の作成 //--- Creating controls: // メインメニュー //--- コンテキストメニュー //--- ステータスバーの作成 //--- チェックボックス //--- スライダー if(!CreateDualSlider1("Dual Slider 1:")) return(false); //--- チャートの再描画 m_chart.Redraw(); return(true); }
5番目のチェックボックスの現状態はシンプルスライダーとデュアルスライダの2つのコントロールを定義します。
//+------------------------------------------------------------------+ //| イベントハンドラ | //+------------------------------------------------------------------+ void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- テキストラベルの押下イベント if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL) { ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam); //--- 5番目のチェックボックスがクリックされた場合 if(lparam==m_checkbox5.Id()) { //--- スライダーの状態を設定する m_slider1.SliderState(m_checkbox5.CheckButtonState()); m_dual_slider1.SliderState(m_checkbox5.CheckButtonState()); } } //--- 入力フィールドイベントへの入力の最後 if(id==CHARTEVENT_CUSTOM+ON_END_EDIT) { ::Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam); } }
プログラムをコンパイルしてプログラムをチャートに読み込みます。下のスクリーンショットが結果を示します。
図4。デュアルスライダーコントロール
おわりに
シリーズの第六部では6つのコントロールが検討されました。
- チェックボックス
- 編集コントロール
- チェックボックスを持った編集コントロール
- チェックコンボボックス
- スライダー
- デュアルスライダー
グラフィカルインタフェースを作成するためのライブラリーの概略は現在以下の通りに見えます。
図5。開発の現段階でのライブラリの構造
シリーズの次の部分では、テーブルやタブでライブラリーを改善します。
パートVI の資料はダウンロードされ、動作の検証が可能です。それらのファイルの資料を使用についてご質問がある場合は、以下のリストにある記事のいずれかでライブラリの開発の詳細をご参照になるるか、本稿へのコメント欄でご質問ください。
第六部の記事(チャプター)のリストは下記の通りです。
- グラフィカルインタフェースVI:チェックボックスコントロール、編集コントロールとその混合型(チャプター 1)
- グラフィカルインタフェースVI:スライダーとデュアルスライダーコントロール(チャプター 2)
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/2468





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