グラフィカルインタフェースX: テキストエディットボックス、ピクチャスライダー、及びシンプルなコントロール(ビルド5)
コンテンツ
- はじめに
- テキストエディットボックス
- テキストエディットボックス作成クラス
- ピクチャスライダー
- ピクチャスライダー作成クラス
- テキストラベルとピクチャ
- フォントを使用するためのCFontsクラス
- 追加的なライブラリ更新
- コントロールを検証するためのアプリケーション
- おわりに
はじめに
このライブラリの目的のより良い理解を得るためにはシリーズ最初のグラフィカルインタフェース I: ライブラリストラクチャの準備(チャプター 1)稿をお読みください。各章の末尾では記事へのリンクの完全なリストがみられます。そこではまた、開発の現段階でのライブラリの完全版をダウンロードすることができます。ファイルはアーカイブと同じディレクトリに配置される必要があります。
この記事では、テキストエディットボックス、ピクチャスライダー、および追加的なシンプルなコントロール(テキストラベルとピクチャ)の新しいコントロールについて検討します。これらは様々な場合に有用です。ライブラリは成長を続けており、新しいコントロールの導入に加えて、以前作成されたものも改善されています。ライブラリは現在多数のユーザによって利用されており、複数のコメントや提案を受けとっています。これらのリクエストの多くは、新しいバージョンのライブラリに実装されています。さらに、特定のアルゴリズムも最適化されてきました。これによりCPU負荷は大幅に減少しています。詳細は本稿で後ほどお話しします。
テキストエディットボックス
これまでのところ、開発されたライブラリにはすでにエディットボックス( CSpinEdit クラス)が含まれていますが、これは数値のみを入力するように設計されています。ここでは、テキストをフィールドに入力できる別のコントロールを追加します。テキストエディットボックスはさまざまな状況で必要になり得ます。例は端末「サンドボックス」のファイルでの文字列検索の作成です。もう1つの選択肢は、MQLアプリケーションのエンドユーザに、取引する銘柄の配列を入力する機能を提供することです。要するに、これは作業に必要な任意のテキストデータが使えます。
テキストエディットボックスのすべてのコンポーネントを列挙しましょう。
- 背景
- アイコン
- 説明
- エディットボックス
図1 テキストエディットボックスのコンポーネント
このコントロールのクラスを詳しく見てみましょう。
テキストエディットボックス作成クラス
すべてのコントロールに標準的なメソッドを持つCTextEditクラスを持ったTextEdit.mqhファイルを作成しライブラリエンジン(WndContainer.mqhファイル)に関連付けます。下にあるのはユーザがカスタマイズできるコントロールプロパティのリストです。
- コントロールの背景色
- アクティブ状態とブロック状態でのコントロールアイコン
- 2つの軸(x、y)に沿ったアイコンのマージン
- コントロールの説明テキスト
- 2つの軸(x、y)に沿ったテキストラベルのマージン
- コントロールの異なる状態にあるテキストの色
- エディットボックスの大きさ
- 2つの軸(x、y)に沿ったエディットボックスのマージン
- 異なる状態のエディットボックスの色及びそのテキストの色
- エディットボックス内のテキストの整列モード(左/右/中央)
- テキスト選択カーソルの表示モード
- エディットボックスの値のリセットモード
//| テキストエディットボックス作成クラス |
//+------------------------------------------------------------------+
class CTextEdit : public CElement
{
private:
//--- コントロールの背景色
color m_area_color;
//--- アクティブ状態とブロック状態でのコントロールアイコン
string m_icon_file_on;
string m_icon_file_off;
//--- アイコンのマージン
int m_icon_x_gap;
int m_icon_y_gap;
//--- エディットボックスの説明テキスト
string m_label_text;
//--- テキストラベルのマージン
int m_label_x_gap;
int m_label_y_gap;
//--- 異なる状態でのテキストの色
color m_label_color;
color m_label_color_hover;
color m_label_color_locked;
color m_label_color_array[];
//--- エディットボックスの現在値
string m_edit_value;
//--- エディットボックスの大きさ
int m_edit_x_size;
int m_edit_y_size;
//--- エディットボックスのマージン
int m_edit_x_gap;
int m_edit_y_gap;
//--- 異なる状態のエディットボックスの色及びそのテキストの色
color m_edit_color;
color m_edit_color_locked;
color m_edit_text_color;
color m_edit_text_color_locked;
color m_edit_text_color_highlight;
//--- 異なる状態にあるエディットボックスフレームの色
color m_edit_border_color;
color m_edit_border_color_hover;
color m_edit_border_color_locked;
color m_edit_border_color_array[];
//--- 値のリセットモード(空の文字列)
bool m_reset_mode;
//--- テキスト選択ポインタの表示モード
bool m_show_text_pointer_mode;
//--- テキストの配置モード
ENUM_ALIGN_MODE m_align_mode;
//---
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; }
//--- (1) 背景色 (2) エディットボックスの説明テキスト (3) テキストレベルのマージン
void AreaColor(const color clr) { m_area_color=clr; }
string LabelText(void) const { return(m_label.Description()); }
void LabelText(const string text) { m_label.Description(text); }
void LabelXGap(const int x_gap) { m_label_x_gap=x_gap; }
void LabelYGap(const int y_gap) { m_label_y_gap=y_gap; }
//--- 異なる状態にあるテキストラベルの色
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 EditXGap(const int x_gap) { m_edit_x_gap=x_gap; }
void EditYGap(const int y_gap) { m_edit_y_gap=y_gap; }
//--- 異なる状態にあるエディットボックスの色
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 EditTextColorHighlight(const color clr) { m_edit_text_color_highlight=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) テキスト選択ポインタの表示モード
bool ResetMode(void) { return(m_reset_mode); }
void ResetMode(const bool mode) { m_reset_mode=mode; }
void ShowTextPointerMode(const bool mode) { m_show_text_pointer_mode=mode; }
//--- テキスト配置モード
void AlignMode(ENUM_ALIGN_MODE mode) { m_align_mode=mode; }
//--- ボタンがアクティブ及びブロックされた状態でのアイコンの設定
void IconFileOn(const string file_path);
void IconFileOff(const string file_path);
};
テキスト選択ポインタの表示モードは、マウスカーソルがエディットボックスの上をホバーすると、テキストボックスにテキストを入力できることを示す追加アイコンで補完されることを意味します。この機能のために、もう1つの識別子( MP_TEXT_SELECT )が ENUM_MOUSE_POINTER 列挙体に追加されました。
//| ポインタタイプの列挙 |
//+------------------------------------------------------------------+
enum ENUM_MOUSE_POINTER
{
MP_CUSTOM =0,
MP_X_RESIZE =1,
MP_Y_RESIZE =2,
MP_XY1_RESIZE =3,
MP_XY2_RESIZE =4,
MP_X_SCROLL =5,
MP_Y_SCROLL =6,
MP_TEXT_SELECT =7
};
CPointerクラスはこれに対応して変更されました(コードは下記参照)。テキスト選択のカーソルアイコンの画像は、本稿末尾のアーカイブにあります。
//| Pointer.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
//--- リソース
...
#resource "\\Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp"
//+------------------------------------------------------------------+
//| カーソルタイプに基づいてカーソルアイコンを設定する |
//+------------------------------------------------------------------+
void CPointer::SetPointerBmp(void)
{
switch(m_type)
{
case MP_X_RESIZE :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_x_rs_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_x_rs.bmp";
break;
case MP_Y_RESIZE :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_y_rs_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_y_rs.bmp";
break;
case MP_XY1_RESIZE :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_xy1_rs_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_xy1_rs.bmp";
break;
case MP_XY2_RESIZE :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_xy2_rs_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_xy2_rs.bmp";
break;
case MP_X_SCROLL :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_x_scroll_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_x_scroll.bmp";
break;
case MP_Y_SCROLL :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_y_scroll_blue.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_y_scroll.bmp";
break;
case MP_TEXT_SELECT :
m_file_on ="Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp";
m_file_off ="Images\\EasyAndFastGUI\\Controls\\pointer_text_select.bmp";
break;
}
//--- カスタムタイプ(MP_CUSTOM)が指定された場合
if(m_file_on=="" || m_file_off=="")
::Print(__FUNCTION__," > Both icons must be set for the cursor!");
}
テキストボックスの作成には、5つのprivateメソッドと1つのpublicメソッドが必要です。
{
private:
//--- エディットボックス作成オブジェクト
CRectLabel m_area;
CBmpLabel m_icon;
CLabel m_label;
CEdit m_edit;
CPointer m_text_select;
//---
public:
//--- エディットボックス作成メソッド
bool CreateTextEdit(const long chart_id,const int subwin,const string label_text,const int x,const int y);
//---
private:
bool CreateArea(void);
bool CreateIcon(void);
bool CreateLabel(void);
bool CreateEdit(void);
bool CreateTextSelectPointer(void);
};
CTextEditの残りは、このシリーズの前回の記事ですでに取り上げられてきたものだけです。ご自身でその機能をお調べください。現在のバージョンのテキストエディットボックスには 63文字という制限があります。
ピクチャスライダー
ピクチャスライダーは、グラフィカルインターフェイスの情報コントロールに属します。クイックリファレンスガイドの作成は便利です。ここでは、価格チャートの特定の状況や、使用されているMQLアプリケーションのグラフィカルインターフェイスの特定のコントロールの目的について簡単に説明できます。
ピクチャスライダーのすべてのコンポーネントを列挙しましょう。
- 背景
- スライダー矢印ボタン
- ラジオボタングループ
- ラジオボタングループに関連付けられた画像グループ
図2 ピクチャスライダーのコンポーネント
ピクチャスライダー作成クラス
他のクラスに存在する標準的なメソッドを持つPicturesSlider.mqhファイルを作成してWndContainer.mqhファイルに含みます。以下は、ユーザがカスタマイズできるコントロールのプロパティです。
- コントロールの背景色
- コントロールの背景フレームの色
- Y軸に沿った画像マージン
- 2つの軸(x、y)に沿ったスライダー矢印のマージン
- 2つの軸(x、y)に沿ったラジオボタンのマージン
- ラジオボタン間のマージン
//| ピクチャスライダー作成クラス |
//+------------------------------------------------------------------+
class CPicturesSlider : public CElement
{
private:
//--- 背景色と背景フレームの色
color m_area_color;
color m_area_border_color;
//--- Y軸に沿った画像マージン
int m_pictures_y_gap;
//--- ボタンのマージン
int m_arrows_x_gap;
int m_arrows_y_gap;
//--- ラジオボタンのマージン
int m_radio_buttons_x_gap;
int m_radio_buttons_y_gap;
int m_radio_buttons_x_offset;
//---
public:
//--- (1) 背景色 (2) 背景フレームの色
void AreaColor(const color clr) { m_area_color=clr; }
void AreaBorderColor(const color clr) { m_area_border_color=clr; }
//--- 矢印ボタンのマージン
void ArrowsXGap(const int x_gap) { m_arrows_x_gap=x_gap; }
void ArrowsYGap(const int y_gap) { m_arrows_y_gap=y_gap; }
//--- Y軸に沿った画像マージン
void PictureYGap(const int y_gap) { m_pictures_y_gap=y_gap; }
//--- (1) ラジオボタンのマージン (2) ラジオボタン間の距離
void RadioButtonsXGap(const int x_gap) { m_radio_buttons_x_gap=x_gap; }
void RadioButtonsYGap(const int y_gap) { m_radio_buttons_y_gap=y_gap; }
void RadioButtonsXOffset(const int x_offset) { m_radio_buttons_x_offset=x_offset; }
};
ピクチャスライダーの作成には、5つのprivateメソッドと1つのpublicメソッドが必要です。
{
private:
//--- コントロール作成のためのオブジェクト
CRectLabel m_area;
CBmpLabel m_pictures[];
CRadioButtons m_radio_buttons;
CIconButton m_left_arrow;
CIconButton m_right_arrow;
//---
public:
//--- コントロール作成メソッド
bool CreatePicturesSlider(const long chart_id,const int subwin,const int x,const int y);
//---
private:
bool CreateArea(void);
bool CreatePictures(void);
bool CreateRadioButtons(void);
bool CreateLeftArrow(void);
bool CreateRightArrow(void);
};
コントロールの幅は、ユーザー定義のパラメータに基づいて自動的に計算されます。これらのパラメータには、コントロールの左端からのラジオボタンのグループのマージンもふくまれ、ピクチャスライダーの右矢印ボタンの座標はこれに相対して計算されます。コントロールの高さも画像サイズに依存します。画像サイズは同じであると仮定されているので、計算はグループの最初の画像のサイズを使用します。
コントロールを作成するためのメインメソッドを呼び出す前に、CPicturesSlider :: AddPicture ()メソッドを使用して画像を配列に追加する必要があります。画像へのパスがこのメソッドの唯一の引数として設定されていない場合はデフォルトパスが適用されます。
//| PicturesSlider.mqh |
//| Copyright 2016, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
...
//--- デフォルト画像
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp"
//+------------------------------------------------------------------+
//| ピクチャスライダー作成クラス |
//+------------------------------------------------------------------+
class CPicturesSlider : public CElement
{
private:
//--- 画像の配列(画像へのパス)
string m_file_path[];
//--- 画像へのデフォルトパス
string m_default_path;
//---
public:
//--- 画像を追加する
void AddPicture(const string file_path="");
};
//+------------------------------------------------------------------+
//| コンストラクタ |
//+------------------------------------------------------------------+
CPicturesSlider::CPicturesSlider(void) : m_default_path("Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp"),
m_area_color(clrNONE),
m_area_border_color(clrNONE),
m_arrows_x_gap(2),
m_arrows_y_gap(2),
m_radio_button_width(12),
m_radio_buttons_x_gap(25),
m_radio_buttons_y_gap(1),
m_radio_buttons_x_offset(20),
m_pictures_y_gap(25)
{
//--- コントロールクラス名を基本クラスに格納する
CElement::ClassName(CLASS_NAME);
//--- 左マウスクリックの優先順位を設定する
m_zorder=0;
}
//+------------------------------------------------------------------+
//| 画像を追加する |
//+------------------------------------------------------------------+
void CPicturesSlider::AddPicture(const string file_path="")
{
//--- 配列サイズを1要素で増やす
int array_size=::ArraySize(m_pictures);
int new_size=array_size+1;
::ArrayResize(m_pictures,new_size);
::ArrayResize(m_file_path,new_size);
//--- 受け取ったパラメータの値を格納する
m_file_path[array_size]=(file_path=="")?m_default_path : file_path;
}
グループの画像を表示するにはCPicturesSlider::SelectPicture() メソッドを使用します。このメソッドは矢印ボタンとラジオボタンを押すと CPicturesSlider クラスのハンドラで呼び出されます。
{
public:
//--- 指定されたインデックスで画像を切り替える
void SelectPicture(const uint index);
};
//+------------------------------------------------------------------+
//| 表示される画像を指定する |
//+------------------------------------------------------------------+
void CPicturesSlider::SelectPicture(const uint index)
{
//--- 画像数を取得する
uint pictures_total=PicturesTotal();
//--- グループに画像がない場合は報告する
if(pictures_total<1)
{
::Print(__FUNCTION__," > This method is to be called, "
"if a group contains at least one picture!Use the CPicturesSlider::AddPicture() method");
return;
}
//--- 配列の範囲を超えた場合、インデックス値を調整する
uint correct_index=(index>=pictures_total)?pictures_total-1 : index;
//--- このインデックスでラジオボタンを選択する
m_radio_buttons.SelectRadioButton(correct_index);
//--- 画像へ切り替える
for(uint i=0; i<pictures_total; i++)
{
if(i==correct_index)
m_pictures[i].Timeframes(OBJ_ALL_PERIODS);
else
m_pictures[i].Timeframes(OBJ_NO_PERIODS);
}
}
矢印ボタンを押すと、コントロールのイベントハンドラがCPicturesSlider :: OnClickLeftArrow () メソッドとCPicturesSlider :: OnClickRightArrow () メソッドを呼び出します。下のリストは、左マウスボタンのメソッドのコードを示しています。ピクチャスライダーボタンをクリックするイベントは、必要に応じてMQLアプリケーションのカスタムクラスでトレースできます。
{
public:
private:
//--- 左ボタンのクリックの処理
bool OnClickLeftArrow(const string clicked_object);
//--- 右ボタンのクリックの処理
bool OnClickRightArrow(const string clicked_object);
};
//+------------------------------------------------------------------+
//| 左ボタンのクリックの処理 |
//+------------------------------------------------------------------+
bool CPicturesSlider::OnClickLeftArrow(const string clicked_object)
{
//--- クリックされたのがボタンでなければ終了する
if(::StringFind(clicked_object,CElement::ProgramName()+"_icon_button_",0)<0)
return(false);
//--- オブジェクト名からコントロールの識別子を取得する
int id=CElement::IdFromObjectName(clicked_object);
//--- オブジェクト名からコントロールのインデックスを取得する
int index=CElement::IndexFromObjectName(clicked_object);
//--- コントロールの識別子が一致しない場合は終了する
if(id!=CElement::Id())
return(false);
//--- コントロールのインデックスが一致しない場合は終了する
if(index!=0)
return(false);
//--- 選択されたラジオボタンの現在のインデックスを取得する
int selected_radio_button=m_radio_buttons.SelectedButtonIndex();
//--- 画像を切り替える
SelectPicture(--selected_radio_button);
//--- それについてのメッセージを送信する
::EventChartCustom(m_chart_id,ON_CLICK_BUTTON,CElement::Id(),CElement::Index(),"");
return(true);
}
下記はピクチャスライダーのイベントハンドラの短縮コードを一覧します。スライダのラジオボタンをクリックしたイベントもここで追跡されることは明らかです。コントロール識別子がピクチャスライダーの識別子と等しいとローカルグループ内のラジオボタンがクリックされたことを理解することができます。
//| イベントハンドラ |
//+------------------------------------------------------------------+
void CPicturesSlider::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- カーソル移動イベントの処理
...
//--- ラジオボタンのクリックイベントの処理
if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL)
{
//--- これがスライダーのラジオボタンの場合は画像を切り替える
if(lparam==CElement::Id())
SelectPicture(m_radio_buttons.SelectedButtonIndex());
//---
return;
}
//--- オブジェクトのマウス左クリックイベントの処理
if(id==CHARTEVENT_OBJECT_CLICK)
{
//--- スライダーの矢印ボタンがクリックされた場合は画像を切り替える
if(OnClickLeftArrow(sparam))
return;
if(OnClickRightArrow(sparam))
return;
//---
return;
}
}
テキストラベルとピクチャ
補足として、ライブラリにはシンプルなテキストラベルと画像を作成するための新しい CTextLabelと CPictureクラスの2つが含まれています。これらは、他のコントロールにバインドすることなく独立したオブジェクトとして使用できます。内容はとても簡単です。CPictureクラスでユーザが変更できるのは画像へのパスを示す1プロパティだけです。このためにはCPicture::Path()メソッドが実装されています。カスタムパスが指定されていなければデフォルト画像が使用されます。ピクチャは、MQLアプリケーションのグラフィカルインタフェースの作成後も、いつでもプログラムで変更することができます。
//| Picture.mqh |
//| Copyright 2016, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Element.mqh"
#include "Window.mqh"
//--- リソース
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp"
//+------------------------------------------------------------------+
//| 画像作成クラス |
//+------------------------------------------------------------------+
class CPicture : public CElement
{
private:
//--- 画像へのパス
string m_path;
//---
public:
//--- 画像へのパスの取得/設定
string Path(void) const { return(m_path); }
void Path(const string path);
};
//+------------------------------------------------------------------+
//| コンストラクタ |
//+------------------------------------------------------------------+
CPicture::CPicture(void) : m_path("Images\\EasyAndFastGUI\\Icons\\bmp64\\no_image.bmp")
{
//--- コントロールクラス名を基本クラスに格納する
CElement::ClassName(CLASS_NAME);
//--- 左マウスクリックの優先順位を設定する
m_zorder=0;
}
//+------------------------------------------------------------------+
//| 画像を設定する |
//+------------------------------------------------------------------+
void CPicture::Path(const string path)
{
m_path=path;
m_picture.BmpFileOn("::"+path);
m_picture.BmpFileOff("::"+path);
}
テキストラベルでは、すべてが非常に単純で、ユーザが定義できるプロパティは4つだけです。
- ラベルのテキスト
- テキストの色
- フォント
- フォントサイズ
//| テキストラベル作成クラス |
//+------------------------------------------------------------------+
class CTextLabel : public CElement
{
public:
//--- ラベルテキストを取得/設定する
string LabelText(void) const { return(m_label.Description()); }
void LabelText(const string text) { m_label.Description(text); }
//--- テキストラベルの (1) 色 (2) フォント (3) フォントサイズの設定
void LabelColor(const color clr) { m_label.Color(clr); }
void LabelFont(const string font) { m_label.Font(font); }
void LabelFontSize(const int size) { m_label.FontSize(size); }
};
フォントを使用するためのCFontsクラス
フォントの選択を容易にするために、CFontsクラスが実装されています。これは187フォントを含みます。これらは端末のシステムフォントです。これは特定のグラフィックオブジェクトの設定で一覧できると思われます。
図3 端末のシステムフォント
フォントファイル(Fonts.mqh)は "MetaTrader 5\MQL5\Include\EasyAndFastGUI\Fonts.mqh"ディレクトリに位置します。このファイルはライブラリのスキーム全体で完全にアクセスできるようにObjects.mqhファイルにインクルードされています。
//| Objects.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Enums.mqh"
#include "Defines.mqh"
#include "..\Fonts.mqh"
#include "..\Canvas\Charts\LineChart.mqh"
#include <ChartObjects\ChartObjectSubChart.mqh>
#include <ChartObjects\ChartObjectsBmpControls.mqh>
#include <ChartObjects\ChartObjectsTxtControls.mqh>
CFontsクラスに含まれているのはフォント配列のサイズの取得とインデックスによるフォントの取得のための2つのパブリックメソッドのみです。フォントの配列はクラスコンストラクタで初期化されています。
//| Fonts.mqh |
//| Copyright 2016, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| フォントを使用するためのクラス |
//+------------------------------------------------------------------+
class CFonts
{
private:
//--- フォントの配列
string m_fonts[];
//---
public:
CFonts(void);
~CFonts(void);
//--- フォント数を返す
int FontsTotal(void) const { return(::ArraySize(m_fonts)); }
//--- フォントをインデックスで返す
string FontsByIndex(const uint index);
//---
private:
//--- フォントの配列を初期化する
void InitializeFontsArray(void);
};
//+------------------------------------------------------------------+
//| コンストラクタ |
//+------------------------------------------------------------------+
CFonts::CFonts(void)
{
//--- フォントの配列を初期化する
InitializeFontsArray();
}
//+------------------------------------------------------------------+
//| デストラクタ |
//+------------------------------------------------------------------+
CFonts::~CFonts(void)
{
::ArrayFree(m_fonts);
}
CFonts::FontsByIndex()メソッドが呼び出されると配列サイズの超過を予防するための調整が行われます。:
//| フォントをインデックスで返す |
//+------------------------------------------------------------------+
string CFonts::FontsByIndex(const uint index)
{
//--- 配列サイズ
uint array_size=FontsTotal();
//--- サイズが超過した場合の調整
uint i=(index>=array_size)?array_size-1 : index;
//--- フォントを返す
return(m_fonts[i]);
}
追加的なライブラリ更新
1. ダイアログボックスにツールヒントが正しく表示されない問題を修正しました。これで、メインウィンドウのツールヒントボタンが押された状態が、グラフィカルインタフェースのすべてのウィンドウに適用されます。ボタンを押すと、新しい ON_WINDOW_TOOLTIPSイベント識別子を持つメッセージが生成されます( Defines.mqh ファイルを参照)。
//| Defines.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
...
#define ON_WINDOW_TOOLTIPS (29) // ツールヒントボタンのクリック
したがって、ツールヒントの処理のためにOnClickTooltipsButton()メソッドがCWindowクラスに追加されました。
//| コントロールフォーム作成クラス |
//+------------------------------------------------------------------+
class CWindow : public CElement
{
private:
//--- ツールヒントボタンクリックのイベントの処理
bool OnClickTooltipsButton(const string clicked_object);
};
//+------------------------------------------------------------------+
//| チャートイベントハンドラ |
//+------------------------------------------------------------------+
void CWindow::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- オブジェクトクリックイベントの処理
if(id==CHARTEVENT_OBJECT_CLICK)
{
//--- ツールヒントボタンがクリックされた場合
if(OnClickTooltipsButton(sparam))
return;
}
}
//+------------------------------------------------------------------+
//| ツールヒントボタンクリックのイベントの処理 |
//+------------------------------------------------------------------+
bool CWindow::OnClickTooltipsButton(const string clicked_object)
{
//--- ウィンドウがダイアログボックスの場合はこのボタンは必須でない
if(m_window_type==W_DIALOG)
return(false);
//--- クリックされたのがラジオボタンでなければ終了する
if(::StringFind(clicked_object,CElement::ProgramName()+"_window_tooltip_",0)<0)
return(false);
//--- オブジェクト名からコントロールの識別子を取得する
int id=CElement::IdFromObjectName(clicked_object);
//--- コントロールの識別子が一致しない場合は終了する
if(id!=CElement::Id())
return(false);
//--- 状態をクラスフィールドに収納する
m_tooltips_button_state=m_button_tooltip.State();
//--- それについてのメッセージを送信する
::EventChartCustom(m_chart_id,ON_WINDOW_TOOLTIPS,CElement::Id(),CElement::Index(),"");
return(true);
}
このすべてがライブラリエンジン(CWndEventsクラス)で機能するためには ON_WINDOW_TOOLTIPS 識別子を持つイベントを処理する OnWindowTooltips () メソッドが追加されました :
{
private:
//--- ツールヒントの有効/無効化
bool OnWindowTooltips(void);
};
//+------------------------------------------------------------------+
//| CHARTEVENT_CUSTOMイベント |
//+------------------------------------------------------------------+
void CWndEvents::ChartEventCustom(void)
{
//--- フォーム最小化のシグナルの場合
//--- フォーム最大化のシグナルの場合
//--- シグナルがX軸に沿ってコントロールのサイズを変えるための場合
//--- シグナルがY軸に沿ってコントロールのサイズを変えるための場合
//--- シグナルがツールヒントの有効/無効化のための場合
if(OnWindowTooltips())
return;
//--- 開始項目の下のコンテキストメニューを非表示にするシグナルの場合
//--- すべてのコンテキストメニューを非表示にするシグナルの場合
//--- ダイアログウィンドウを開くシグナルの場合
//--- ダイアログウィンドウを閉じるシグナルの場合
//--- 指定されたフォームの要素の色をすべてゼロにするシグナルの場合
//--- マウスの左クリックの優先順位をリセットするシグナルの場合
//--- マウスの左クリックの優先順位を復元するシグナルの場合
}
//+------------------------------------------------------------------+
//| ON_WINDOW_TOOLTIPSイベント |
//+------------------------------------------------------------------+
bool CWndEvents::OnWindowTooltips(void)
{
//--- ツールヒントの有効/無効化シグナルの場合
if(m_id!=CHARTEVENT_CUSTOM+ON_WINDOW_TOOLTIPS)
return(false);
//--- ウィンドウの識別子が一致した場合
if(m_lparam!=m_windows[0].Id())
return(true);
//--- すべてのウィンドウでツールヒントモードを同期させる
int windows_total=WindowsTotal();
for(int w=0; w<windows_total; w++)
{
if(w>0)
m_windows[w].TooltipButtonState(m_windows[0].TooltipButtonState());
}
//---
return(true);
}
2. 以下のコントロールの作成後に説明のテキストを変更する機能が追加されました。
図4 作成後にテキストを変更できるコントロールのリスト
3. 必要な場合すべてのコントロールでアイコンを設定できるようになりました(下の表を参照)。さらに、作成後にコントロールアイコンを変更する機能が追加されました。
図5 作成後にアイコンを変更できるコントロールのリスト
上の表のすべてのコントロールのアイコンを置き換えるにはIconFileOn() およびIconFileOff()メソッドが存在します。
4. 作成後に全タイプのボタンとタブの状態(押されている/いない)をプログラムで管理する機能が追加されました。次の表はこの追加を含むコントロールを示します。
図6。作成後に状態(押されている/いない)が変更できるコントロールのリスト
5. 下記のコントロールの上にマウスカーソルがホバーされたときに項目を強調表示するアルゴリズムを最適化しました。
図7 項目の強調表示アルゴリズムが最適化されたコントロール
プログラムは以前は上記のコントロールのリスト内のすべての項目を反復処理してマウスカーソルの位置を確認していました。したがって、カーソル下の項目は異なる色で強調表示され、項目の残りの部分はデフォルト色に設定されていました。しかし、この方法は非常にリソース集中的なので、最適化する必要がありました。今度は、項目の配列全体を反復処理する代わりに、色の変更には2つの項目のみが関与します。サイクル内の検索は、別の項目への遷移があったとき、つまりフォーカスが変更されたときにのみ行われます。
さらに、例として、CListViewクラスでこれがどのように実装されたかを考えてみましょう。上記を実装するには、(1)最後にフォーカスを当てたアイテムのインデックスを格納するm_prev_item_index_focusクラスフィールドと (2)項目へのフォーカスを確認するCListView :: CheckItemFocus()メソッドの追加と (3) CListView :: ChangeItemsColor >() メソッドのアルゴリズムの変更が必要です。
//| リストビュー作成クラス |
//+------------------------------------------------------------------+
class CListView : public CElement
{
private:
//--- ある項目から別の項目へのマウスカーソルの移動の瞬間を判断する
int m_prev_item_index_focus;
//---
private:
//--- カーソルが上をホバーしたらリストビュー項目の色を変更する
void ChangeItemsColor(void);
//--- カーソルが上をホバーしたらリストビュー項目のフォーカスを確認する
void CheckItemFocus(void);
};
CListView ::CheckItemFocus() メソッドは、マウスカーソルがコントロール(この場合はCListView)の領域内に入ったとき及びある項目から別の項目に変更されたときだけに呼び出されます (以下のコードを参照)。マウスがホバーしている項目が見つかると、そのインデックスが保存されます。
//| カーソルが上をホバーしたらリストビュー項目のフォーカスを確認する |
//+------------------------------------------------------------------+
void CListView::CheckItemFocus(void)
{
//--- スクロールバースライダーの現在位置を取得する
int v=m_scrollv.CurrentPos();
//--- カーソルがホバーしている項目を特定して強調表示する
for(int i=0; i<m_visible_items_total; i++)
{
//--- リストビューの範囲を超えていない場合はカウンタを増やす
if(v>=0 && v<m_items_total)
v++;
//--- 選択された項目をスキップする
if(m_selected_item_index==v-1)
{
m_items[i].BackColor(m_item_color_selected);
m_items[i].Color(m_item_text_color_selected);
continue;
}
//--- カーソルがこの項目でホバーしている場合は強調表示する
if(m_mouse.X()>m_items[i].X() && m_mouse.X()<m_items[i].X2() &&
m_mouse.Y()>m_items[i].Y() && m_mouse.Y()<m_items[i].Y2())
{
m_items[i].BackColor(m_item_color_hover);
m_items[i].Color(m_item_text_color_hover);
//--- 項目を記憶する
m_prev_item_index_focus=i;
break;
}
}
}
CListView::CheckItemFocus()メソッドは上記のケースでCListView::ChangeItemsColor()メソッドの中から呼び出されます (以下のコードを参照)。
//| カーソルが上をホバリングした時のリストビュー項目の色の変更 |
//+------------------------------------------------------------------+
void CListView::ChangeItemsColor(void)
{
//--- カーソルがホバーした時の項目の強調表示が有効になっていないかスクロールバーがアクティブな場合には終了する
if(!m_lights_hover || m_scrollv.ScrollState())
return;
//--- これがドロップダウン要素ではなくフォームがブロックされている場合には終了する
if(!CElement::IsDropdown() && m_wnd.IsLocked())
return;
//--- 再びリストビューの場合
if(m_prev_item_index_focus==WRONG_VALUE)
{
//--- 現在の項目上のフォーカスを確認する
CheckItemFocus();
}
else
{
//--- 現在の行上のフォーカスを確認する
int i=m_prev_item_index_focus;
bool condition=m_mouse.X()>m_items[i].X() && m_mouse.X()<m_items[i].X2() &&
m_mouse.Y()>m_items[i].Y() && m_mouse.Y()<m_items[i].Y2();
//--- 他の項目に動いた場合
if(!condition)
{
//--- 前の項目の色をリセットする
m_items[i].BackColor(m_item_color);
m_items[i].Color(m_item_text_color);
m_prev_item_index_focus=WRONG_VALUE;
//--- 新しい項目の色をリセットする
CheckItemFocus();
}
}
}
CListView::OnEvent()イベントハンドラではCListView::ChangeItemsColor()メソッドはマウスカーソルがコントロールの領域内にあるときのみに呼び出されます。 カーソルがコントロール領域を離れると、デフォルトの色が設定されて項目のインデックス値がリセットされます。イベントハンドラの短縮版を以下に示します。
//| イベントハンドラ |
//+------------------------------------------------------------------+
void CListView::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- カーソル移動イベントの処理
if(id==CHARTEVENT_MOUSE_MOVE)
{
//--- 要素が隠れている場合は終了する
//--- サブウィンドウの番号が一致しない場合は終了する
//--- 要素上のフォーカスの確認
//--- これはドロップダウンリストでマウスボタンが押下されている
//--- スライダーの管理が有効になっている場合はリストを移動する
//--- フォーカスされていない場合は要素の色をリセットする
if(!CElement::MouseFocus())
{
//--- 項目がすでにフォーカスされている
if(m_prev_item_index_focus!=WRONG_VALUE)
{
//--- リストビューの色をリセットする
ResetColors();
m_prev_item_index_focus=WRONG_VALUE;
}
return;
}
//--- カーソルが上をホバーしたらリストビュー項目の色を変更する
ChangeItemsColor();
return;
}
}
CTable、CCalendar、CTreeViewクラスでも同じ原則が実装されていますが、各コントロールの特性が考慮されています。
6. 2状態モード(クリックしてからボタンを放していない状態)でCIconButtonタイプのボタンを押すと、別のアイコンが表示されます(設定されている場合)。押されたボタンのアイコンはCIconButton :: IconFilePressedOn()とCIconButton :: IconFilePressedOff()メソッドを使用して設定できます。
//| アイコンボタン作成クラス |
//+------------------------------------------------------------------+
class CIconButton : public CElement
{
private:
//--- ボタンのアクティブ、ブロックされた及び押された状態を示すアイコン
string m_icon_file_on;
string m_icon_file_off;
string m_icon_file_pressed_on;
string m_icon_file_pressed_off;
//---
public:
//--- ボタンが押された、アクティブ及びブロックされた状態でのアイコンの設
void IconFileOn(const string file_path);
void IconFileOff(const string file_path);
void IconFilePressedOn(const string file_path);
void IconFilePressedOff(const string file_path);
};
//+------------------------------------------------------------------+
//| 押された"ON"の状態のアイコンを設定する |
//+------------------------------------------------------------------+
void CIconButton::IconFilePressedOn(const string file_path)
{
//--- ボタンの2状態モードが無効な場合は終了する
if(!m_two_state)
return;
//--- 画像へのパスを格納する
m_icon_file_pressed_on=file_path;
//--- ボタンが押下されているかを即時決定する
if(m_button.State())
m_icon.BmpFileOn("::"+file_path);
}
//+------------------------------------------------------------------+
//| 押された"OFF"の状態のアイコンを設定する |
//+------------------------------------------------------------------+
void CIconButton::IconFilePressedOff(const string file_path)
{
//--- ボタンの2状態モードが無効な場合は終了する
if(!m_two_state)
return;
//--- 画像へのパスを格納する
m_icon_file_pressed_off=file_path;
//--- ボタンが押下されているかを即時決定する
if(m_button.State())
m_icon.BmpFileOff("::"+file_path);
}
7. テーブル(CTable)の行をプログラムで選択する機能を追加しました。このためにはCTable::SelectRow()メソッドを使用します。すでに選択されている行のインデックスを指定すると選択が解除されます。
//| エディットボックステーブル作成クラス |
//+------------------------------------------------------------------+
class CTable : public CElement
{
public:
//--- テーブルの指定された行を選択する
void SelectRow(const uint row_index);
};
//+------------------------------------------------------------------+
//| テーブルの指定された行を選択する |
//+------------------------------------------------------------------+
void CTable::SelectRow(const uint row_index)
{
//--- 範囲を超過した場合の調整
uint index=(row_index>=(uint)m_rows_total)?m_rows_total-1 : row_index;
//--- この行がすでに選択されている場合は選択を解除する
bool is_selected=(index==m_selected_item);
//--- 行のインデックスを格納する
m_selected_item=(is_selected)?WRONG_VALUE : (int)index;
//--- セルの行を格納する
m_selected_item_text=(is_selected)?"" : m_vcolumns[0].m_vrows[index];
//--- セルパラメータで文字列を生成する
string cell_params=string(0)+"_"+string(index)+"_"+m_vcolumns[0].m_vrows[index];
//--- フォーカスをリセットする
m_prev_item_index_focus=WRONG_VALUE;
//--- テーブルを更新する
UpdateTable();
//--- 選択された行を強調表示する
HighlightSelectedItem();
}
8. CIconTabs コントロールの選択されたタブでの要素表示の問題を修正しました。問題はこのタイプのタブを持つフォームを開いて最大化するときに発生していました。
コントロールを検証するためのアプリケーション
テストアプリケーションを作成しましょう。そこでは、自分で新しいコントロールをすべてテストして練習を行い、異なるモードを評価することができます。アプリケーションのグラフィカルインターフェイスで、次の内容をもつ4つのタブを含むタブコントロール(CTabsクラス)を作成します。
1. 1番目のタブ:
- プログレスバー(CProgressBar)
- テキストエディットボックス(CTextEdit)
- ドロップダウンリストを持つコンボボックス(CCombobox)
- 数値のためのスピンエディットボックス(CSpinEdit)
- カラーピッカーを呼び出すボタン( CColorButton )
- テキストラベル(CTextLabel)
テキストラベル以外のすべてのコントロールのアイコンを設定します。プログレスバーとテキストエディットボックスのコントロールの説明は、そのような機能が利用可能であることを示すために、一定の時間間隔で変更されます。CFontsクラスのすべてのフォントの名前をコンボボックスのリストに置きます。MQLテストアプリケーションのイベントモデルは、コンボボックスからのフォント選択がテキストラベルに反映されるように構築されます。同様に、テキストラベルは、ピッカー内のフォントサイズと色の選択を変更するための数値エディットボックスにバインドされます。
テキストラベルコントロールのパラメータを管理するイベントハンドラは次のようになります。
//| チャートイベントハンドラ |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- コンボボックスリストからの選択イベント
if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM)
{
//--- コントロールの識別子が一致する場合
if(lparam==m_combobox1.Id())
{
//--- フォントを変更する
m_text_label1.LabelFont(m_combobox1.ButtonText());
}
//---
return;
}
//--- スピンエディットボックスのボタンのクリックイベント
if(id==CHARTEVENT_CUSTOM+ON_CLICK_INC ||
id==CHARTEVENT_CUSTOM+ON_CLICK_DEC)
{
//--- コントロールの識別子が一致する場合
if(lparam==m_spin_edit1.Id())
{
//--- フォントサイズを変更する
m_text_label1.LabelFontSize(int(m_spin_edit1.GetValue()));
}
//---
return;
}
//--- カラーピッカーを使った色の変更のイベント
if(id==CHARTEVENT_CUSTOM+ON_END_EDIT)
{
//--- コントロールの識別子が一致する場合
if(lparam==m_spin_edit1.Id())
{
//--- フォントサイズを変更する
m_text_label1.LabelFontSize(int(m_spin_edit1.GetValue()));
}
//---
return;
}
//--- カラーピッカーを使った色の変更のイベント
if(id==CHARTEVENT_CUSTOM+ON_CHANGE_COLOR)
{
//--- コントロールの識別子が一致する場合
if(lparam==m_color_picker.Id())
{
//--- ボタン1 からの応答の場合
if(sparam==m_color_button1.LabelText())
{
//--- オブジェクトの色を変更する
m_text_label1.LabelColor(m_color_button1.CurrentColor());
return;
}
}
return;
}
//--- ボタン押下イベント
if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
{
//--- カラーピッカーを呼び出す1番目のボタンが押下された場合
if(sparam==m_color_button1.LabelText())
{
//--- ボタンポインタを渡すとカラーピッカーを持つウィンドウが自動的に開く
m_color_picker.ColorButtonPointer(m_color_button1);
return;
}
//---
return;
}
}
下のスクリーンショットは、グラフィカルインタフェースを使ってテキスト表示を設定する方法を示しています。
図8 2番目のタブのコントロールグループ
2. 2番目のタブにはピクチャスライダ( CPicturesSlider クラス)の1つのコントロール のみが配置されます。コントロールを自分で簡単にテスト出来るようにグループにはデフォルトの3画像しか追加されません。コントロールが正しく機能するには、同じサイズの画像を用意します。
図9 2番目のタブのピクチャスライダー
画像をプログラム的に切り替えるにはCPicturesSlider::SelectPicture()メソッドを使用します。
3. 3番目のタブにはCTableタイプののテーブルが含まれます。プログラム的に行を選択するには、CTable :: SelectRow()メソッドを使用します。
図10 3番目のタブのテーブル
4. 4番目のタブには(1) カレンダー、(2)ドロップダウンカレンダー、(3)押されている/いないの2つの状態のためのアイコンを持つボタンがあります。
図11 4番目のタブのコントロールグループ
本稿で紹介されたテストアプリケーションをさらに研究するためには、以下のリンクを使用してダウンロードすることができます。
おわりに
開発の現段階では、以下の図に示されたような結果が得られるはずです。
図12 開発の現段階でのライブラリの構造
次のバージョンでは、ライブラリーは追加のコントロールとともに拡張されます。また、既存のコントロールはさらに開発され、新しい機能で拡張されます。
これらのファイルに含まれている資料の使用についてご質問がある場合は、記事のいずれかでライブラリの開発の詳細をご参照になるか、本稿へのコメント欄でご質問ください。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/2829
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索