グラフィカルインタフェースIX:カラーピッカーコントロール(チャプター1)
コンテンツ
はじめに
このライブラリの目的のより良い理解を得るためには、シリーズ初めのグラフィカルインタフェース I: ライブラリストラクチャの準備(チャプター 1)をお読みください。各部の記事の終わりにはリンク付きのチャプターリストがあり、開発の現段階でのライブラリの完全版をダウンロードすることができます。ファイルはアーカイブと同じディレクトリに配置される必要があります。
シリーズの第九部では、以下のコントロールおよびインターフェース要素を説明します。
1. 第1章
- カラーピッカーコントロール(CColorPickerクラス)
- カラーボタンコントロール(CColorButtonクラス)
2. 第2章
- プログレスバーコントロール(CProgressBarクラス)
- 折れ線グラフコントロール(CLineGraphクラス)
カスタムアプリケーションにも適用可能な方法を示す包括的な例が、上記されたコントロールの全てにおいて提供されています。
カラーピッカーコントロール
カラーパレットは、オブジェクトの色を示すオプションを持つ様々なアプリケーションで見ることができます。MetaTraderの取引ターミナルでは、カラーパレットはMQLアプリケーションのコントロールの色を簡単に変更するために使用できます。たとえば、グラフィカルインターフェイスの視覚的舞台が設定されて各コントロールで色を設定する必要がある場合、カラーパレットなしでこれを行うのは非常に不便でしょう。
カラーパレットは、選択されたカラーモデルを表示する実際のパレットに加えて他のオブジェクトとコントロールのグループを持っている複雑なコントロール複合要素です。このコントロールの複合部分は以下の通りです。
- 背景
- 指定されたカラーモデルを表示するカラーパレット
- 設定された色のマーカー
- 選択された色のマーカー
- マウスがホバーするときの色のマーカー
- カラーモデルのコンポーネントを手動で設定するための編集ボックス付きのラジオボタンのグループ
- 選択された色をキャンセルするボタン
- 2番目のマーカーで指定された色を設定(修正)するボタン
図1 カラーピッカーの複合部分
上記のスクリーンショットでは、ラジオボタンのグループがそれぞれ3つのラジオボタンを有する3つのサブグループに分割されています。それぞれのサブグループはカラーモデルで、ラジオボタンはモデルの構成要素(色領域の座標)です。以下のリストは、開発中のライブラリのカラーパレットの作成に使用されるすべてのカラーモデルの略語を解読します。
1. HSLカラーモデル:
- H - 色相。0~360の値。
- S - 彩度。0~100の値。
- L - 明度。0~100の値。
2. RGBカラーモデル:
- R - 赤。0 ~255の値。
- G - 緑。0 ~255の値。
- B - 青。0~255の値。
3. Labカラーモデル:
- L - 輝度。0~100の値。
- a – 緑から紫の色調を定義する1番目の色座標。128~127の値。
- b – 青から黄の色調を定義する2番目の色座標。128~127の値。
さらに、カラーパレットを作成するためのColorPickerクラスを考察します。
CColorPickerクラスの開発
コントロールのファイルが現在保持されているディレクトリ(<data folder>\MQLX\Include\EasyAndFastGUI\Controls)にColorPicker.mqh ファイルを作成します。このファイルで、下記のコードにあるように、標準的なメンバーを持ったCColorPickerクラスを作成します。
//+------------------------------------------------------------------+ //| ColorPicker.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "Element.mqh" #include "Window.mqh" //+------------------------------------------------------------------+ //| カラーピッカー作成クラス | //+------------------------------------------------------------------+ class CColorPicker : public CElement { private: //--- コントロールが接続されるフォームへのポインタ CWindow *m_wnd; //--- public: CColorPicker(void); ~CColorPicker(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); //--- 色をリセットする virtual void ResetColors(void) {} };
コントロールのグラフィカルオブジェクトの設定には次のプロパティが利用できるようになります。
- コントロール領域の色
- コントロール領域の境界の色
- カラーパレットとマーカーの境界線の色
他のコントロールのグラフィカルオブジェクトのプロパティは、そのポインタが受け取られた後に変更することができます。
class CColorPicker : public CElement { private: //--- (1) 領域と (2) 領域の境界の色 color m_area_color; color m_area_border_color; //--- パレット境界の色 color m_palette_border_color; //--- public: //--- (1) 領域と (2) 領域の境界の色と (3) パレットの境界の色 void AreaBackColor(const color clr) { m_area_color=clr; } void AreaBorderColor(const color clr) { m_area_border_color=clr; } void PaletteBorderColor(const color clr) { m_palette_border_color=clr; } };
他のコントロールはカラーパレットの複合部分として使われるためこれらのコントロールのクラスファイルを ColorPicker.mqhファイルと結びつける必要があります。カラーパレットの作成には17のプライベートメソッドと1つのパブリックメソッドが必要になります。
//+------------------------------------------------------------------+ //| ColorPicker.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "Element.mqh" #include "Window.mqh" #include "SpinEdit.mqh" #include "SimpleButton.mqh" #include "RadioButtons.mqh" //+------------------------------------------------------------------+ //| カラーパレット作成クラス | //+------------------------------------------------------------------+ class CColorPicker : public CElement { private: //--- コントロール作成のためのオブジェクト CRectLabel m_area; CRectCanvas m_canvas; CRectLabel m_current; CRectLabel m_picked; CRectLabel m_hover; //--- CRadioButtons m_radio_buttons; CSpinEdit m_hsl_h_edit; CSpinEdit m_hsl_s_edit; CSpinEdit m_hsl_l_edit; //--- CSpinEdit m_rgb_r_edit; CSpinEdit m_rgb_g_edit; CSpinEdit m_rgb_b_edit; //--- CSpinEdit m_lab_l_edit; CSpinEdit m_lab_a_edit; CSpinEdit m_lab_b_edit; //--- CSimpleButton m_button_ok; CSimpleButton m_button_cancel; //--- public: //--- コントロール作成メソッド bool CreateColorPicker(const long chart_id,const int subwin,const int x,const int y); //--- private: bool CreateArea(void); bool CreatePalette(void); bool CreateCurrentSample(void); bool CreatePickedSample(void); bool CreateHoverSample(void); bool CreateRadioButtons(void); bool CreateHslHEdit(void); bool CreateHslSEdit(void); bool CreateHslLEdit(void); bool CreateRgbREdit(void); bool CreateRgbGEdit(void); bool CreateRgbBEdit(void); bool CreateLabLEdit(void); bool CreateLabAEdit(void); bool CreateLabBEdit(void); bool CreateButtonOK(const string text); bool CreateButtonCancel(const string text); };
カラーパレットの隣にあるラジオボタンを切り替えると、色領域の2次元カットが選択されたコンポーネントに示された値に応じて表示されます。すなわち、各カットを描画するためには、初めにそのコンポーネントの現在値に相対して計算を行う必要があります。したがって、各カラーモデルのための3つの別々のメソッドが記述されます。選択されたラジオボタンのインデックスはすべてこれらのメソッドに送信されます(選択されたインデックス)。
色を変えるためには、コントロールの基本クラス(CElement)で宣言されたCColors クラスのインスタンスのメソッドを使用します 。CColorsクラスにはRGB形式をLabに変換する適切なメソッドがありません。よって、RGB->Lab変換が必要な場合には XYZカラーマスターモデルを通じた二重補正RGB->XYZ->Labが使われなければなりません。すべてのカラーモデルのコンポーネントを計算してCColorPickerクラスに格納するには、関連したフィールドの宣言が必要です。
class CColorPicker : public CElement { private: //--- 異なるカラーモデルでのコンポーネントの値 // HSL double m_hsl_h; double m_hsl_s; double m_hsl_l; //--- RGB double m_rgb_r; double m_rgb_g; double m_rgb_b; //--- Lab double m_lab_l; double m_lab_a; double m_lab_b; //--- XYZ double m_xyz_x; double m_xyz_y; double m_xyz_z; //--- private: //--- HSLカラーモデルに基づいてパレットを描画する(0: H, 1: S, 2: L) void DrawHSL(const int index); //--- RGBカラーモデルに基づいてパレットを描画する(3: R, 4: G, 5: B) void DrawRGB(const int index); //--- LABカラーモデルに基づいてパレットを描画する(6: L, 7: a, 8: b) void DrawLab(const int index); };
メソッド間の唯一の違いは変更前のコンポーネント値の試算なので、ここでは例としてこれらのメソッドの内の1つであるCColorPicker::DrawHSL()のコードを提示します。他のメソッドのコードは本稿に添付されたファイルで参照できます。
計算と描画は表示される各画素で行われます。計算はカラーパレットサイズに相対して行われることにご注意ください。すなわち、このコードの使用によって、異なるサイズや形状(必ずしも正方形ではない)のカラーパレットを有する同様のコントロールを作成することができます。
図2 500x255画素サイズのカラーパレットの例
//+------------------------------------------------------------------+ //| HSLパレットを描画する | //+------------------------------------------------------------------+ void CColorPicker::DrawHSL(const int index) { switch(index) { //--- Hue (H) - 0~360の範囲の色調 case 0 : { //--- Hコンポーネントを計算する m_hsl_h=m_hsl_h_edit.GetValue()/360.0; //--- for(int ly=0; ly<m_canvas.YSize(); ly++) { //--- Lコンポーネントを計算する m_hsl_l=ly/(double)m_canvas.YSize(); //--- for(int lx=0; lx<m_canvas.XSize(); lx++) { //--- Sコンポーネントを計算する m_hsl_s=lx/(double)m_canvas.XSize(); //--- HSLコンポーネントをRGBに変換する m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b); //--- チャンネルをつなげる uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b); m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color); } } break; } //--- Saturation (S) - 0〜100の範囲の彩度 case 1 : { //--- Sコンポーネントを計算する m_hsl_s=m_hsl_s_edit.GetValue()/100.0; //--- for(int ly=0; ly<m_canvas.YSize(); ly++) { //--- Lコンポーネントを計算する m_hsl_l=ly/(double)m_canvas.YSize(); //--- for(int lx=0; lx<m_canvas.XSize(); lx++) { //--- Hコンポーネントを計算する m_hsl_h=lx/(double)m_canvas.XSize(); //--- HSLコンポーネントをRGBに変換する m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b); //--- チャンネルをつなげる uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b); m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color); } } break; } //--- Lightness (L) - 0~100の範囲の明度 case 2 : { //--- Lコンポーネントを計算する m_hsl_l=m_hsl_l_edit.GetValue()/100.0; //--- for(int ly=0; ly<m_canvas.YSize(); ly++) { //--- Sコンポーネントを計算する m_hsl_s=ly/(double)m_canvas.YSize(); //--- for(int lx=0; lx<m_canvas.XSize(); lx++) { //--- Hコンポーネントを計算する m_hsl_h=lx/(double)m_canvas.XSize(); //--- HSLコンポーネントをRGBに変換する m_clr.HSLtoRGB(m_hsl_h,m_hsl_s,m_hsl_l,m_rgb_r,m_rgb_g,m_rgb_b); //--- チャンネルをつなげる uint rgb_color=XRGB(m_rgb_r,m_rgb_g,m_rgb_b); m_canvas.PixelSet(lx,m_canvas.YSize()-ly,rgb_color); } } break; } } }
カラーパレットのキャンバスに境界を描画するCColorPicker::DrawPaletteBorder() メソッドを書きます。
class CColorPicker : public CElement { private: //--- パレットの境界を描画する void DrawPaletteBorder(void); }; //+------------------------------------------------------------------+ //| パレットの境界を描画する | //+------------------------------------------------------------------+ void CColorPicker::DrawPaletteBorder(void) { //--- パレットサイズ int x_size=m_canvas.XSize()-1; int y_size=m_canvas.YSize()-1; //--- 境界を描画する m_canvas.Line(0,0,x_size,0,m_palette_border_color); m_canvas.Line(0,y_size,x_size,y_size,m_palette_border_color); m_canvas.Line(0,0,0,y_size,m_palette_border_color); m_canvas.Line(x_size,0,x_size,y_size,m_palette_border_color); }
上記された描画メソッドのすべては最終的にカラーパレット描画メソッドであるCColorPicker::DrawPalette() で呼ばれます。
class CColorPicker : public CElement { private: //--- パレットを描画する void DrawPalette(const int index); }; //+------------------------------------------------------------------+ //| パレットを描画する | //+------------------------------------------------------------------+ void CColorPicker::DrawPalette(const int index) { switch(index) { //--- HSL (0: H, 1: S, 2: L) case 0 : case 1 : case 2 : { DrawHSL(index); break; } //--- RGB (3: R, 4: G, 5: B) case 3 : case 4 : case 5 : { DrawRGB(index); break; } //--- LAB (6: L, 7: a, 8: b) case 6 : case 7 : case 8 : { DrawLab(index); break; } } //--- パレットの境界を描画する DrawPaletteBorder(); //--- パレットを更新する m_canvas.Update(); }
パレットから色を選択したりコントロールに提示したカラーモデルのコンポーネントを設定する場合、すべての編集ボックスの値が自動的に再計算されます。カット(選択されたラジオボタン)が現在のパレットに表示されているコントロールのすべてのカラーモデルの構成要素の計算に使用することができるメソッドが必要です。
初めに、クラスの他の多数のメソッドで呼び出されるRGBコンポーネントとHSLモデルの補修メソッドが必要です。
class CColorPicker : public CElement { private: //--- RGBコンポーネントの補正 void AdjustmentComponentRGB(void); //--- HSLコンポーネントの補正 void AdjustmentComponentHSL(void); }; //+------------------------------------------------------------------+ //| RGBコンポーネントの補正 | //+------------------------------------------------------------------+ void CColorPicker::AdjustmentComponentRGB(void) { m_rgb_r=::fmin(::fmax(m_rgb_r,0),255); m_rgb_g=::fmin(::fmax(m_rgb_g,0),255); m_rgb_b=::fmin(::fmax(m_rgb_b,0),255); } //+------------------------------------------------------------------+ //| HSLコンポーネントの補正 | //+------------------------------------------------------------------+ void CColorPicker::AdjustmentComponentHSL(void) { m_hsl_h*=360; m_hsl_s*=100; m_hsl_l*=100; }
すべてのコンポーネントが計算された後は編集ボックスに新しい値を設定する必要があります。いくつかの場合においては(1)全てのコンポーネント値の設定と、時々(2)現在選択されたもの以外のコンポーネント値の設定が必要とされ得ます。そのために2つのモードでの動作が可能なCColorPicker::SetControls() メソッドが書かれます。
class CColorPicker : public CElement { private: //--- 編集ボックスでの現在のパラメータの設定 void SetControls(const int index,const bool fix_selected); }; //+------------------------------------------------------------------+ //| 編集ボックスでの現在のパラメータの設定 | //+------------------------------------------------------------------+ void CColorPicker::SetControls(const int index,const bool fix_selected) { //--- 値が選択されたラジオボタンの編集ボックスで補正される必要がある場合 if(fix_selected) { //--- HSLコンポーネント if(index!=0) m_hsl_h_edit.ChangeValue(m_hsl_h); if(index!=1) m_hsl_s_edit.ChangeValue(m_hsl_s); if(index!=2) m_hsl_l_edit.ChangeValue(m_hsl_l); //--- RGBコンポーネント if(index!=3) m_rgb_r_edit.ChangeValue(m_rgb_r); if(index!=4) m_rgb_g_edit.ChangeValue(m_rgb_g); if(index!=5) m_rgb_b_edit.ChangeValue(m_rgb_b); //--- Labコンポーネント if(index!=6) m_lab_l_edit.ChangeValue(m_lab_l); if(index!=7) m_lab_a_edit.ChangeValue(m_lab_a); if(index!=8) m_lab_b_edit.ChangeValue(m_lab_b); return; } //--- すべてのカラーモデルの値を編集ボックスで補正する必要がある場合 m_hsl_h_edit.ChangeValue(m_hsl_h); m_hsl_s_edit.ChangeValue(m_hsl_s); m_hsl_l_edit.ChangeValue(m_hsl_l); //--- m_rgb_r_edit.ChangeValue(m_rgb_r); m_rgb_g_edit.ChangeValue(m_rgb_g); m_rgb_b_edit.ChangeValue(m_rgb_b); //--- m_lab_l_edit.ChangeValue(m_lab_l); m_lab_a_edit.ChangeValue(m_lab_a); m_lab_b_edit.ChangeValue(m_lab_b); }
カット(選択されたラジオボタン)が現在のパレットに表示されているコントロールのすべてのカラーモデルの構成要素を計算するにはCColorPicker::SetHSL()、CColorPicker::SetRGB()、CColorPicker::SetLab()の3つの別々のメソッドが書かれます。これらのメソッドの内容は非常に似ているので、ここではそのうち1つであるCColorPicker::SetRGB()のコードのみを示します。 メソッドの冒頭ではRGBモデルの編集ボックスから値のクラスフィールドで値を取得します。取得された値はHSLおよびLab形式に変換されます。最後には コントロールのすべてのカラーモデルで値を設定するモードでCColorPicker::SetControls()メソッドを呼び出します(false)。
class CColorPicker : public CElement { private: //--- (1) HSL、(2) RGB、(3) Labに相対したカラーモデルパラメータの設定 void SetHSL(void); void SetRGB(void); void SetLab(void); }; //+------------------------------------------------------------------+ //| RGB カラーモデルパラメータの設定 | //+------------------------------------------------------------------+ void CColorPicker::SetRGB(void) { //--- RGBコンポーネントの現在値を取得する m_rgb_r=m_rgb_r_edit.GetValue(); m_rgb_g=m_rgb_g_edit.GetValue(); m_rgb_b=m_rgb_b_edit.GetValue(); //--- RGBコンポーネントのHSLコンポーネントへの変換 m_clr.RGBtoHSL(m_rgb_r,m_rgb_g,m_rgb_b,m_hsl_h,m_hsl_s,m_hsl_l); //--- HSLコンポーネントの補正 AdjustmentComponentHSL(); //--- RGBコンポーネントのLabコンポーネントへの変換 m_clr.RGBtoXYZ(m_rgb_r,m_rgb_g,m_rgb_b,m_xyz_x,m_xyz_y,m_xyz_z); m_clr.XYZtoCIELab(m_xyz_x,m_xyz_y,m_xyz_z,m_lab_l,m_lab_a,m_lab_b); //--- 編集ボックスでの現在パラメータの設定 SetControls(0,false); }
最後に、上記されたすべての計算、描画およびコンポーネント値の設定メソッドをコントロールの編集ボックスで呼び出すメインメソッドが必要です。ここではそれはCColorPicker::SetComponents()メソッドです。これも2つのモードで動作します。fix_selected引数がtrueの場合、コンポーネントは選択された色に相対して計算され、, 編集ボックスでの値の設定はコンポーネントで選択されたラジオボタンに相対します。fix_selected引数がfalseの場合、計算は示されたカラーモデルに相対して行われます。計算後にはカラーパレットが再描画されます。
class CColorPicker : public CElement { private: //--- カラーコンポーネントの計算と設定 void SetComponents(const int index,const bool fix_selected); }; //+------------------------------------------------------------------+ //| カラーコンポーネントの計算と設定 | //+------------------------------------------------------------------+ void CColorPicker::SetComponents(const int index=0,const bool fix_selected=true) { //--- コンポーネントで選択されたラジオボタンに対して色を補正する必要がある場合 if(fix_selected) { //--- 選択された色をRGBコンポーネントに分解する m_rgb_r=m_clr.GetR(m_picked_color); m_rgb_g=m_clr.GetG(m_picked_color); m_rgb_b=m_clr.GetB(m_picked_color); //--- RGBコンポーネントをHSLコンポーネントに変換する m_clr.RGBtoHSL(m_rgb_r,m_rgb_g,m_rgb_b,m_hsl_h,m_hsl_s,m_hsl_l); //--- HSLコンポーネントの補正 AdjustmentComponentHSL(); //--- RGBコンポーネントをLABコンポーネントに変換する m_clr.RGBtoXYZ(m_rgb_r,m_rgb_g,m_rgb_b,m_xyz_x,m_xyz_y,m_xyz_z); m_clr.XYZtoCIELab(m_xyz_x,m_xyz_y,m_xyz_z,m_lab_l,m_lab_a,m_lab_b); //--- 編集ボックスで色を設定する SetControls(m_radio_buttons.SelectedButtonIndex(),true); return; } //--- カラーモデルパラメータの設定 switch(index) { case 0 : case 1 : case 2 : SetHSL(); break; case 3 : case 4 : case 5 : SetRGB(); break; case 6 : case 7 : case 8 : SetLab(); break; } //--- 選択されたラジオボタンに対してパレットを描画する DrawPalette(m_radio_buttons.SelectedButtonIndex()); }
すべてのマーカーオブジェクトに割り当てられるパレットの現在の色を設定するにはCColorPicker::CurrentColor()メソッドを書きます。それがどこで使用されるかは本稿で後に明らかになります。
class CColorPicker : public CElement { public: //--- パレットでユーザに選択された色を設定する void CurrentColor(const color clr); }; //+------------------------------------------------------------------+ //| 現在の色の設定 | //+------------------------------------------------------------------+ void CColorPicker::CurrentColor(const color clr) { m_hover_color=clr; m_hover.Color(clr); m_hover.BackColor(clr); m_hover.Tooltip(::ColorToString(clr)); //--- m_picked_color=clr; m_picked.Color(clr); m_picked.BackColor(clr); m_picked.Tooltip(::ColorToString(clr)); //--- m_current_color=clr; m_current.BackColor(clr); m_current.Tooltip(::ColorToString(clr)); }
計算メソッドはすべてそろいました。コントロールイベント処理メソッドに進みます。
コントロールイベント処理メソッド
以下のメソッドはイベントを処理してカラーパレットを管理するために必要となります。
- CColorPicker::OnHoverColor() メソッド — (パレット上の)マウスカーソルの色の取得。マウスカーソルがパレット領域の外にある場合は、プログラムはメソッドを終了します。カーソルが領域にある場合は座標が決定されマウスカーソルの色が取得されます。この新しい色が特別に設計されたマーカーのために設定された直後、マーカーとカラーパレットのグラフィックオブジェクトはColorToString()メソッドをもってRGB形式の色を表す文字列のツールヒントを持ちます。
//+------------------------------------------------------------------+ //| マウスカーソルの色を取得する | //+------------------------------------------------------------------+ bool CColorPicker::OnHoverColor(const int x,const int y) { //--- フォーカスがパレットにない場合は終了する if(!m_canvas.MouseFocus()) return(false); //--- マウスカーソルのパレットの色を定義する int lx =x-m_canvas.X(); int ly =y-m_canvas.Y(); m_hover_color=(color)::ColorToARGB(m_canvas.PixelGet(lx,ly),0); //--- 関連するサンプルで色とツールチップ(マーカー)を設定する m_hover.Color(m_hover_color); m_hover.BackColor(m_hover_color); m_hover.Tooltip(::ColorToString(m_hover_color)); //--- パレットのツールヒントを設定する m_canvas.Tooltip(::ColorToString(m_hover_color)); return(true); }
- CColorPicker::OnClickPalette() メソッドはカラーパレットのクリックを処理します。メソッドの初めにはオブジェクト名が確認されます。クリックがパレット上で発生した場合は、関連するマーカーのマウスカーソルとツールチップの色が保存されて設定されます。メソッドの最終部では コンポーネントの選択されたラジオボタンに対したカラーモデルのコンポーネントの計算と設定のためにCColorPicker::SetComponents()が呼ばれます。
//+------------------------------------------------------------------+ //| カラーパレットのクリックを処理する | //+------------------------------------------------------------------+ bool CColorPicker::OnClickPalette(const string clicked_object) { //--- オブジェクト名が一致しない場合は終了する if(clicked_object!=m_canvas.Name()) return(false); //--- 関連するサンプルで色とツールチップ(マーカー)を設定する m_picked_color=m_hover_color; m_picked.Color(m_picked_color); m_picked.BackColor(m_picked_color); m_picked.Tooltip(::ColorToString(m_picked_color)); //--- 選択されたラジオボタンに対してカラーコンポーネントを計算して設定する SetComponents(); return(true); }
- CColorPicker::OnClickRadioButton()メソッドはラジオボタンのクリックを処理します。まず、(1)要素識別子と(2)ラジオボタンに表示されるテキストによる2つのチェックが完了しなければなりません。条件が満たされた場合は使われているカラーモデルの選択されたコンポーネントに対してカラーパレットが再描画されます。
//+------------------------------------------------------------------+ //| ラジオボタンのクリックを処理する | //+------------------------------------------------------------------+ bool CColorPicker::OnClickRadioButton(const long id,const int button_index,const string button_text) { //--- 識別子が一致しない場合は終了する if(id!=CElement::Id()) return(false); //--- ラジオボタンテキストが一致しない場合は終了する if(button_text!=m_radio_buttons.SelectedButtonText()) return(false); //--- 最近の変更を考慮してパレットを更新する DrawPalette(button_index); return(true); }
- CColorPicker::OnEndEdit()メソッドは編集ボックスでの新しい値の入力を処理します。要素識別子による1つのチェックが十分で、完成後には、現在選択されているコンポーネントのラジオボタンを持つものに対してすべてのカラーモデルのコンポーネントが計算されます。
//+------------------------------------------------------------------+ //| 編集ボックスでの新しい値を処理する | //+------------------------------------------------------------------+ bool CColorPicker::OnEndEdit(const long id,const int button_index) { //--- 識別子が一致しない場合は終了する if(id!=CElement::Id()) return(false); //--- すべてのカラーモデルのカラーコンポーネントを計算して設定する SetComponents(button_index,false); return(true); }
- CColorPicker::OnClickButtonOK()メソッドはOKボタンのクリックを処理します。このメソッドは本稿でさらに改正されるので、これは最終版ではありません。ここで知らなければならないのは、ボタンをクリックすると選択した色が現在の色として保存されることだけです。
//+------------------------------------------------------------------+ //| 「OK」ボタンのクリックを処理する | //+------------------------------------------------------------------+ bool CColorPicker::OnClickButtonOK(const string clicked_object) { //--- オブジェクト名が一致しない場合は終了する if(clicked_object!=m_button_ok.Text()) return(false); //--- 選択された色を保存する m_current_color=m_picked_color; m_current.BackColor(m_current_color); m_current.Tooltip(::ColorToString(m_current_color)); return(true); }
- CColorPicker::OnClickButtonCancel() メソッドはキャンセルボタンのクリックを処理します。このメソッドではオブジェクト名によるチェックが1つあります。その後、コントロールが接続されているフォームがダイアログウィンドウ型である場合、ウィンドウが閉じられます.。
//+------------------------------------------------------------------+ //| 「キャンセル」ボタンのクリックを処理する | //+------------------------------------------------------------------+ bool CColorPicker::OnClickButtonCancel(const string clicked_object) { //--- オブジェクト名が一致しない場合は終了する if(clicked_object!=m_button_cancel.Text()) return(false); //--- ダイアログウィンドウの場合はウィンドウを閉じる if(m_wnd.WindowType()==W_DIALOG) m_wnd.CloseDialogBox(); //--- return(true); }
CColorPicker::OnEvent()カラーパレットのイベントハンドラには全部で6つのブロックがあります。上記リストでみられるすべてのメソッドは、それを目的としたイベント識別子の到着時に呼び出されます。イベントハンドラのコード全体は以下のコードから入手できます。
//+------------------------------------------------------------------+ //| チャートイベントハンドラ //+------------------------------------------------------------------+ void CColorPicker::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_canvas.MouseFocus(x>m_canvas.X() && x<m_canvas.X2()-1 && y>m_canvas.Y() && y<m_canvas.Y2()-1); //--- マウスカーソルの色を取得する if(OnHoverColor(x,y)) return; //--- return; } //--- オブジェクトの左マウスクリックイベントを処理する if(id==CHARTEVENT_OBJECT_CLICK) { //--- パレットがクリックされた場合 if(OnClickPalette(sparam)) return; //--- return; } //--- 編集ボックスでの値の入力を処理する if(id==CHARTEVENT_CUSTOM+ON_END_EDIT) { //--- 新しい値の入力をチェックする if(OnEndEdit(lparam,(int)dparam)) return; //--- return; } //--- コントロールのクリックを処理する if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL) { //--- ラジオボタンがクリックされた場合 if(OnClickRadioButton(lparam,(int)dparam,sparam)) return; //--- return; } //--- 編集ボックスのスウィッチのクリックの処理 if(id==CHARTEVENT_CUSTOM+ON_CLICK_INC || id==CHARTEVENT_CUSTOM+ON_CLICK_DEC) { //--- 新しい値の入力をチェックする if(OnEndEdit(lparam,(int)dparam)) return; //--- return; } //--- コントロールボタンへのクリックの処理 if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON) { //--- 識別子が一致しない場合は終了する if(lparam!=CElement::Id()) return; //--- 「OK」ボタンがクリックされた場合 if(OnClickButtonOK(sparam)) return; //--- 「キャンセル」ボタンがクリックされた場合 if(OnClickButtonCancel(sparam)) return; //--- return; } }
開発中のライブラリの多数のコントロールはFastSwitching()メソッドを持ちます。これは、通常、編集ボックス、リストまたはテーブルのスクロールバーでの値の高速な切り替えに使用されます。しかし、ここでは、コンポーネントの編集ボックスのカウンタの高速での切り替えがアクティブにされた際のカラーパレットの再描画に必要とされています。CColorPicker::FastSwitching()メソッドのコードは本稿に添付されたファイルで参照できます。
カラーボタン
カラーパレット作成クラスの準備はそろいましたが、本格的に使用するためにはまだ1つの要素が不足しています。カラーパレットを持つウィンドウを呼び出すために使用されるボタンです。このボタンは、現在設定されているカラーを参照するためのオプションを持っている必要があります。このようなボタンを作成するためのクラスを記述します。以下のリストは、その複合部分を示します。
- コントロール領域
- 説明付きのテキストラベル
- 選択された色の指標
- ボタン領域
- RGB形式での選択された色の説明
図3 カラーパレットを呼び出すボタンの複合部分
前回の記事ですでに同様のコントロールが考察されたので、ここではこのコードクラスの説明は提供しません。その代わりに、ボタンとカラーパレットが相互作用する部分に進みます。より多くを学ぶためには、本稿添付のアーカイブ内のColorButton.mqhファイルでCColorButtonをご覧ください。
呼び出しのためにはボタンをカラーパレットを繋げる必要があります。これはCColorPickerクラスで格納されるボタンポインタを通して行います。この目的のためにはColorButton.mqhファイルをColorPicker.mqhファイルと結びつけ、カラーパレットを呼ぶためのボタンへのポインタが格納されるCColorButtonクラスのインスタンスを宣言します。
//+------------------------------------------------------------------+ //| ColorPicker.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "Element.mqh" #include "Window.mqh" #include "SpinEdit.mqh" #include "SimpleButton.mqh" #include "RadioButtons.mqh" #include "ColorButton.mqh" //+------------------------------------------------------------------+ //| カラーピッカー作成クラス | //+------------------------------------------------------------------+ class CColorPicker : public CElement { private: //--- カラーピッキング用のコントロールを呼び出すボタンへのポインタ CColorButton *m_color_button; };
ボタンへのポインタを格納するためのパブリックメソッドも必要とされます。呼出ボタンとパレットとの間の相互作用を簡単にするために、ポインタを格納するためにボタンのオブジェクトが送信されるときには、すべてのパレットマーカーにはボタンの現在の色が割り当てられます。その後カラーパレットが取り付けられたウィンドウが開かれます(下のコードを参照)。
class CColorPicker : public CElement { public: //--- カラーパレットを呼び出すボタンへのポインタを格納する void ColorButtonPointer(CColorButton &object); }; //+------------------------------------------------------------------+ //| カラーパレットを呼び出すボタンへのポインタを格納して | //| パレットが取り付けられているウィンドウを開く | //+------------------------------------------------------------------+ void CColorPicker::ColorButtonPointer(CColorButton &object) { //--- ボタンへのポインタを格納する m_color_button=::GetPointer(object); //--- パレットのすべてのマーカーに送信されたボタンの色を設定する CurrentColor(object.CurrentColor()); //--- パレットが取り付けられているウィンドウを開く m_wnd.Show(); }
さらに、ボタンの色を設定して保存するためのメソッドが必要になります。設定した色はボタンのマーカー(指標)に表示され、ボタンテキストでは追加的な情報としてRGB形式の色が文字列で表示されます。
class CColorButton : public CElement { public: //--- パラメータの現在の色を返す/設定する color CurrentColor(void) const { return(m_current_color); } void CurrentColor(const color clr); }; //+------------------------------------------------------------------+ //| パラメータの現在の色を変える | //+------------------------------------------------------------------+ void CColorButton::CurrentColor(const color clr) { m_current_color=clr; m_button_icon.BackColor(clr); m_button_label.Description(::ColorToString(clr)); }
CColorPicker::OnClickButtonOK()メソッドに小規模の追加をします。ボタンへのポインタが設定されている場合には
- ボタンにはパレット上で選択された色が設定されています。
- カラーパレットが取り付けられているウィンドウは閉じることができます。
- 新しい色がパレットで選択されたというメッセージが生成されます。ON_CHANGE_COLORイベントのための新しい識別子がDefines.mqhファイルに含まれる必要があります。このメッセージにはまた (1) コントロールの識別子 (2) 要素インデックス (3) カラーパレットを呼んだボタンのテキストが含まれます。こうすると、イベントハンドラでメッセージがどのボタンを指すかが分かり、イベントを正しく処理するのに役立ちます。
- ボタンへのポインタがゼロ化されます。
ボタンへのポインタが存在しない場合は、端末のログにMQLアプリケーション開発者のために表示されるツールチップを使用したメッセージが表示されることになります。
//+------------------------------------------------------------------+ //| 「OK」ボタンのクリックを処理する | //+------------------------------------------------------------------+ bool CColorPicker::OnClickButtonOK(const string clicked_object) { //--- オブジェクト名が一致しない場合は終了する if(clicked_object!=m_button_ok.Text()) return(false); //--- 選択された色を保存する m_current_color=m_picked_color; m_current.BackColor(m_current_color); m_current.Tooltip(::ColorToString(m_current_color)); //--- 色の選択のためにウィンドウを呼び出すボタンへのポインタが存在する場合 if(::CheckPointer(m_color_button)!=POINTER_INVALID) { //--- ボタンに選択された色を設定する m_color_button.CurrentColor(m_current_color); //--- ウィンドウを閉じる m_wnd.CloseDialogBox(); //--- 関連したメッセージを送信する ::EventChartCustom(m_chart_id,ON_CHANGE_COLOR,CElement::Id(),CElement::Index(),m_color_button.LabelText()); //--- ポインタをリセットする m_color_button=NULL; } else { //--- ポインタがなくてダイアログウィンドウの場合 // コントロールを呼び出すボタンにポインタがないというメッセージを表示する if(m_wnd.WindowType()==W_DIALOG) ::Print(__FUNCTION__," > Non-valid pointer of calling control (CColorButton)."); } //--- return(true); }
カラーパレットの検証を始めるためのすべてがそろいました。
コントロールの検証
検証には前回の記事からの任意のエキスパートアドバイザーが使用できます。コピーを作成してメインメニューとステータス文字列のみを保存しましょう。グラフィカルインターフェースのメインウィンドウ(W_MAIN)で、カラーパレットを持つダイアログウィンドウ(W_DIALOG)を呼び出す5つのボタンを作成します。すなわち、MQLアプリケーション全体に対して1つのカラーパレットを作成するので十分です。カラーパレットのダイアログウィンドウを呼び出すためのボタンがクリックされるたびに、呼び出されるウィンドウは同じです。しかし、呼び出しの時点でのボタンポインタは独立してCColorPicker に送信される必要があります。これがアプリケーションのカスタムクラスでどのように実装されるべきかはさらに示されます。
CProgramと名付けられたカスタムクラスでは、追加的なウィンドウ(CWindow)作成のためのクラスのインスタンス、カラーパレットを呼び出すための5つのボタンCColorButtonとCColorPicker、またそれらをフォームの端からのオフセットを持って作成するメソッドの宣言が必要です。
class CProgram : public CWndEvents { private: //--- フォーム2 - 色を選択するためのカラーパレットウィンドウ CWindow m_window2; //--- カラーパレットウィンドウを呼び出すボタン CColorButton m_color_button1; CColorButton m_color_button2; CColorButton m_color_button3; CColorButton m_color_button4; CColorButton m_color_button5; //--- カラーパレット CColorPicker m_color_picker; //--- private: //--- フォーム2 bool CreateWindow2(const string text); //--- カラーパレットを呼ぶボタン #define COLORBUTTON1_GAP_X (7) #define COLORBUTTON1_GAP_Y (50) bool CreateColorButton1(const string text); #define COLORBUTTON2_GAP_X (7) #define COLORBUTTON2_GAP_Y (75) bool CreateColorButton2(const string text); #define COLORBUTTON3_GAP_X (7) #define COLORBUTTON3_GAP_Y (100) bool CreateColorButton3(const string text); #define COLORBUTTON4_GAP_X (7) #define COLORBUTTON4_GAP_Y (125) bool CreateColorButton4(const string text); #define COLORBUTTON5_GAP_X (7) #define COLORBUTTON5_GAP_Y (150) bool CreateColorButton5(const string text); //--- カラーパレット #define COLORPICKER_GAP_X (1) #define COLORPICKER_GAP_Y (20) bool CreateColorPicker(void); };
カラーパレットを呼び出すためのボタンを作成するメソッドのコードは実質的に同一のため、ここではそのうち1つの例を表示します。唯一の違いは設定後にボタンで表示される初期色の設定と説明テキストでしょう。
//+------------------------------------------------------------------+ //| カラーパレット1を呼び出すボタンを作成する | //+------------------------------------------------------------------+ bool CProgram::CreateColorButton1(const string text) { //--- ウィンドウへのポインタを格納する m_color_button1.WindowPointer(m_window1); //--- 座標 int x=m_window1.X()+COLORBUTTON1_GAP_X; int y=m_window1.Y()+COLORBUTTON1_GAP_Y; //--- 作成前にプロパティを設定する m_color_button1.XSize(195); m_color_button1.YSize(18); m_color_button1.ButtonXSize(100); m_color_button1.ButtonYSize(18); m_color_button1.AreaColor(clrWhiteSmoke); m_color_button1.LabelColor(clrBlack); m_color_button1.BackColor(C'220,220,220'); m_color_button1.BorderColor(clrSilver); m_color_button1.CurrentColor(clrRed); //--- 要素を作成する if(!m_color_button1.CreateColorButton(m_chart_id,m_subwin,text,x,y)) return(false); //--- ベースでのコントロールにポインタを追加する CWndContainer::AddToElementsArray(0,m_color_button1); return(true); }
カラーパレットダイアログウィンドウのフォームを作成するメソッドのコードは ウィンドウタイプ(W_DIALOG)が示されることによってのみメインウィンドウと異なります。加えて、このウィンドウにはその目的を示す独自の画像が設定されます。画像はすべての本稿末尾でアーカイブに添付されています。
//+------------------------------------------------------------------+ //| カラーパレットのフォーム2を作成する | //+------------------------------------------------------------------+ #resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\color_picker.bmp" //--- bool CProgram::CreateWindow2(const string caption_text) { //--- ウィンドウへのポインタを格納する CWndContainer::AddWindow(m_window2); //--- 座標 int x=(m_window2.X()>0) ?m_window2.X() : 30; int y=(m_window2.Y()>0) ?m_window2.Y() : 30; //--- プロパティ m_window2.Movable(true); m_window2.XSize(350); m_window2.YSize(286); m_window2.WindowType(W_DIALOG); m_window2.WindowBgColor(clrWhiteSmoke); m_window2.WindowBorderColor(clrLightSteelBlue); m_window2.CaptionBgColor(clrLightSteelBlue); m_window2.CaptionBgColorHover(clrLightSteelBlue); m_window2.IconFile("Images\\EasyAndFastGUI\\Icons\\bmp16\\color_picker.bmp"); //--- フォームの作成 if(!m_window2.CreateWindow(m_chart_id,m_subwin,caption_text,x,y)) return(false); //--- return(true); }
下記はCProgram::CreateColorPicker()カラーパレット作成メソッドのコードです。コントロールが取り付けられるダイアログウィンドウへのポインタの保存は重要です。コントロールのベースにコントロールポインタを追加する際には要素が接続されているウィンドウのインデックスが送信されなければなりません。この場合それはダイアログウィンドウインデックス [1]です。
//+------------------------------------------------------------------+ //| 色の選択のためのカラーパレットを作成する | //+------------------------------------------------------------------+ bool CProgram::CreateColorPicker(void) { //--- ウィンドウへのポインタを格納する m_color_picker.WindowPointer(m_window2); //--- 座標 int x=m_window2.X()+COLORPICKER_GAP_X; int y=m_window2.Y()+COLORPICKER_GAP_Y; //--- コントロールを作成する if(!m_color_picker.CreateColorPicker(m_chart_id,m_subwin,x,y)) return(false); //--- ベースでのコントロールにポインタを追加する CWndContainer::AddToElementsArray(1,m_color_picker); return(true); }
ボタンをクリックした際にそのポインタがカラーパレットに送信されていることを確認する必要があります。これはCProgram::OnEvent()カスタムクラスのイベントハンドラで行えます。ボタンがクリックされるとON_CLICK_BUTTONイベント識別子を持ったメッセージが生成されます。メッセージにはどちらの CColorButton型のオブジェクトがカラーパレットに送信される必要があるかを定義するのに使われるボタンの記述が含まれます。ボタンオブジェクトが送信された直後には、カラーパレットを持つウィンドウが開き、すべてのマーカーにオブジェクトが送信されたボタンが表示されます。これは下記のコードで実証されています。
//+------------------------------------------------------------------+ //| イベントハンドラ | //+------------------------------------------------------------------+ void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- ボタンクリックイベント if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON) { //--- ボタン1がクリックされた場合 if(sparam==m_color_button1.LabelText()) { m_color_picker.ColorButtonPointer(m_color_button1); return; } //--- ボタン2がクリックされた場合 if(sparam==m_color_button2.LabelText()) { m_color_picker.ColorButtonPointer(m_color_button2); return; } //--- ボタン3がクリックされた場合 if(sparam==m_color_button3.LabelText()) { m_color_picker.ColorButtonPointer(m_color_button3); return; } //--- ボタン4がクリックされた場合 if(sparam==m_color_button4.LabelText()) { m_color_picker.ColorButtonPointer(m_color_button4); return; } //--- ボタン5がクリックされた場合 if(sparam==m_color_button5.LabelText()) { m_color_picker.ColorButtonPointer(m_color_button5); return; } } }
色の選択がカラーパレットの「OK」ボタンのクリックによって確認されると、下記のコードにみられるようにON_CHANGE_COLOR識別子を持ったメッセージが処理されます。
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- カラーパレットを使った色の変更のイベント if(id==CHARTEVENT_CUSTOM+ON_CHANGE_COLOR) { //---コントロールの識別子が一致する場合 if(lparam==m_color_picker.Id()) { //--- ボタン1 からの応答の場合 if(sparam==m_color_button1.LabelText()) { //--- ボタン1を参照するオブジェクトの色を変える... return; } //--- ボタン2からの応答の場合 if(sparam==m_color_button2.LabelText()) { //--- ボタン2を参照するオブジェクトの色を変える... return; } //--- ボタン3からの応答の場合 if(sparam==m_color_button3.LabelText()) { //--- ボタン3を参照するオブジェクトの色を変える... return; } //--- ボタン4からの応答の場合 if(sparam==m_color_button4.LabelText()) { //--- ボタン4を参照するオブジェクトの色を変える... return; } //--- ボタン5からの応答の場合 if(sparam==m_color_button5.LabelText()) { //--- ボタン5を参照するオブジェクトの色を変える... return; } } return; } }
プログラムをコンパイルしてターミナルのチャートにアップロードします。結果は以下のスクリーンショットに見られます。
図4 カラーパレットを呼ぶボタンの検証
メインウィンドウに提示される5つの色ボタンからカラーパレットを呼び出すためのボタンをクリックすると、次のスクリーンショットに示されるようにカラーピッカーウィンドウが開かれます。
図5。カラーピッカー要素の検証
これで、すべてが設計されたように動作します。
おわりに
本稿(記事シリーズ第九部第1章)では、カラーピッカーと呼ばれるグラフィカルインターフェースの複雑な複合コントロールが示されました。カラーパレットを呼び出すための特別なボタンが追加的なコントロールとして作成されました。これで、開発されたライブラリのユーザーは、そのMQLアプリケーションのグラフィカルインターフェースを使用してオブジェクトの色を管理することができます。
次の記事は、プログレスバーや折れ線グラフのようなコントロールのコードクラスの記述を含みます。
以下は、動作検証のためにPC上にダウンロードできる記事シリーズ第九部の資料です。これらのファイルに含まれている資料の使用についてご質問がある場合は、以下のリストにある記事のいずれかでライブラリの開発の詳細をご参照になるか、本稿へのコメント欄でご質問ください。
第九部の記事(チャプター)のリストは下記の通りです。
- グラフィカルインタフェースIX:カラーピッカーコントロール(チャプター1)
- グラフィカルインタフェースIX:プログレスバーと折れ線グラフコントロール(チャプター2)
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/2579
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索