
DoEasy-コントロール(第17部):オブジェクトの非表示部分の切り取り、補助矢印ボタンのWinFormsオブジェクト
内容
概念
コンテナに接続された各グラフィック要素は、そのコンテナ内でのみ表示されます。要素の一部がコンテナの境界を越えてはみ出している場合、このはみ出した部分は非表示にする必要があります。オブジェクト全体ではなく、接続されている親オブジェクトの可視性の境界の外側にある部分のみを非表示にする必要があります。通常コンテナの端が可視性の境界として使用されますが、オブジェクトにフレームがある場合、このフレームは接続されたオブジェクトと重なりません。この場合、突き出たオブジェクトの可視性の境界はコンテナフレームの内側の端になります。
MQLは、bmp画像に基づいたグラフィック要素(OBJ_BITMAP_LABELおよびOBJ_BITMAP)を切り取るための特別なグラフィカルオブジェクトプロパティを備えています。これらのプロパティを使用すると、長方形の可視範囲によってアウトラインされた画像の一部のみを表示することができます。
残念ながら、キャンバスを使用している場合、長方形の範囲内のオブジェクトの可視部分の切り取りと配置は機能しません。キャンバスのリソースはメモリ内のビットマップイメージとして作成されますが、メモリ内にイメージがリソースとして組み込まれている物理的なbmpファイルに基づくオブジェクトを対象とするこのメソッドを使用すると、「何かが許可されません」。
したがって、私は自分の道を進みます。自分でそのような範囲を作成し、コンテナの範囲を超えるオブジェクトの部分を切り取ります。最初は、長方形の範囲はコンテナの幅と高さに等しいか、オブジェクトフレーム内にあります(フレームがある場合)。各グラフィック要素には、コンテナに対する独自の位置を読み取り、余分な可視部分を切り取るメソッドがあります(完全に透明な透明色で背景をペイントするだけです)。
前述のグラフィック要素の機能の実装に加えて、グラフィック要素のいくつかの補助クラスも作成します。矢印付きボタンオブジェクトです。このようなボタンは、スクロールバー、ドロップダウンリスト、その他の同様のコントロールなどのコントロールを実装するために必要です。
開発中のTabControlについて言えば、タブヘッダーが多すぎてコントロールに収まらない場合に備えて、1行に配置されたタブヘッダーを移動するためのボタンが必要です。コントロールからはみ出るタブは非表示にする必要があり(これは私が今日実装しているものです)、左右の矢印が付いた2つのボタンだけを使用してヘッダーバーをスクロールし、目的のタブヘッダーを見つけて表示します。したがって、このような矢印付きのボタンオブジェクトを作成した後、「左右」と「上下」の2つのボタンを持つ、さらに2つのオブジェクトを作成します。次の記事では、これらのオブジェクトを使用して、TabControlオブジェクト内の非表示のタブを見つけます。
ライブラリクラスの改善
\MQL5\Include\DoEasy\Defines.mqhで、矢印ボタンの辺のデフォルトサイズを指定するマクロ置換を追加します。
#define DEF_FONT ("Calibri") // Default font #define DEF_FONT_SIZE (8) // Default font size #define DEF_CHECK_SIZE (12) // Verification flag default size #define DEF_ARROW_BUTTON_SIZE (15) // Default arrow button size #define OUTER_AREA_SIZE (16) // Size of one side of the outer area around the form workspace #define DEF_FRAME_WIDTH_SIZE (3) // Default form/panel/window frame width
このようなボタンオブジェクトを作成するときに、ボタンの辺に他のサイズをいつでも指定できますが、デフォルトのサイズは15ピクセルになります。
新しいタイプ(補助オブジェクト)をWinFormsオブジェクトセクションにあるライブラリオブジェクトタイプのリストに追加します。
//+------------------------------------------------------------------+ //| List of library object types | //+------------------------------------------------------------------+ enum ENUM_OBJECT_DE_TYPE { //--- Graphics OBJECT_DE_TYPE_GBASE = COLLECTION_ID_LIST_END+1, // "Base object of all library graphical objects" object type OBJECT_DE_TYPE_GELEMENT, // "Graphical element" object type OBJECT_DE_TYPE_GFORM, // Form object type OBJECT_DE_TYPE_GFORM_CONTROL, // "Form for managing pivot points of graphical object" object type OBJECT_DE_TYPE_GSHADOW, // Shadow object type //--- WinForms OBJECT_DE_TYPE_GWF_BASE, // WinForms Base object type (base abstract WinForms object) OBJECT_DE_TYPE_GWF_CONTAINER, // WinForms container object type OBJECT_DE_TYPE_GWF_COMMON, // WinForms standard control object type OBJECT_DE_TYPE_GWF_HELPER, // WinForms auxiliary control object type //--- Animation //---... //---... }
その後、このタイプのグラフィカルオブジェクトに従って補助オブジェクトのみを選択して、それらを使用してアクションを実行できるようになります。
グラフィック要素タイプのリストに新しいタイプを追加しましょう。このオブジェクトクラスは現在の記事で作成します。
//+------------------------------------------------------------------+ //| The list of graphical element types | //+------------------------------------------------------------------+ enum ENUM_GRAPH_ELEMENT_TYPE { GRAPH_ELEMENT_TYPE_STANDARD, // Standard graphical object GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED, // Extended standard graphical object GRAPH_ELEMENT_TYPE_SHADOW_OBJ, // Shadow object GRAPH_ELEMENT_TYPE_ELEMENT, // Element GRAPH_ELEMENT_TYPE_FORM, // Form GRAPH_ELEMENT_TYPE_WINDOW, // Window //--- WinForms GRAPH_ELEMENT_TYPE_WF_UNDERLAY, // Panel object underlay GRAPH_ELEMENT_TYPE_WF_BASE, // Windows Forms Base //--- 'Container' object types are to be set below GRAPH_ELEMENT_TYPE_WF_CONTAINER, // Windows Forms container base object GRAPH_ELEMENT_TYPE_WF_PANEL, // Windows Forms Panel GRAPH_ELEMENT_TYPE_WF_GROUPBOX, // Windows Forms GroupBox GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL, // Windows Forms TabControl //--- 'Standard control' object types are to be set below GRAPH_ELEMENT_TYPE_WF_COMMON_BASE, // Windows Forms base standard control GRAPH_ELEMENT_TYPE_WF_LABEL, // Windows Forms Label GRAPH_ELEMENT_TYPE_WF_BUTTON, // Windows Forms Button GRAPH_ELEMENT_TYPE_WF_CHECKBOX, // Windows Forms CheckBox GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON, // Windows Forms RadioButton GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX, // Base list object of Windows Forms elements GRAPH_ELEMENT_TYPE_WF_LIST_BOX, // Windows Forms ListBox GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX, // Windows Forms CheckedListBox GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX, // Windows Forms ButtonListBox //--- Auxiliary elements of WinForms objects GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM, // Windows Forms ListBoxItem GRAPH_ELEMENT_TYPE_WF_TAB_HEADER, // Windows Forms TabHeader GRAPH_ELEMENT_TYPE_WF_TAB_FIELD, // Windows Forms TabField GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON, // Windows Forms ArrowButton GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP, // Windows Forms UpArrowButton GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN, // Windows Forms DownArrowButton GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT, // Windows Forms LeftArrowButton GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT, // Windows Forms RightArrowButton GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX, // Windows Forms UpDownArrowButtonsBox GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX, // Windows Forms LeftRightArrowButtonsBox }; //+------------------------------------------------------------------+
キャンバス上のグラフィック要素の整数プロパティのリストで、4つの新しいプロパティを追加して、グラフィック要素の表示領域の座標と寸法を指定し、整数プロパティの総数を92から96に増やします。
//+------------------------------------------------------------------+ //| Integer properties of the graphical element on the canvas | //+------------------------------------------------------------------+ enum ENUM_CANV_ELEMENT_PROP_INTEGER { CANV_ELEMENT_PROP_ID = 0, // Element ID CANV_ELEMENT_PROP_TYPE, // Graphical element type //---... //---... CANV_ELEMENT_PROP_ACT_RIGHT, // Right border of the element active area CANV_ELEMENT_PROP_ACT_BOTTOM, // Bottom border of the element active area CANV_ELEMENT_PROP_VISIBLE_AREA_X, // Visibility scope X coordinate CANV_ELEMENT_PROP_VISIBLE_AREA_Y, // Visibility scope Y coordinate CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH, // Visibility scope width CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT, // Visibility scope height CANV_ELEMENT_PROP_GROUP, // Group the graphical element belongs to CANV_ELEMENT_PROP_ZORDER, // Priority of a graphical object for receiving the event of clicking on a chart //---... //---... }; #define CANV_ELEMENT_PROP_INTEGER_TOTAL (96) // Total number of integer properties #define CANV_ELEMENT_PROP_INTEGER_SKIP (0) // Number of integer properties not used in sorting //+------------------------------------------------------------------+
キャンバス上のグラフィック要素を並べ替える可能性のある基準の列挙に新しいプロパティを追加します。
//+------------------------------------------------------------------+ //| Possible sorting criteria of graphical elements on the canvas | //+------------------------------------------------------------------+ #define FIRST_CANV_ELEMENT_DBL_PROP (CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP) #define FIRST_CANV_ELEMENT_STR_PROP (CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP+CANV_ELEMENT_PROP_DOUBLE_TOTAL-CANV_ELEMENT_PROP_DOUBLE_SKIP) enum ENUM_SORT_CANV_ELEMENT_MODE { //--- Sort by integer properties SORT_BY_CANV_ELEMENT_ID = 0, // Sort by element ID SORT_BY_CANV_ELEMENT_TYPE, // Sort by graphical element type //---... //---... SORT_BY_CANV_ELEMENT_ACT_RIGHT, // Sort by the right border of the element active area SORT_BY_CANV_ELEMENT_ACT_BOTTOM, // Sort by the bottom border of the element active area SORT_BY_CANV_ELEMENT_VISIBLE_AREA_X, // Sort by visibility scope X coordinate SORT_BY_CANV_ELEMENT_VISIBLE_AREA_Y, // Sort by visibility scope Y coordinate SORT_BY_CANV_ELEMENT_VISIBLE_AREA_WIDTH, // Sort by visibility scope width SORT_BY_CANV_ELEMENT_VISIBLE_AREA_HEIGHT, // Sort by visibility scope height SORT_BY_CANV_ELEMENT_GROUP, // Sort by a group the graphical element belongs to SORT_BY_CANV_ELEMENT_ZORDER, // Sort by the priority of a graphical object for receiving the event of clicking on a chart //---... //---... SORT_BY_CANV_ELEMENT_TAB_PAGE_COLUMN, // Sort by tab column index SORT_BY_CANV_ELEMENT_ALIGNMENT, // Sort by the location of the object inside the control //--- Sort by real properties //--- Sort by string properties SORT_BY_CANV_ELEMENT_NAME_OBJ = FIRST_CANV_ELEMENT_STR_PROP,// Sort by an element object name SORT_BY_CANV_ELEMENT_NAME_RES, // Sort by the graphical resource name SORT_BY_CANV_ELEMENT_TEXT, // Sort by graphical element text SORT_BY_CANV_ELEMENT_DESCRIPTION, // Sort by graphical element description }; //+------------------------------------------------------------------+
これで、新しいプロパティでグラフィック要素を選択し、それによって並び替えられるようになります。
\MQL5\Include\DoEasy\Data.mqhに、新しいメッセージインデックスを追加します。
MSG_GRAPH_ELEMENT_TYPE_WF_TAB_FIELD, // TabControl tab field MSG_GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL, // TabControl MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON, // ArrowButton control MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP, // UpArrowButton control MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN, // DownArrowButton control MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT, // LeftArrowButton control MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT, // RightArrowButton control MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX, // UpDownArrowBox control MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX, // LeftRightArrowBox control MSG_GRAPH_OBJ_BELONG_PROGRAM, // Graphical object belongs to a program MSG_GRAPH_OBJ_BELONG_NO_PROGRAM, // Graphical object does not belong to a program
...
MSG_CANV_ELEMENT_PROP_ACT_RIGHT, // Right border of the element active area MSG_CANV_ELEMENT_PROP_ACT_BOTTOM, // Bottom border of the element active area MSG_CANV_ELEMENT_PROP_VISIBLE_AREA_X, // Visibility scope X coordinate MSG_CANV_ELEMENT_PROP_VISIBLE_AREA_Y, // Visibility scope Y coordinate MSG_CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH, // Visibility scope width MSG_CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT, // Visibility scope height MSG_CANV_ELEMENT_PROP_ENABLED, // Element availability flag MSG_CANV_ELEMENT_PROP_FORE_COLOR, // Default text color for all control objects
また、新しく追加されたインデックスに対応するテキストメッセージも追加します。
{"Поле вкладки элемента управления \"TabControl\"","Tab field of the Control element \"TabControl\""}, {"Элемент управления \"TabControl\"","Control element \"TabControl\""}, {"Элемент управления \"ArrowButton\"","Control element \"ArrowButton\""}, {"Элемент управления \"UpArrowButton\"","Control element \"UpArrowButton\""}, {"Элемент управления \"DownArrowButton\"","Control element \"DownArrowButton\""}, {"Элемент управления \"LeftArrowButton\"","Control element \"LeftArrowButton\""}, {"Элемент управления \"RightArrowButton\"","Control element \"RightArrowButton\""}, {"Элемент управления \"UpDownArrowBox\"","Control element \"UpDownArrowBox\""}, {"Элемент управления \"LeftRightArrowBox\"","Control element \"LeftRightArrowBox\""}, {"Графический объект принадлежит программе","The graphic object belongs to the program"}, {"Графический объект не принадлежит программе","The graphic object does not belong to the program"},
...
{"Правая граница активной зоны элемента","Right border of the element's active area"}, {"Нижняя граница активной зоны элемента","Bottom border of the element's active area"}, {"Координата X области видимости","X-coordinate of object visibility area"}, {"Координата Y области видимости","Y-coordinate of object visibility area"}, {"Ширина области видимости","Width of object visibility area"}, {"Высота области видимости","Height of object visibility area"}, {"Флаг доступности элемента","Element Availability Flag"}, {"Цвет текста по умолчанию для всех объектов элемента управления","Default text color for all objects in the control"},
ライブラリサービス関数のファイル(\MQL5\Include\DoEasy\Services\DELib.mqh)にある、グラフィカルオブジェクトのタイプを「文字列」として返す関数にいくつかのマイナーな改善を導入しましょう。
//+------------------------------------------------------------------+ //| Return the graphical object type as string | //+------------------------------------------------------------------+ string TypeGraphElementAsString(const ENUM_GRAPH_ELEMENT_TYPE type) { ushort array[]; int total=StringToShortArray(StringSubstr(EnumToString(type),18),array); for(int i=0;i<total-1;i++) { if(array[i]==95) { i+=1; continue; } else array[i]+=0x20; } string txt=ShortArrayToString(array); StringReplace(txt,"_Wf_Base","WFBase"); StringReplace(txt,"_Wf_",""); StringReplace(txt,"_Obj",""); StringReplace(txt,"_",""); StringReplace(txt,"Groupbox","GroupBox"); StringReplace(txt,"ButtonsUdBox","ButtonsUDBox"); StringReplace(txt,"ButtonsLrBox","ButtonsLRBox"); return txt; } //+------------------------------------------------------------------+
新しいグラフィック要素を作成するので、作成するために、グラフィカルオブジェクトの自動生成された名前を少し変更する必要があります。名前文字列を作成するとき、関数は最初は2つ以上の連続する大文字を許可しません。同時に、オブジェクト名にはそのような文字を3つ含める必要があります。したがって、自動生成された名前文字列を必要なものに置き換えるだけです。
これで、作成された新しいオブジェクトの名前が正しくなります。
\MQL5\Include\DoEasy\Objects\Graph\WForms\ListBoxItem.mqhにあるListBoxItem補助オブジェクトのクラスコンストラクタで、ライブラリグラフィカルオブジェクトタイプを「補助WinFormsオブジェクト」として入力します。
//+------------------------------------------------------------------+ //| Protected constructor with an object type, | //| chart ID and subwindow | //+------------------------------------------------------------------+ CListBoxItem::CListBoxItem(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CButton(type,chart_id,subwindow,descript,x,y,w,h) { //--- Set the specified graphical element type for the object and assign the library object type to the current object this.SetTypeElement(type); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetTextAlign(ANCHOR_LEFT); this.SetTextShiftSpace(1); } //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CListBoxItem::CListBoxItem(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CButton(GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetTextAlign(ANCHOR_LEFT); this.SetTextShiftSpace(1); } //+------------------------------------------------------------------+
キャンバスで、グラフィカルオブジェクトの可視部分のみを表示する標準的な手法を使用すると、長方形の範囲で輪郭が描かれるため、問題が発生する場合があります。よって、自分でやるつもりです。ただし、グラフィカルオブジェクトにはまだそのようなプロパティがあるため、これらのプロパティを設定してグラフィカルオブジェクトに取得するための機能を作成する必要があります。この機能は、キャンバス上のグラフィック要素の可視範囲を作成するためにも使用されます。
ライブラリの基本グラフィカルオブジェクトのファイル(\MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh)で、グラフィカルオブジェクトの新しいプロパティを設定および取得するための仮想メソッドを追加し、表示フラグを設定するメソッドはメソッドによってフラグが設定されていることを明らかにするために名前変更されます。
//--- Set the priority of a graphical object for receiving the event of clicking on a chart virtual bool SetZorder(const long value,const bool only_prop) { ::ResetLastError(); if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_ZORDER,value)) || only_prop) { this.m_zorder=value; return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- (1) Set and (2) return the X coordinate of the upper left corner of the rectangle visibility scope of the OBJ_BITMAP_LABEL and OBJ_BITMAP graphical object virtual bool SetXOffset(const long value) { ::ResetLastError(); if(!::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_XOFFSET,value)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } virtual int XOffset(void) const { return (int)::ObjectGetInteger(this.m_chart_id,this.m_name,OBJPROP_XOFFSET); } //--- (1) Set and (2) return the Y coordinate of the upper left corner of the rectangle visibility scope of the OBJ_BITMAP_LABEL and OBJ_BITMAP graphical object virtual bool SetYOffset(const long value) { ::ResetLastError(); if(!::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_YOFFSET,value)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } virtual int YOffset(void) const { return (int)::ObjectGetInteger(this.m_chart_id,this.m_name,OBJPROP_YOFFSET); } //--- (1) Set and (2) return the width of OBJ_LABEL (read only), OBJ_BUTTON, OBJ_CHART, OBJ_BITMAP, OBJ_BITMAP_LABEL, OBJ_EDIT and OBJ_RECTANGLE_LABEL objects virtual bool SetXSize(const long value) { ::ResetLastError(); if(!::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_XSIZE,value)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } virtual int XSize(void) const { return (int)::ObjectGetInteger(this.m_chart_id,this.m_name,OBJPROP_XSIZE); } //--- (1) Set and (2) return the height of OBJ_LABEL (read only), OBJ_BUTTON, OBJ_CHART, OBJ_BITMAP, OBJ_BITMAP_LABEL, OBJ_EDIT, OBJ_RECTANGLE_LABEL objects virtual bool SetYSize(const long value) { ::ResetLastError(); if(!::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_YSIZE,value)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } virtual int YSize(void) const { return (int)::ObjectGetInteger(this.m_chart_id,this.m_name,OBJPROP_YSIZE); } //--- Set object visibility on all timeframes bool SetVisibleFlag(const bool flag,const bool only_prop) { long value=(flag ? OBJ_ALL_PERIODS : OBJ_NO_PERIODS); ::ResetLastError(); if((!only_prop && ::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_TIMEFRAMES,value)) || only_prop) { this.m_visible=flag; return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; }
プロパティを設定するメソッドは、グラフィカルオブジェクトの指定されたプロパティ値がチャートキューに正常に配置されたことを示すフラグを返します。つまり、この関数は非同期であり、キュー内のコマンドの設定が成功したというフラグのみを返し、必要なプロパティの設定が成功したというフラグは返しません。チェックを実行するには、オブジェクトから変更されたプロパティを読み取り、その値を確認する必要があります。これはすべてのObjectSetXXX関数に対しておこなわれましたが、ライブラリを使用した場合、コマンドキューの実行に遅延は見られませんでした。そのため、今のところ、この構成を使用してグラフィカルオブジェクトのプロパティを設定します。
グラフィック要素のタイプの説明を返すメソッドで新しいオブジェクトの説明を返すようにします。現在の記事で実装する矢印ボタンです。
//+------------------------------------------------------------------+ //| Return the description of the graphical element type | //+------------------------------------------------------------------+ string CGBaseObj::TypeElementDescription(const ENUM_GRAPH_ELEMENT_TYPE type) { return ( type==GRAPH_ELEMENT_TYPE_STANDARD ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDARD) : type==GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED) : type==GRAPH_ELEMENT_TYPE_ELEMENT ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_ELEMENT) : type==GRAPH_ELEMENT_TYPE_SHADOW_OBJ ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_SHADOW_OBJ) : type==GRAPH_ELEMENT_TYPE_FORM ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_FORM) : type==GRAPH_ELEMENT_TYPE_WINDOW ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WINDOW) : //--- WinForms type==GRAPH_ELEMENT_TYPE_WF_UNDERLAY ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_UNDERLAY) : type==GRAPH_ELEMENT_TYPE_WF_BASE ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BASE) : //--- Containers type==GRAPH_ELEMENT_TYPE_WF_CONTAINER ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CONTAINER) : type==GRAPH_ELEMENT_TYPE_WF_GROUPBOX ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_GROUPBOX) : type==GRAPH_ELEMENT_TYPE_WF_PANEL ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_PANEL) : type==GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL) : //--- Standard controls type==GRAPH_ELEMENT_TYPE_WF_COMMON_BASE ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_COMMON_BASE) : type==GRAPH_ELEMENT_TYPE_WF_LABEL ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_LABEL) : type==GRAPH_ELEMENT_TYPE_WF_CHECKBOX ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CHECKBOX) : type==GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON) : type==GRAPH_ELEMENT_TYPE_WF_BUTTON ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BUTTON) : type==GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX) : type==GRAPH_ELEMENT_TYPE_WF_LIST_BOX ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_LIST_BOX) : type==GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM) : type==GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX) : type==GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX) : //--- Auxiliary control objects type==GRAPH_ELEMENT_TYPE_WF_TAB_HEADER ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TAB_HEADER) : type==GRAPH_ELEMENT_TYPE_WF_TAB_FIELD ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_TAB_FIELD) : type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON) : type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP) : type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN) : type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT) : type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT) : type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX) : type==GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX ? CMessage::Text(MSG_GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX) : "Unknown" ); } //+------------------------------------------------------------------+
新しいタイプの補助オブジェクトの準備が整い、それらを作成できるようになったら、それらの説明を取得できます。
ライブラリ標準グラフィカルオブジェクトの基本オブジェクトのファイル(\MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqh)で、可視性フラグ設定メソッドの呼び出しを修正しました。このメソッドは名前が変更されたためです。
//--- Object visibility on timeframes bool Visible(void) const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0); } bool SetFlagVisible(const bool flag,const bool only_prop) { if(!CGBaseObj::SetVisibleFlag(flag,only_prop)) return false; this.SetProperty(GRAPH_OBJ_PROP_TIMEFRAMES,0,flag); return true; } //--- Background object
キャンバス上のグラフィック要素オブジェクトのファイル(MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh)にあるオブジェクトprivate構造体に新しい整数プロパティを追加します。
private: int m_shift_coord_x; // Offset of the X coordinate relative to the base object int m_shift_coord_y; // Offset of the Y coordinate relative to the base object struct SData { //--- Object integer properties int id; // Element ID int type; // Graphical element type //---... //---... int tab_alignment; // Location of tabs inside the control int alignment; // Location of the object inside the control int visible_area_x; // Visibility scope X coordinate int visible_area_y; // Visibility scope Y coordinate int visible_area_w; // Visibility scope width int visible_area_h; // Visibility scope height //--- Object real properties //--- Object string properties uchar name_obj[64]; // Graphical element object name uchar name_res[64]; // Graphical resource name uchar text[256]; // Graphical element text uchar descript[256]; // Graphical element description }; SData m_struct_obj; // Object structure
ファイルからオブジェクトのプロパティを正しく保存して読み取るには、オブジェクトプロパティの構造体が必要です。
基本グラフィカルオブジェクトファイル内の以前に名前が変更されたメソッドにアクセスするすべてのメソッドは、このメソッドを新しい名前で参照する必要があります。
//--- Set the object above all virtual void BringToTop(void) { CGBaseObj::SetVisibleFlag(false,false); CGBaseObj::SetVisibleFlag(true,false);} //--- (1) Show and (2) hide the element virtual void Show(void) { CGBaseObj::SetVisibleFlag(true,false); } virtual void Hide(void) { CGBaseObj::SetVisibleFlag(false,false); } //--- Priority of a graphical object for receiving the event of clicking on a chart
新しいグラフィック要素のプロパティを操作するための仮想メソッドを実装しましょう。
//--- Graphical object group virtual int Group(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_GROUP); } virtual void SetGroup(const int value) { CGBaseObj::SetGroup(value); this.SetProperty(CANV_ELEMENT_PROP_GROUP,value); } //--- Visibility scope X coordinate virtual int XOffset(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X); } virtual bool SetXOffset(const int value,const bool only_prop) { ::ResetLastError(); if((!only_prop && CGBaseObj::SetXOffset(value)) || only_prop) { this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X,value); return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Visibility scope Y coordinate virtual int YOffset(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y); } virtual bool SetYOffset(const int value,const bool only_prop) { ::ResetLastError(); if((!only_prop && CGBaseObj::SetYOffset(value)) || only_prop) { this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y,value); return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Visibility scope width virtual int XSize(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH); } virtual bool SetXSize(const int value,const bool only_prop) { ::ResetLastError(); if((!only_prop && CGBaseObj::SetXSize(value)) || only_prop) { this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH,value); return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Visibility scope height virtual int YSize(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT); } virtual bool SetYSize(const int value,const bool only_prop) { ::ResetLastError(); if((!only_prop && CGBaseObj::SetYSize(value)) || only_prop) { this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,value); return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Visibility scope X coordinate virtual int VisibleAreaX(void) const { return this.XOffset(); } virtual bool SetVisibleAreaX(const int value,const bool only_prop) { ::ResetLastError(); if((!only_prop && CGBaseObj::SetXOffset(value)) || only_prop) { this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X,value); return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Visibility scope Y coordinate virtual int VisibleAreaY(void) const { return this.YOffset(); } virtual bool SetVisibleAreaY(const int value,const bool only_prop) { ::ResetLastError(); if((!only_prop && CGBaseObj::SetYOffset(value)) || only_prop) { this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y,value); return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Visibility scope width virtual int VisibleAreaWidth(void) const { return this.XSize(); } virtual bool SetVisibleAreaWidth(const int value,const bool only_prop) { ::ResetLastError(); if((!only_prop && CGBaseObj::SetXSize(value)) || only_prop) { this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH,value); return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Visibility scope height virtual int VisibleAreaHeight(void) const { return this.YSize(); } virtual bool SetVisibleAreaHeight(const int value,const bool only_prop) { ::ResetLastError(); if((!only_prop && CGBaseObj::SetYSize(value)) || only_prop) { this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,value); return true; } else CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Return the (1) X coordinate, (2) right border, (3) Y coordinate, (4) bottom border of the visible area int CoordXVisibleArea(void) const { return this.CoordX()+this.VisibleAreaX(); } int RightEdgeVisibleArea(void) const { return this.CoordXVisibleArea()+this.VisibleAreaWidth(); } int RightEdgeVisibleAreaRelative(void) const { return this.VisibleAreaX()+this.VisibleAreaWidth(); } int CoordYVisibleArea(void) const { return this.CoordY()+this.VisibleAreaY(); } int BottomEdgeVisibleArea(void) const { return this.CoordYVisibleArea()+this.VisibleAreaHeight(); } int BottomEdgeVisibleAreaRelative(void) const { return this.VisibleAreaY()+this.VisibleAreaHeight(); } //--- Graphical element description
プロパティ値を設定するメソッドは、まず、プロパティをグラフィカルオブジェクト自体に直接設定します。操作が成功すると、値がオブジェクトクラスプロパティに設定されます。値は、プロパティ設定メソッドによって以前に設定されたオブジェクトプロパティから返されます。
補助メソッドは、目的のエッジの計算値またはオブジェクト可視範囲の左上隅の座標を返し、可視範囲境界の必要なプロパティを読み取るためのアクセスを簡素化します。グラフィック要素の同様のメソッドに従って名前が付けられ、個別に計算する必要なく目的の値を返すためです。
グラフィック要素オブジェクトが作成されると、設定された色で塗りつぶされ、必要なラベルまたは画像が描画され、オブジェクトはコンテナ内の位置を計算し、コンテナの外側に突出した部分を切り取る必要があります。.非表示にする必要がある領域を透明色で塗りつぶすことで、切り取りがおこなわれます。まずErase()メソッドを呼び出す必要があります。このメソッドは、背景を色で塗りつぶし、オブジェクトに何か他のものを描画してから、画像の見えない部分を消去します。これはすべてErase()メソッドに再度配置する必要があるので、まず非表示領域を切り取りせずに色の塗りつぶしが発生することになります。このメソッドをEraseNoCrop()と呼びましょう。さらに、非表示領域を切り取りするCrop()メソッドを作成します。これらのメソッドを既存のErase()メソッドに順次呼び出します。
クラスのprotectedセクションとpublicセクションで新しいメソッドを宣言しましょう。
//+------------------------------------------------------------------+ //| The methods of filling, clearing and updating raster data | //+------------------------------------------------------------------+ //--- Clear the element filling it with color and opacity virtual void Erase(const color colour,const uchar opacity,const bool redraw=false); //--- Clear the element with a gradient fill virtual void Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false); //--- Clear the element completely virtual void Erase(const bool redraw=false); protected: //--- Clear the element filling it with color and opacity without cropping and updating virtual void EraseNoCrop(const color colour,const uchar opacity,const bool redraw=false); //--- Clears the element with a gradient fill without cropping and updating virtual void EraseNoCrop(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false); public: //--- Crops the image outlined by (1) the specified and (2) previously set rectangular visibility scope void Crop(const uint coord_x,const uint coord_y,const uint width,const uint height); virtual void Crop(void); //--- Update the element void Update(const bool redraw=false) { this.m_canvas.Update(redraw); } //+------------------------------------------------------------------+
両方のクラスコンストラクタで、長方形の可視範囲がオブジェクト全体のサイズになるように座標とオブジェクトの可視範囲のサイズのデフォルト値を設定します。すべてのプロパティを設定したら、オブジェクトの可視性フラグをhiddenに設定します。これにより、すべてのプログラムGUI要素オブジェクトがどのように徐々に構築されるか(グラフィカルコンポーネントを構築するときプログラム自体でメインフォームオブジェクトを非表示にしてすべてのグラフィカルオブジェクトを構築した後に表示する)を観察する必要がなくなります。
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, const int element_id, const int element_num, const long chart_id, const int wnd_num, const string descript, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable=true, const bool activity=true, const bool redraw=false) : m_shadow(false) { this.SetTypeElement(element_type); this.m_type=OBJECT_DE_TYPE_GELEMENT; this.m_element_main=NULL; this.m_element_base=NULL; this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND); this.m_name=this.CreateNameGraphElement(element_type); this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id); this.m_subwindow=wnd_num; this.SetFont(DEF_FONT,DEF_FONT_SIZE); this.m_text_anchor=0; this.m_text_x=0; this.m_text_y=0; this.SetBackgroundColor(colour,true); this.SetOpacity(opacity); this.m_shift_coord_x=0; this.m_shift_coord_y=0; if(::ArrayResize(this.m_array_colors_bg,1)==1) this.m_array_colors_bg[0]=this.BackgroundColor(); if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1) this.m_array_colors_bg_dwn[0]=this.BackgroundColor(); if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1) this.m_array_colors_bg_ovr[0]=this.BackgroundColor(); if(this.Create(chart_id,wnd_num,x,y,w,h,redraw)) { this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,this.m_canvas.ResourceName()); // Graphical resource name this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,CGBaseObj::ChartID()); // Chart ID //---... //---... this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.ActiveAreaRight()); // Right border of the element active area this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.ActiveAreaBottom()); // Bottom border of the element active area this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X,0); // Visibility scope X coordinate this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y,0); // Visibility scope Y coordinate this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH,w); // Visibility scope width this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,h); // Visibility scope height //---... //---... this.SetProperty(CANV_ELEMENT_PROP_BELONG,ENUM_GRAPH_OBJ_BELONG::GRAPH_OBJ_BELONG_PROGRAM); // Graphical element affiliation this.SetProperty(CANV_ELEMENT_PROP_ZORDER,0); // Priority of a graphical object for receiving the event of clicking on a chart //---... //---... this.SetProperty(CANV_ELEMENT_PROP_ALIGNMENT,CANV_ELEMENT_ALIGNMENT_TOP); // Location of an object inside the control this.SetProperty(CANV_ELEMENT_PROP_TEXT,""); // Graphical element text this.SetProperty(CANV_ELEMENT_PROP_DESCRIPTION,descript); // Graphical element description this.SetVisibleFlag(false,false); } else { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj()); } } //+------------------------------------------------------------------+ //| Protected constructor | //+------------------------------------------------------------------+ CGCnvElement::CGCnvElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, const long chart_id, const int wnd_num, const string descript, const int x, const int y, const int w, const int h) : m_shadow(false) { this.m_type=OBJECT_DE_TYPE_GELEMENT; this.m_element_main=NULL; this.m_element_base=NULL; this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND); this.m_name=this.CreateNameGraphElement(element_type); this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id); this.m_subwindow=wnd_num; this.m_type_element=element_type; this.SetFont(DEF_FONT,DEF_FONT_SIZE); this.m_text_anchor=0; this.m_text_x=0; this.m_text_y=0; this.SetBackgroundColor(CLR_CANV_NULL,true); this.SetOpacity(0); this.m_shift_coord_x=0; this.m_shift_coord_y=0; if(::ArrayResize(this.m_array_colors_bg,1)==1) this.m_array_colors_bg[0]=this.BackgroundColor(); if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1) this.m_array_colors_bg_dwn[0]=this.BackgroundColor(); if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1) this.m_array_colors_bg_ovr[0]=this.BackgroundColor(); if(this.Create(chart_id,wnd_num,x,y,w,h,false)) { this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,this.m_canvas.ResourceName()); // Graphical resource name this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,CGBaseObj::ChartID()); // Chart ID //---... //---... this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.ActiveAreaRight()); // Right border of the element active area this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.ActiveAreaBottom()); // Bottom border of the element active area this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X,0); // Visibility scope X coordinate this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y,0); // Visibility scope Y coordinate this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH,w); // Visibility scope width this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,h); // Visibility scope height //---... //---... this.SetProperty(CANV_ELEMENT_PROP_TAB_ALIGNMENT,CANV_ELEMENT_ALIGNMENT_TOP); // Location of tabs inside the control this.SetProperty(CANV_ELEMENT_PROP_ALIGNMENT,CANV_ELEMENT_ALIGNMENT_TOP); // Location of an object inside the control //---... //---... this.SetProperty(CANV_ELEMENT_PROP_TEXT,""); // Graphical element text this.SetProperty(CANV_ELEMENT_PROP_DESCRIPTION,descript); // Graphical element description this.SetVisibleFlag(false,false); } else { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj()); } } //+------------------------------------------------------------------+
オブジェクトの構造を作成するメソッドで、範囲の可視性プロパティを設定するようにします。
//+------------------------------------------------------------------+ //| Create the object structure | //+------------------------------------------------------------------+ bool CGCnvElement::ObjectToStruct(void) { //--- Save integer properties this.m_struct_obj.id=(int)this.GetProperty(CANV_ELEMENT_PROP_ID); // Element ID this.m_struct_obj.type=(int)this.GetProperty(CANV_ELEMENT_PROP_TYPE); // Graphical element type //---... //---... this.m_struct_obj.coord_act_y=(int)this.GetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y); // Y coordinate of the element active area this.m_struct_obj.coord_act_right=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_RIGHT); // Right border of the element active area this.m_struct_obj.coord_act_bottom=(int)this.GetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM); // Bottom border of the element active area this.m_struct_obj.visible_area_x=(int)this.GetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X); // Visibility scope X coordinate this.m_struct_obj.visible_area_y=(int)this.GetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y); // Visibility scope Y coordinate this.m_struct_obj.visible_area_w=(int)this.GetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH); // Visibility scope width this.m_struct_obj.visible_area_h=(int)this.GetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT); // Visibility scope height this.m_struct_obj.zorder=this.GetProperty(CANV_ELEMENT_PROP_ZORDER); // Priority of a graphical object for receiving the on-chart mouse click event this.m_struct_obj.enabled=(bool)this.GetProperty(CANV_ELEMENT_PROP_ENABLED); // Element availability flag //---... //---... this.m_struct_obj.tab_alignment=(int)this.GetProperty(CANV_ELEMENT_PROP_TAB_ALIGNMENT); // Location of tabs inside the control this.m_struct_obj.alignment=(int)this.GetProperty(CANV_ELEMENT_PROP_ALIGNMENT); // Location of an object inside the control //--- Save real properties //--- Save string properties ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_OBJ),this.m_struct_obj.name_obj); // Graphical element object name ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_NAME_RES),this.m_struct_obj.name_res); // Graphical resource name ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_TEXT),this.m_struct_obj.text); // Graphical element text ::StringToCharArray(this.GetProperty(CANV_ELEMENT_PROP_DESCRIPTION),this.m_struct_obj.descript);// Graphical element description //--- Save the structure to the uchar array ::ResetLastError(); if(!::StructToCharArray(this.m_struct_obj,this.m_uchar_array)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY,true); return false; } return true; } //+------------------------------------------------------------------+
構造体からオブジェクトを作成するメソッドで、範囲の可視性プロパティをオブジェクトプロパティに設定するようにします。
//+------------------------------------------------------------------+ //| Create the object from the structure | //+------------------------------------------------------------------+ void CGCnvElement::StructToObject(void) { //--- Save integer properties this.SetProperty(CANV_ELEMENT_PROP_ID,this.m_struct_obj.id); // Element ID this.SetProperty(CANV_ELEMENT_PROP_TYPE,this.m_struct_obj.type); // Graphical element type //---... //---... this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.m_struct_obj.coord_act_right); // Right border of the element active area this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.m_struct_obj.coord_act_bottom); // Bottom border of the element active area this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X,this.m_struct_obj.visible_area_x); // Visibility scope X coordinate this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y,this.m_struct_obj.visible_area_y); // Visibility scope Y coordinate this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH,this.m_struct_obj.visible_area_w); // Visibility scope width this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,this.m_struct_obj.visible_area_h); // Visibility scope height this.SetProperty(CANV_ELEMENT_PROP_ZORDER,this.m_struct_obj.zorder); // Priority of a graphical object for receiving the event of clicking on a chart this.SetProperty(CANV_ELEMENT_PROP_ENABLED,this.m_struct_obj.enabled); // Element availability flag //---... //---... this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR,this.m_struct_obj.fore_color); // Default text color for all control objects this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,this.m_struct_obj.fore_color_opacity); // Opacity of the default text color for all control objects //---... //---... this.SetProperty(CANV_ELEMENT_PROP_TAB_ALIGNMENT,this.m_struct_obj.tab_alignment); // Location of tabs inside the control this.SetProperty(CANV_ELEMENT_PROP_ALIGNMENT,this.m_struct_obj.alignment); // Location of an object inside the control //--- Save real properties //--- Save string properties this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,::CharArrayToString(this.m_struct_obj.name_obj)); // Graphical element object name this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,::CharArrayToString(this.m_struct_obj.name_res)); // Graphical resource name this.SetProperty(CANV_ELEMENT_PROP_TEXT,::CharArrayToString(this.m_struct_obj.text)); // Graphical element text this.SetProperty(CANV_ELEMENT_PROP_DESCRIPTION,::CharArrayToString(this.m_struct_obj.descript));// Graphical element description } //+------------------------------------------------------------------+
コントロールの幅と高さを設定するメソッドで、長方形の範囲の可視性プロパティを設定するようにします。
//+------------------------------------------------------------------+ //| Set a new width | //+------------------------------------------------------------------+ bool CGCnvElement::SetWidth(const int width) { if(this.GetProperty(CANV_ELEMENT_PROP_WIDTH)==width) return true; if(!this.m_canvas.Resize(width,this.m_canvas.Height())) { CMessage::ToLog(DFUN+this.TypeElementDescription()+": width="+(string)width+": ",MSG_CANV_ELEMENT_ERR_FAILED_SET_WIDTH); return false; } this.SetProperty(CANV_ELEMENT_PROP_WIDTH,width); this.SetVisibleAreaX(0,true); this.SetVisibleAreaWidth(width,true); return true; } //+------------------------------------------------------------------+ //| Set a new height | //+------------------------------------------------------------------+ bool CGCnvElement::SetHeight(const int height) { if(this.GetProperty(CANV_ELEMENT_PROP_HEIGHT)==height) return true; if(!this.m_canvas.Resize(this.m_canvas.Width(),height)) { CMessage::ToLog(DFUN+this.TypeElementDescription()+": height="+(string)height+": ",MSG_CANV_ELEMENT_ERR_FAILED_SET_HEIGHT); return false; } this.SetProperty(CANV_ELEMENT_PROP_HEIGHT,height); this.SetVisibleAreaY(0,true); this.SetVisibleAreaHeight(height,true); return true; } //+------------------------------------------------------------------+
グラフィック要素のサイズが変更された場合、それに応じて可視範囲が変更され、オブジェクト全体がカバーされるようにする必要があります。これがここでおこなっていることです。オブジェクトのサイズを変更するたびに、対応する可視範囲の新しいサイズを設定し、その開始座標をグラフィカルオブジェクトの左上隅でゼロに等しくします。
Erase()メソッドは次のようになります。
//+------------------------------------------------------------------+ //| Clear the element filling it with color and opacity | //+------------------------------------------------------------------+ void CGCnvElement::Erase(const color colour,const uchar opacity,const bool redraw=false) { this.EraseNoCrop(colour,opacity,false); this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+ //| Clear the element with a gradient fill | //+------------------------------------------------------------------+ void CGCnvElement::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false) { this.EraseNoCrop(colors,opacity,vgradient,cycle,false); this.Crop(); //--- If specified, update the canvas this.Update(redraw); } //+------------------------------------------------------------------+
最初にEraseNoCrop()メソッドを呼び出して、指定された色で更新を無効にして要素をクリアします。次に、Crop()メソッドを呼び出して非表示領域を切り取り、指定されたチャート更新フラグを持つキャンバスが更新されます。
以下は、非表示領域を切り取らずに色を使用してキャンバスを塗りつぶすメソッドです。
//+------------------------------------------------------------------+ //| Clear the element filling it with color and opacity | //| without cropping and with the chart update by flag | //+------------------------------------------------------------------+ void CGCnvElement::EraseNoCrop(const color colour,const uchar opacity,const bool redraw=false) { color arr[1]; arr[0]=colour; this.SaveColorsBG(arr); this.m_canvas.Erase(::ColorToARGB(colour,opacity)); this.Update(redraw); } //+------------------------------------------------------------------+ //| Clear the element with a gradient fill without cropping | //| but with updating the chart by flag | //+------------------------------------------------------------------+ void CGCnvElement::EraseNoCrop(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false) { //--- Set the vertical and cyclic gradient filling flags this.m_gradient_v=vgradient; this.m_gradient_c=cycle; //--- Check the size of the color array int size=::ArraySize(colors); //--- If there are less than two colors in the array if(size<2) { //--- if the array is empty, erase the background completely and leave if(size==0) { this.Erase(redraw); return; } //--- in case of one color, fill the background with this color and opacity, and leave this.EraseNoCrop(colors[0],opacity,redraw); return; } //--- Declare the receiver array color out[]; //--- Set the gradient size depending on the filling direction (vertical/horizontal) int total=(vgradient ? this.Height() : this.Width()); //--- and get the set of colors in the receiver array CColors::Gradient(colors,out,total,cycle); total=::ArraySize(out); //--- In the loop by the number of colors in the array for(int i=0;i<total;i++) { //--- depending on the filling direction switch(vgradient) { //--- Horizontal gradient - draw vertical segments from left to right with the color from the array case false : DrawLineVertical(i,0,this.Height()-1,out[i],opacity); break; //--- Vertical gradient - draw horizontal segments downwards with the color from the array default: DrawLineHorizontal(0,this.Width()-1,i,out[i],opacity); break; } } //--- Save the background color array this.SaveColorsBG(colors); this.Update(redraw); } //+------------------------------------------------------------------+
実際、これらは過去のErase()メソッドであり、現在は非表示領域を切り取りするメソッドが追加されており、新しいErase()メソッドはこれらのメソッドを呼び出してコンテナを超える領域を切り取りする機能を備えています。
以下は、指定された長方形の可視範囲によって輪郭が描かれた画像を切り取りするメソッドです。
//+--------------------------------------------------------------------+ //| Crop the image outlined by a specified rectangular visibility scope| //+--------------------------------------------------------------------+ void CGCnvElement::Crop(const uint coord_x,const uint coord_y,const uint width,const uint height) { //--- If the passed coordinates and the size of the visibility scope match the size of the object, leave if(coord_x==0 && coord_y==0 && width==this.Width() && height==this.Height()) return; //--- Set the coordinates and size of the visibility scope in the object properties this.SetVisibleAreaX(coord_x,true); this.SetVisibleAreaY(coord_y,true); this.SetVisibleAreaWidth(width,true); this.SetVisibleAreaHeight(height,true); //--- If the object in the current state has not yet been saved, //--- save its bitmap to the array for subsequent restoration if(::ArraySize(this.m_duplicate_res)==0) this.ResourceStamp(DFUN); //--- In the loop through the image lines of the graphical object for(int y=0;y<this.Height();y++) { //--- go through each pixel of the current line for(int x=0;x<this.Width();x++) { //--- If the string and its pixel are in the visibility scope, skip the pixel if(y>=this.VisibleAreaY() && y<=this.BottomEdgeVisibleAreaRelative() && x>=this.VisibleAreaX() && x<=this.RightEdgeVisibleAreaRelative()) continue; //--- If the line pixel is outside the visibility scope, set a transparent color for it this.SetPixel(x,y,CLR_CANV_NULL,0); } } } //+------------------------------------------------------------------+
コンテナを基準としたオブジェクトの可視領域の初期座標と、この領域のサイズがメソッドに渡されます。渡された値はオブジェクトのプロパティに設定され、設定された可視領域を超える画像ピクセルの消去(透明色での塗りつぶし)が2つのループで発生します。
以下は、計算された長方形の可視範囲によって輪郭が描かれた画像を切り取るメソッドです。
//+------------------------------------------------------------------+ //| Crop the image outlined by the calculated | //| rectangular visibility scope | //+------------------------------------------------------------------+ void CGCnvElement::Crop(void) { //--- Get the pointer to the base object CGCnvElement *base=this.GetBase(); //--- If the object does not have a base object it is attached to, then there is no need to crop the hidden areas - leave if(base==NULL) return; //--- Set the initial coordinates and size of the visibility scope to the entire object int vis_x=0; int vis_y=0; int vis_w=this.Width(); int vis_h=this.Height(); //--- Set the size of the top, bottom, left and right areas that go beyond the container int crop_top=0; int crop_bottom=0; int crop_left=0; int crop_right=0; //--- Calculate the boundaries of the container area, inside which the object is fully visible int top=fmax(base.CoordY()+(int)base.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_TOP),base.CoordYVisibleArea()); int bottom=fmin(base.BottomEdge()-(int)base.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM),base.BottomEdgeVisibleArea()+1); int left=fmax(base.CoordX()+(int)base.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_LEFT),base.CoordXVisibleArea()); int right=fmin(base.RightEdge()-(int)base.GetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT),base.RightEdgeVisibleArea()+1); //--- Calculate the values of the top, bottom, left and right areas, at which the object goes beyond //--- the boundaries of the container area, inside which the object is fully visible crop_top=this.CoordY()-top; if(crop_top<0) vis_y=-crop_top; crop_bottom=bottom-this.BottomEdge()-1; if(crop_bottom<0) vis_h=this.Height()+crop_bottom-vis_y; crop_left=this.CoordX()-left; if(crop_left<0) vis_x=-crop_left; crop_right=right-this.RightEdge()-1; if(crop_right<0) vis_w=this.Width()+crop_right-vis_x; //--- If there are areas that need to be hidden, call the cropping method with the calculated size of the object visibility scope if(crop_top<0 || crop_bottom<0 || crop_left<0 || crop_right<0) this.Crop(vis_x,vis_y,vis_w,vis_h); } //+------------------------------------------------------------------+
メソッドのロジックはコードのコメントで完全に説明されています。まず、このグラフィック要素が接続されているコンテナオブジェクトへのポインタを取得します。コンテナのサイズと、接続されたオブジェクトが表示される領域の端に応じて、コンテナに添付されたオブジェクトがこのコンテナ領域の境界をどれだけ超えるかを計算します。オブジェクトがいずれかの側の制限を超える場合、非表示にする必要がある画像の領域を切り取りするメソッドを呼び出します。
影オブジェクトクラスファイル(\MQL5\Include\DoEasy\Objects\Graph\ShadowObj.mqh)を改善してみましょう。
クラスコンストラクタで、作成されたオブジェクトの可視性フラグをhiddenに設定します。
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CShadowObj::CShadowObj(const long chart_id, const int subwindow, const string name, const int x, const int y, const int w, const int h) : CGCnvElement(GRAPH_ELEMENT_TYPE_SHADOW_OBJ,chart_id,subwindow,name,x,y,w,h) { this.m_type=OBJECT_DE_TYPE_GSHADOW; CGCnvElement::SetBackgroundColor(clrNONE,true); CGCnvElement::SetOpacity(0); CGCnvElement::SetActive(false); this.m_opacity=CLR_DEF_SHADOW_OPACITY; this.m_blur=DEF_SHADOW_BLUR; color gray=CGCnvElement::ChangeColorSaturation(this.ChartBackgroundColor(),-100); this.m_color=CGCnvElement::ChangeColorLightness(gray,-50); this.m_shadow=false; this.SetVisibleFlag(false,false); CGCnvElement::Erase(); } //+------------------------------------------------------------------+
影の描き方では、まずオブジェクトの可視性を確認します。オブジェクトが非表示の場合、描画するものは何もないので、終了します。
//+------------------------------------------------------------------+ //| Draw the object shadow | //+------------------------------------------------------------------+ void CShadowObj::Draw(const int shift_x,const int shift_y,const uchar blur_value,const bool redraw) { if(!this.IsVisible()) return; //--- Set the shadow shift values to the variables by X and Y axes this.SetCoordXRelative(shift_x); this.SetCoordYRelative(shift_y); //--- Calculate the height and width of the drawn rectangle int w=this.Width()-OUTER_AREA_SIZE*2; int h=this.Height()-OUTER_AREA_SIZE*2; //--- Draw a filled rectangle with calculated dimensions this.DrawShadowFigureRect(w,h); //--- Calculate the blur radius, which cannot exceed a quarter of the OUTER_AREA_SIZE constant this.m_blur=(blur_value>OUTER_AREA_SIZE/4 ? OUTER_AREA_SIZE/4 : blur_value); //--- If failed to blur the shape, exit the method (GaussianBlur() displays the error on the journal) if(!this.GaussianBlur(this.m_blur)) return; //--- Shift the shadow object by X/Y offsets specified in the method arguments and update the canvas CGCnvElement::Move(this.CoordX()+this.CoordXRelative(),this.CoordY()+this.CoordYRelative(),redraw); CGCnvElement::Update(redraw); } //+------------------------------------------------------------------+
フォームオブジェクトクラスファイル(\MQL5\Include\DoEasy\Objects\Graph\Form.mqh)にある、新しい接続された要素を作成して接続済みオブジェクトのリストに追加するメソッドで、以前に名前を変更したメソッドの名前を修正します。
//+------------------------------------------------------------------+ //| Create a new attached element | //| and add it to the list of bound objects | //+------------------------------------------------------------------+ CGCnvElement *CForm::CreateAndAddNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool activity) { //--- If the type of a created graphical element is less than the "element", inform of that and return 'false' if(element_type<GRAPH_ELEMENT_TYPE_ELEMENT) { ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_NOT_INTENDED),::StringSubstr(::EnumToString(element_type),19)); return NULL; } //--- Specify the element index in the list int num=this.m_list_elements.Total(); //--- Create a description of the default graphical element string descript=TypeGraphElementAsString(element_type); //--- Get the screen coordinates of the object relative to the coordinate system of the base object int elm_x=x; int elm_y=y; this.GetCoords(elm_x,elm_y); //--- Create a new graphical element CGCnvElement *obj=this.CreateNewGObject(element_type,num,descript,elm_x,elm_y,w,h,colour,opacity,false,activity); if(obj==NULL) return NULL; //--- and add it to the list of bound graphical elements if(!this.AddNewElement(obj,elm_x,elm_y)) { delete obj; return NULL; } //--- Set the minimum properties for a bound graphical element obj.SetBackgroundColor(colour,true); obj.SetOpacity(opacity); obj.SetActive(activity); obj.SetMain(this.GetMain()==NULL ? this.GetObject() : this.GetMain()); obj.SetBase(this.GetObject()); obj.SetID(this.GetMaxIDAll()+1); obj.SetNumber(num); obj.SetCoordXRelative(obj.CoordX()-this.CoordX()); obj.SetCoordYRelative(obj.CoordY()-this.CoordY()); obj.SetZorder(this.Zorder(),false); obj.SetCoordXRelativeInit(obj.CoordXRelative()); obj.SetCoordYRelativeInit(obj.CoordYRelative()); obj.SetVisibleFlag(this.IsVisible(),false); obj.SetActive(this.Active()); obj.SetEnabled(this.Enabled()); return obj; } //+------------------------------------------------------------------+
可視性フラグが有効になっている場合にのみ影が描画されるようになったため、影の描画メソッドで影のレンダリングと可視性フラグを有効にします。
//+------------------------------------------------------------------+ //| Draw the shadow | //+------------------------------------------------------------------+ void CForm::DrawShadow(const int shift_x,const int shift_y,const color colour,const uchar opacity=127,const uchar blur=DEF_SHADOW_BLUR) { //--- If the shadow flag is disabled, exit if(!this.m_shadow) return; //--- If there is no shadow object, create it if(this.m_shadow_obj==NULL) this.CreateShadowObj(colour,opacity); //--- If the shadow object exists, draw the shadow on it, //--- set the shadow object visibility flag and //--- move the form object to the foreground if(this.m_shadow_obj!=NULL) { this.m_shadow_obj.SetVisibleFlag(true,false); this.m_shadow_obj.Draw(shift_x,shift_y,blur,true); this.BringToTop(); } } //+------------------------------------------------------------------+
以前は、これらのメソッドが逆の順序で呼び出され、影が描画されませんでした。
すべてのWinFormsオブジェクトの基本オブジェクトのクラスのファイル(\MQL5\Include\DoEasy\Objects\Graph\WForms\WinFormBase.mqh)にあるErase()メソッドを改善します。
//+------------------------------------------------------------------+ //| Clear the element filling it with color and opacity | //+------------------------------------------------------------------+ void CWinFormBase::Erase(const color colour,const uchar opacity,const bool redraw=false) { //--- Fill the element having the specified color and the redrawing flag CGCnvElement::EraseNoCrop(colour,opacity,false); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE) this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.Opacity(),this.BorderStyle()); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+ //| Clear the element with a gradient fill | //+------------------------------------------------------------------+ void CWinFormBase::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false) { //--- Fill the element having the specified color array and the redrawing flag CGCnvElement::EraseNoCrop(colors,opacity,vgradient,cycle,false); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE) this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),this.Opacity(),this.BorderStyle()); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
ここで、まずグラフィック要素オブジェクトのEraseNoCrop()メソッドを呼び出し、次にフレームを描画して非表示領域を切り取ります。
要素の整数プロパティの説明を返すメソッドに、オブジェクトの新しいプロパティの説明(可視範囲の座標とサイズ)を返すコードブロックを追加します。
//+------------------------------------------------------------------+ //| Return the description of the control integer property | //+------------------------------------------------------------------+ string CWinFormBase::GetPropertyDescription(ENUM_CANV_ELEMENT_PROP_INTEGER property,bool only_prop=false) { return ( property==CANV_ELEMENT_PROP_ID ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ID)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_TYPE ? CMessage::Text(MSG_CANV_ELEMENT_PROP_TYPE)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.TypeElementDescription() ) : //---... //---... property==CANV_ELEMENT_PROP_ACT_RIGHT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ACT_RIGHT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ACT_BOTTOM ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ACT_BOTTOM)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_VISIBLE_AREA_X ? CMessage::Text(MSG_CANV_ELEMENT_PROP_VISIBLE_AREA_X)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_VISIBLE_AREA_Y ? CMessage::Text(MSG_CANV_ELEMENT_PROP_VISIBLE_AREA_Y)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH ? CMessage::Text(MSG_CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_GROUP ? CMessage::Text(MSG_GRAPH_OBJ_PROP_GROUP)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ZORDER ? CMessage::Text(MSG_GRAPH_OBJ_PROP_ZORDER)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : //---... //---... property==CANV_ELEMENT_PROP_TAB_PAGE_COLUMN ? CMessage::Text(MSG_CANV_ELEMENT_PROP_TAB_PAGE_COLUMN)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==CANV_ELEMENT_PROP_ALIGNMENT ? CMessage::Text(MSG_CANV_ELEMENT_PROP_ALIGNMENT)+ (only_prop ? "" : !this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+AlignmentDescription((ENUM_CANV_ELEMENT_ALIGNMENT)this.GetProperty(property)) ) : "" ); } //+------------------------------------------------------------------+
オブジェクトは、現在の記事で作成された新しいプロパティの名前を表示できるようになります。
構築の新しい概念に従って、標準コントロール基本オブジェクトクラスファイル(\MQL5\Include\DoEasy\Objects\Graph\WForms\CommonControls\CommonBase.mqh)にあるErase()メソッドを改善します。
//+------------------------------------------------------------------+ //| Clear the element filling it with color and opacity | //+------------------------------------------------------------------+ void CCommonBase::Erase(const color colour,const uchar opacity,const bool redraw=false) { //--- Fill the element having the specified color and the redrawing flag CGCnvElement::EraseNoCrop(colour,opacity,false); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE) this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),255,this.BorderStyle()); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+ //| Clear the element with a gradient fill | //+------------------------------------------------------------------+ void CCommonBase::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false) { //--- Fill the element having the specified color array and the redrawing flag CGCnvElement::EraseNoCrop(colors,opacity,vgradient,cycle,false); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE) this.DrawFormFrame(this.BorderSizeTop(),this.BorderSizeBottom(),this.BorderSizeLeft(),this.BorderSizeRight(),this.BorderColor(),255,this.BorderStyle()); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
ここでは、最初にグラフィック要素オブジェクトのEraseNoCrop()メソッドを呼び出し、次にフレームを描画して非表示領域を切り取ります。
CheckBox\MQL5\Include\DoEasy\Objects\Graph\WForms\CommonControls\CheckBox.mqh WinFormsオブジェクトクラスファイルのRedraw()メソッドを改善します。
//+------------------------------------------------------------------+ //| Redraw the object | //+------------------------------------------------------------------+ void CCheckBox::Redraw(bool redraw) { //--- Fill the object with the background color having full transparency this.EraseNoCrop(this.BackgroundColor(),this.Opacity(),true); //--- Set corrected text coordinates relative to the checkbox this.SetCorrectTextCoords(); //--- Draw the text and checkbox within the set coordinates of the object and the binding point, and update the object this.Text(this.m_text_x,this.m_text_y,this.Text(),this.ForeColor(),this.ForeColorOpacity(),this.TextAnchor()); this.ShowControlFlag(this.CheckState()); this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
ここでは、まず非表示領域を切り取らずにオブジェクトの色で画像をクリアし、(前におこなったように)必要なものをすべてキャンバスに描画し、画像の非表示領域を切り取るメソッドを呼び出します。
LabelWinFormsオブジェクトクラスのファイル(\MQL5\Include\DoEasy\Objects\Graph\WForms\CommonControls\Label.mqh)にある要素テキストを設定するメソッドで、それが設定された後、非表示エリアを切り取るメソッドを呼び出して、描画されたテキストが表示エリアの境界に沿って切り取られるように:します。
//--- Set the element text virtual void SetText(const string text) { CWinFormBase::SetText(text); if(this.AutoSize()) this.AutoSetWH(); this.Crop(); }
オブジェクトを再描画するメソッドで、Erase()メソッドの呼び出しをEraseNoCrop()メソッドの呼び出しに置き換えます。オブジェクトの外観を構築するすべての操作の後、画像の非表示領域を切り取るメソッドを呼び出します。
//+------------------------------------------------------------------+ //| Redraw the object | //+------------------------------------------------------------------+ void CLabel::Redraw(bool redraw) { //--- Fill the object with the background color having full transparency this.EraseNoCrop(this.BackgroundColor(),0,redraw); //--- Declare the variables for X and Y coordinates and set their values depending on the text alignment int x=0,y=0; this.SetTextParamsByAlign(x,y); //--- Draw the text within the set coordinates of the object and the binding point of the text, and update the object this.Text(x,y,this.Text(),this.ForeColor(),this.ForeColorOpacity(),this.TextAnchor()); this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
ボタンWinFormsオブジェクトファイル(\MQL5\Include\DoEasy\Objects\Graph\WForms\CommonControls\Button.mqh)で、同じ方法でオブジェクトの再描画方法を改善します。
//+------------------------------------------------------------------+ //| Redraw the object | //+------------------------------------------------------------------+ void CButton::Redraw(bool redraw) { //--- Fill the object with the background color this.EraseNoCrop(this.BackgroundColor(),this.Opacity(),redraw); //--- Declare the variables for X and Y coordinates and set their values depending on the text alignment int x=0,y=0; CLabel::SetTextParamsByAlign(x,y); //--- Draw the text within the set coordinates of the object and the binding point of the text, and update the object this.Text(x,y,this.Text(),this.ForeColor(),this.ForeColorOpacity(),this.TextAnchor()); this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
補助矢印ボタンオブジェクトのクラス
WinFormsオブジェクトのタブヘッダーが1行のレイアウトで、オブジェクトの幅または高さに収まりきらないほど多くのタブがある場合、コンテナを超えるタブヘッダーは非表示になります。ヘッダーバーを移動するために、矢印ボタンを作成する必要があります。それらをクリックすると、ヘッダーバーが左右または上下に移動します。他のコントロールにそのようなボタンが必要になるため、それらは補助WinFormsオブジェクトのリストに含まれます。これらは独立したコントロールではありませんが、他のコントロールを構築するために使用されます。
このような矢印付きのボタンオブジェクトは次のように配置されます。そのようなすべてのボタンの基本オブジェクトを作成します。これには、そのプロパティを設定するためのメソッドが含まれます。子孫オブジェクトは、上下左右矢印の特定のボタンを作成します。
さらに、作成したオブジェクトに基づいて、さらに2つ作成します。これらはWinForms TabControlオブジェクトの構築に使用されます。つまり、これらは2つのボタンを持つオブジェクトになります。2つ目では、上向き矢印と下向き矢印の付いた2つのボタンが垂直に配置されています。これらのオブジェクトは、タブヘッダーバーの水平および垂直スクロールに使用されます。
\MQL5\Include\DoEasy\Objects\Graph\WForms\ライブラリフォルダで、CArrowButtonクラスの新しいファイルArrowButton.mqhを作成します。
クラスはボタンオブジェクトクラスから派生するので、そのファイルを作成されたクラスファイルにインクルードする必要があります。
//+------------------------------------------------------------------+ //| ArrowButton.mqh | //| Copyright 2022, MetaQuotes Ltd. | //| https://mql5.com/ja/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://mql5.com/ja/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Common Controls\Button.mqh" //+------------------------------------------------------------------+ //| Arrow Button object class of WForms controls | //+------------------------------------------------------------------+ class CArrowButton : public CButton { }
privateセクションでは、矢印の色を格納する変数を宣言します。protectedセクションでは、矢印を描画するための仮想メソッドとprotectedコンストラクタを宣言します。publicセクションでは、矢印の色を設定して返すメソッド、パラメトリックコンストラクタ、オブジェクトを再描画してそのフレームを描画するメソッドを宣言します。
//+------------------------------------------------------------------+ //| Arrow Button object class of WForms controls | //+------------------------------------------------------------------+ class CArrowButton : public CButton { private: color m_arrow_color; // Arrow color protected: //--- Draw the arrow virtual void DrawArrow(void){return;} //--- Protected constructor with object type, chart ID and subwindow CArrowButton(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); public: //--- (1) Set and (2) return the arrow color void SetArrowColor(const color clr) { this.m_arrow_color=clr; } color ArrowColor(void) const { return this.m_arrow_color; } //--- Constructor CArrowButton(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); //--- Redraw the object virtual void Redraw(bool redraw); //--- Clear the element filling it with color and opacity virtual void Erase(const color colour,const uchar opacity,const bool redraw=false); //--- Clear the element with a gradient fill virtual void Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false); //--- Draw the button frame virtual void DrawFrame(void); }; //+------------------------------------------------------------------+
クラスのDrawArrow()仮想メソッドは何も描画しません。これは仮想であるため、継承されたクラスで再定義されます。各クラスは、左、右、上、下の矢印を描画するための独自のメソッドを作成します。
他のメソッドの目的は明らかだと思います。それらはすべて他のライブラリオブジェクトにあり、何度も検討してきました。
以下は、オブジェクトタイプ、チャートID、およびサブウィンドウを指定するprotectedコンストラクタです。
//+------------------------------------------------------------------+ //| Protected constructor with an object type, | //| chart ID and subwindow | //+------------------------------------------------------------------+ CArrowButton::CArrowButton(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CButton(type,chart_id,subwindow,descript,x,y,w,h) { //--- Set the specified graphical element type for the object and assign the library object type to the current object this.SetTypeElement(type); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetPaddingAll(0); this.SetMarginAll(0); this.SetBorderSizeAll(1); this.SetArrowColor(CLR_DEF_FORE_COLOR); } //+------------------------------------------------------------------+
作成されたオブジェクトの型がコンストラクタに渡され、それがチェーンに沿って残りの親オブジェクトに渡されます。コンストラクタの本体は、グラフィック要素のタイプ、ライブラリのグラフィックオブジェクトのタイプ、PaddingとMarginのゼロ値、1ピクセルのフレームのサイズ、矢印の色をコントロールのデフォルトのテキストの色として設定します。
これらすべてのパラメータ(オブジェクトタイプを除く)はオブジェクトを作成した後で変更できます。
パラメトリックコンストラクタでは、作成されるオブジェクトの型が渡されないことを除いて同じことをおこないますが、初期化文字列では、「矢印ボタン」型が親オブジェクトコンストラクタに渡されます。
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CArrowButton::CArrowButton(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CButton(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetPaddingAll(0); this.SetMarginAll(0); this.SetBorderSizeAll(1); this.SetArrowColor(CLR_DEF_FORE_COLOR); } //+------------------------------------------------------------------+
以下は、オブジェクトを再描画するメソッドです。
//+------------------------------------------------------------------+ //| Redraw the object | //+------------------------------------------------------------------+ void CArrowButton::Redraw(bool redraw) { //--- Fill the object with background color having transparency this.Erase(this.BackgroundColor(),this.Opacity(),true); } //+------------------------------------------------------------------+
再描画をおこなうErase()メソッドは、ここで呼び出されます。
//+------------------------------------------------------------------+ //| Clear the element filling it with color and opacity | //+------------------------------------------------------------------+ void CArrowButton::Erase(const color colour,const uchar opacity,const bool redraw=false) { //--- Fill the element having the specified color and the redrawing flag CGCnvElement::EraseNoCrop(colour,opacity,false); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE) this.DrawFrame(); this.DrawArrow(); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
ここでは、画像の非表示領域を切り取るという新しい概念に従って、他のすべてのオブジェクトとまったく同じです。EraseNoCrop()メソッド(オブジェクトが背景色で塗りつぶされる場所)が最初に呼び出され、次にフレームが描画され、矢印だけでなく、非表示領域が切り取られます。
以下は、グラデーションで塗りつぶされた要素をクリアするメソッドです。
//+------------------------------------------------------------------+ //| Clear the element with a gradient fill | //+------------------------------------------------------------------+ void CArrowButton::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false) { //--- Fill the element having the specified color array and the redrawing flag CGCnvElement::EraseNoCrop(colors,opacity,vgradient,cycle,false); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE) this.DrawFrame(); this.DrawArrow(); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
すべてが上記のメソッドとまったく同じです。オーバーロードされたEraeNoCrop()メソッドがここで呼び出されます。背景をグラデーションカラーで塗りつぶします。
以下は、要素の境界線を描画するメソッドです。
//+------------------------------------------------------------------+ //| Draw the element border | //+------------------------------------------------------------------+ void CArrowButton::DrawFrame(void) { this.DrawRectangle(0,0,this.Width()-1,this.Height()-1,this.BorderColor(),this.Opacity()); } //+------------------------------------------------------------------+
ここでは、指定された背景色と不透明度を使用して、オブジェクトの境界の周りに長方形を描くだけです。
このオブジェクトを作成すると、ラベルと矢印のない通常のボタンが単純に描画されます。矢印は、クラスの派生オブジェクトで描画されます。
以下は、左矢印ボタンオブジェクトです。
\MQL5\Include\DoEasy\Objects\Graph\WForms\ライブラリフォルダで、CArrowLeftButtonクラスの新しいファイルArrowLeftButton.mqhを作成します。クラスは、新しく作成された矢印ボタンの基本クラスから派生するので、そのファイルは作成されたクラスファイルにインクルードされる必要があります。
//+------------------------------------------------------------------+ //| ArrowLeftButton.mqh | //| Copyright 2022, MetaQuotes Ltd. | //| https://mql5.com/ja/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://mql5.com/ja/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "ArrowButton.mqh" //+------------------------------------------------------------------+ //| Left Arrow Button object class of WForms controls | //+------------------------------------------------------------------+ class CArrowLeftButton : public CArrowButton { }
クラスのprotectedセクションでは、矢印を描画するメソッドとprotectedコンストラクタを宣言し、publicセクションではパラメトリックコンストラクタを宣言します。
//+------------------------------------------------------------------+ //| Left Arrow Button object class of WForms controls | //+------------------------------------------------------------------+ class CArrowLeftButton : public CArrowButton { private: protected: //--- Draw the arrow virtual void DrawArrow(void); //--- Protected constructor with object type, chart ID and subwindow CArrowLeftButton(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); public: //--- Constructor CArrowLeftButton(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); }; //+------------------------------------------------------------------+
protectedコンストラクタでは、メソッドに渡されるグラフィック要素の型を設定し、パラメトリックコンストラクタでは、オブジェクト型を初期化文字列の「左矢印ボタン」として親クラスコンストラクタに渡し、同じ型をオブジェクトをオブジェクトに設定します。
//+------------------------------------------------------------------+ //| Protected constructor with an object type, | //| chart ID and subwindow | //+------------------------------------------------------------------+ CArrowLeftButton::CArrowLeftButton(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CArrowButton(type,chart_id,subwindow,descript,x,y,w,h) { //--- Set the specified graphical element type for the object and assign the library object type to the current object this.SetTypeElement(type); } //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CArrowLeftButton::CArrowLeftButton(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CArrowButton(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT); } //+------------------------------------------------------------------+
以下は、矢印を描くメソッドです。
//+------------------------------------------------------------------+ //| Draw the arrow | //+------------------------------------------------------------------+ void CArrowLeftButton::DrawArrow(void) { //--- Create X and Y coordinate arrays for drawing a triangle double x=(double)this.Width()/2; double y=(double)this.Height()/2; double w=(double)this.Width(); double h=(double)this.Height(); //--- Calculate coordinates as double values and write them to arrays as integers int array_x[]={int(w*0.7), int(w*0.7), int(w*0.3)}; int array_y[]={int(h*0.3), int(h*0.7), int(h*0.5)}; //--- Draw a filled triangle followed by a smoothed one on top of it this.DrawTriangleFill(array_x[0],array_y[0],array_x[1],array_y[1],array_x[2],array_y[2],this.ArrowColor()); this.DrawTriangleWu(array_x[0],array_y[0],array_x[1],array_y[1],array_x[2],array_y[2],this.ArrowColor()); } //+------------------------------------------------------------------+
この仮想メソッドは、さまざまな方向に矢印を描画するオブジェクトごとに異なります。ただし、描画された三角形の頂点の座標のみが異なります。このクラスと他の方向のボタンに矢印を描画する他のクラスとの違いは、グラフィック要素のタイプと、個々の座標に従って矢印を描画する仮想メソッドのみにあります。
上記のクラスは残りのクラスと完全に同一であり、これらのクラスはすべて同じライブラリフォルダ\MQL5\Include\DoEasy\Objects\Graph\WForms\にあるため、説明なしで全体を考えてみましょう。
以下は、ArrowRightButton.mqhファイルの右矢印ボタンオブジェクトクラスです。
//+------------------------------------------------------------------+ //| ArrowRightButton.mqh | //| Copyright 2022, MetaQuotes Ltd. | //| https://mql5.com/ja/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://mql5.com/ja/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "ArrowButton.mqh" //+------------------------------------------------------------------+ //| Right Arrow Button object class of WForms controls | //+------------------------------------------------------------------+ class CArrowRightButton : public CArrowButton { private: protected: //--- Draw the arrow virtual void DrawArrow(void); //--- Protected constructor with object type, chart ID and subwindow CArrowRightButton(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); public: //--- Constructor CArrowRightButton(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); }; //+------------------------------------------------------------------+ //| Protected constructor with an object type, | //| chart ID and subwindow | //+------------------------------------------------------------------+ CArrowRightButton::CArrowRightButton(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CArrowButton(type,chart_id,subwindow,descript,x,y,w,h) { //--- Set the specified graphical element type for the object and assign the library object type to the current object this.SetTypeElement(type); } //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CArrowRightButton::CArrowRightButton(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CArrowButton(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT); } //+------------------------------------------------------------------+ //| Draw the arrow | //+------------------------------------------------------------------+ void CArrowRightButton::DrawArrow(void) { //--- Create X and Y coordinate arrays for drawing a triangle double x=(double)this.Width()/2; double y=(double)this.Height()/2; double w=(double)this.Width(); double h=(double)this.Height(); //--- Calculate coordinates as double values and write them to arrays as integers int array_x[]={int(w*0.3), int(w*0.7), int(w*0.3)}; int array_y[]={int(h*0.3), int(h*0.5), int(h*0.7)}; //--- Draw a filled triangle followed by a smoothed one on top of it this.DrawTriangleFill(array_x[0],array_y[0],array_x[1],array_y[1],array_x[2],array_y[2],this.ArrowColor()); this.DrawTriangleWu(array_x[0],array_y[0],array_x[1],array_y[1],array_x[2],array_y[2],this.ArrowColor()); } //+------------------------------------------------------------------+
以下は、ArrowUpButton.mqhファイル内の上矢印ボタンオブジェクトクラスです。
//+------------------------------------------------------------------+ //| ArrowUpButton.mqh | //| Copyright 2022, MetaQuotes Ltd. | //| https://mql5.com/ja/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://mql5.com/ja/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "ArrowButton.mqh" //+------------------------------------------------------------------+ //| Up Arrow Button object class of WForms controls | //+------------------------------------------------------------------+ class CArrowUpButton : public CArrowButton { private: protected: //--- Draw the arrow virtual void DrawArrow(void); //--- Protected constructor with object type, chart ID and subwindow CArrowUpButton(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); public: //--- Constructor CArrowUpButton(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); }; //+------------------------------------------------------------------+ //| Protected constructor with an object type, | //| chart ID and subwindow | //+------------------------------------------------------------------+ CArrowUpButton::CArrowUpButton(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CArrowButton(type,chart_id,subwindow,descript,x,y,w,h) { //--- Set the specified graphical element type for the object and assign the library object type to the current object this.SetTypeElement(type); } //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CArrowUpButton::CArrowUpButton(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CArrowButton(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP); } //+------------------------------------------------------------------+ //| Draw the arrow | //+------------------------------------------------------------------+ void CArrowUpButton::DrawArrow(void) { //--- Create X and Y coordinate arrays for drawing a triangle double x=(double)this.Width()/2; double y=(double)this.Height()/2; double w=(double)this.Width(); double h=(double)this.Height(); //--- Calculate coordinates as double values and write them to arrays as integers int array_x[]={int(w*0.3), int(w*0.5), int(w*0.7)}; int array_y[]={int(h*0.7), int(h*0.3), int(h*0.7)}; //--- Draw a filled triangle followed by a smoothed one on top of it this.DrawTriangleFill(array_x[0],array_y[0],array_x[1],array_y[1],array_x[2],array_y[2],this.ArrowColor()); this.DrawTriangleWu(array_x[0],array_y[0],array_x[1],array_y[1],array_x[2],array_y[2],this.ArrowColor()); } //+------------------------------------------------------------------+
以下は、ArrowDownButton.mqhファイルの下矢印ボタンオブジェクトクラスです。
//+------------------------------------------------------------------+ //| ArrowDownButton.mqh | //| Copyright 2022, MetaQuotes Ltd. | //| https://mql5.com/ja/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://mql5.com/ja/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "ArrowButton.mqh" //+------------------------------------------------------------------+ //| Down Arrow Button object class of WForms controls | //+------------------------------------------------------------------+ class CArrowDownButton : public CArrowButton { private: protected: //--- Draw the arrow virtual void DrawArrow(void); //--- Protected constructor with object type, chart ID and subwindow CArrowDownButton(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); public: //--- Constructor CArrowDownButton(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); }; //+------------------------------------------------------------------+ //| Protected constructor with an object type, | //| chart ID and subwindow | //+------------------------------------------------------------------+ CArrowDownButton::CArrowDownButton(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CArrowButton(type,chart_id,subwindow,descript,x,y,w,h) { //--- Set the specified graphical element type for the object and assign the library object type to the current object this.SetTypeElement(type); } //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CArrowDownButton::CArrowDownButton(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CArrowButton(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN); } //+------------------------------------------------------------------+ //| Draw the arrow | //+------------------------------------------------------------------+ void CArrowDownButton::DrawArrow(void) { //--- Create X and Y coordinate arrays for drawing a triangle double x=(double)this.Width()/2; double y=(double)this.Height()/2; double w=(double)this.Width(); double h=(double)this.Height(); //--- Calculate coordinates as double values and write them to arrays as integers int array_x[]={int(w*0.3), int(w*0.5), int(w*0.7)}; int array_y[]={int(h*0.3), int(h*0.7), int(h*0.3)}; //--- Draw a filled triangle followed by a smoothed one on top of it this.DrawTriangleFill(array_x[0],array_y[0],array_x[1],array_y[1],array_x[2],array_y[2],this.ArrowColor()); this.DrawTriangleWu(array_x[0],array_y[0],array_x[1],array_y[1],array_x[2],array_y[2],this.ArrowColor()); } //+------------------------------------------------------------------+
これらのクラスはすべて同一です。クラスコンストラクタで設定されたオブジェクトのタイプのみの違いと、DrawArrow()メソッドの頂点の座標の値の違いに気付くことができます。
矢印付きのボタンオブジェクトの作成されたクラスに基づく、さらに2つの補助クラスがあります。それぞれに、2つのボタンが取り付けられるコンテナがあります。最初のクラスは左右のボタンが水平に配置されており、2番目のクラスは上下のボタンが垂直に配置されています。
\MQL5\Include\DoEasy\Objects\Graph\WForms\ライブラリフォルダで、CARrowLeftRightBoxの新しいファイルArrowLeftRightBox.mqhを作成します。
クラスは、コンテナオブジェクトのWinFormsクラスから派生するので、CPanelクラスファイルは、作成されたクラスのファイルに含める必要があります。
//+------------------------------------------------------------------+ //| ArrowLeftRightBox.mqh | //| Copyright 2022, MetaQuotes Ltd. | //| https://mql5.com/ja/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://mql5.com/ja/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Containers\Panel.mqh" //+------------------------------------------------------------------+ //| ArrowLeftRightBox object class of WForms controls | //+------------------------------------------------------------------+ class CArrowLeftRightBox : public CContainer { }
クラスのprivateセクションで、グラフィカルオブジェクトを作成するための仮想メソッドと、2つの矢印ボタンを作成するためのメソッドを宣言します。クラスのprotectedセクションでprotectedコンストラクタを宣言し、publicセクションで矢印付きのボタンオブジェクトへのポインタを取得する2つのメソッドを記述し、パラメトリックコンストラクタを宣言します。
//+------------------------------------------------------------------+ //| ArrowLeftRightBox object class of WForms controls | //+------------------------------------------------------------------+ class CArrowLeftRightBox : public CContainer { private: //--- Create a new graphical object virtual CGCnvElement *CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int element_num, const string descript, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable, const bool activity); //--- Create ArrowButton Up and Down objects void CreateArrowButtons(const int width,const int height); protected: //--- Protected constructor with object type, chart ID and subwindow CArrowLeftRightBox(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); public: //--- Return the pointer to the (1) up and (2) down arrow button CArrowLeftButton *GetArrowUpButton(void) { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,0); } CArrowRightButton*GetArrowDownButton(void) { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,0); } //--- Constructor CArrowLeftRightBox(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); }; //+------------------------------------------------------------------+
宣言されたメソッドの実装について考えてみましょう。
以下は、オブジェクトタイプ、チャートID、およびサブウィンドウを指定するprotectedコンストラクタです。
//+------------------------------------------------------------------+ //| Protected constructor with an object type, | //| chart ID and subwindow | //+------------------------------------------------------------------+ CArrowLeftRightBox::CArrowLeftRightBox(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CContainer(type,chart_id,subwindow,descript,x,y,w,h) { //--- Set the specified graphical element type for the object and assign the library object type to the current object this.SetTypeElement(type); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetBorderSizeAll(1); this.SetBorderStyle(FRAME_STYLE_SIMPLE); this.SetBorderColor(CLR_DEF_BORDER_COLOR,true); this.SetForeColor(CLR_DEF_FORE_COLOR,true); this.CreateArrowButtons((w<DEF_ARROW_BUTTON_SIZE ? w : DEF_ARROW_BUTTON_SIZE),(h<DEF_ARROW_BUTTON_SIZE ? h : DEF_ARROW_BUTTON_SIZE)); } //+------------------------------------------------------------------+
ここでは、コンストラクタに渡されるグラフィック要素のタイプを設定し、ライブラリのグラフィックオブジェクトのタイプを「補助オブジェクト」として設定し、オブジェクトフレームのサイズを1ピクセルに設定します。フレームタイプはフラット、フレームの色はデフォルトです。矢印のデフォルトの色は、WinFormsオブジェクトのデフォルトのテキストの色と一致し、2つの矢印ボタンを作成するメソッドを呼び出します。この場合、コンストラクタに渡された幅と高さが、デフォルトの矢印を持つボタンオブジェクトの指定されたサイズよりも小さい場合、オブジェクトは指定されたサイズで構築されます。それ以外の場合は、デフォルトのサイズで構築されます。したがって、デフォルトのボタンサイズセットは、矢印ボタンオブジェクトの最大値です。
以下は、チャートとサブウィンドウIDを持つパラメトリックコンストラクタです。
//+------------------------------------------------------------------+ //| Constructor indicating the chart and subwindow ID | //+------------------------------------------------------------------+ CArrowLeftRightBox::CArrowLeftRightBox(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CContainer(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetBorderSizeAll(1); this.SetBorderStyle(FRAME_STYLE_SIMPLE); this.SetBorderColor(CLR_DEF_BORDER_COLOR,true); this.SetForeColor(CLR_DEF_FORE_COLOR,true); this.CreateArrowButtons((w<DEF_ARROW_BUTTON_SIZE ? w : DEF_ARROW_BUTTON_SIZE),(h<DEF_ARROW_BUTTON_SIZE ? h : DEF_ARROW_BUTTON_SIZE)); } //+------------------------------------------------------------------+
グラフィック要素の型がコンストラクタに渡されず、ArrowLeftRightButtonBoxとしてハードコーディングされていることを除いて、すべてがprotectedコンストラクタと同じです。
以下は、ArrowButtonLeftおよびRightオブジェクトを作成するメソッドです。
//+------------------------------------------------------------------+ //| Create ArrowButton Left and Right objects | //+------------------------------------------------------------------+ void CArrowLeftRightBox::CreateArrowButtons(const int width,const int height) { //--- Calculate the width of the object from the width of two buttons plus the size of the frame on the left and right //--- and the height of the object from the height of the button plus the top and bottom frame sizes int w=width*2+this.BorderSizeLeft()+this.BorderSizeRight(); int h=height+this.BorderSizeTop()+this.BorderSizeBottom(); //--- If the received width or height is greater than the width or height of the object, resize it if(w>this.Width() || h>this.Height()) this.Resize((w>this.Width() ? w : this.Width()),(h>this.Height() ? h : this.Height()),false); //--- Create two buttons next to each other starting from the 0 : 0 coordinate of the container this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,0,0,width,height,clrNONE,255,true,false); this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,width,0,width,height,clrNONE,255,true,false); } //+------------------------------------------------------------------+
作成するボタンのサイズをメソッドに渡します。ボタンのサイズに基づいて、コンテナの幅は、オブジェクトフレームのサイズを考慮して、2つのボタンの幅のサイズとして計算されます。コンテナの高さは、コンテナフレームのサイズを考慮して、ボタンの高さから取得されます。ボタンの計算されたサイズがコンテナのサイズよりも大きい場合、そのサイズは計算されたサイズまで増加されますが、メソッドが呼び出されて、水平に配置されたボタンが横に並んで作成されます。
以下は新しいグラフィックオブジェクトを作成するメソッドです。
//+------------------------------------------------------------------+ //| Create a new graphical object | //+------------------------------------------------------------------+ CGCnvElement *CArrowLeftRightBox::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int obj_num, const string descript, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable, const bool activity) { CGCnvElement *element=NULL; switch(type) { case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT : element=new CArrowLeftButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT : element=new CArrowRightButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; default: break; } if(element==NULL) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type)); return element; } //+------------------------------------------------------------------+
仮想メソッドでは、左矢印ボタンと右矢印ボタンの2つのオブジェクトのみを作成できます。
垂直に配置された2つのボタンを持つコンテナを作成するクラスは、上記で検討したものと同じです。
\MQL5\Include\DoEasy\Objects\Graph\WForms\ライブラリフォルダで、CArrowUpDownBoxクラスの新しいファイルArrowUpDownBox.mqhを作成します。
クラスはコンテナオブジェクトのWinFormsクラスから派生するので、CPanelクラスファイルは作成されたクラスのファイルにインクルードする必要があります。
//+------------------------------------------------------------------+ //| ArrowUpDownBox.mqh | //| Copyright 2022, MetaQuotes Ltd. | //| https://mql5.com/ja/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://mql5.com/ja/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Containers\Panel.mqh" //+------------------------------------------------------------------+ //| ArrowUpDownBox object class of the WForms controls | //+------------------------------------------------------------------+ class CArrowUpDownBox : public CContainer { private: //--- Create a new graphical object virtual CGCnvElement *CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int element_num, const string descript, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable, const bool activity); //--- Create ArrowButton Up and Down objects void CreateArrowButtons(const int width,const int height); protected: //--- Protected constructor with object type, chart ID and subwindow CArrowUpDownBox(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); public: //--- Return the pointer to the (1) up and (2) down arrow button CArrowUpButton *GetArrowUpButton(void) { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,0); } CArrowDownButton *GetArrowDownButton(void) { return this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,0); } //--- Constructor CArrowUpDownBox(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h); }; //+------------------------------------------------------------------+ //| Protected constructor with an object type, | //| chart ID and subwindow | //+------------------------------------------------------------------+ CArrowUpDownBox::CArrowUpDownBox(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CContainer(type,chart_id,subwindow,descript,x,y,w,h) { //--- Set the specified graphical element type for the object and assign the library object type to the current object this.SetTypeElement(type); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetBorderSizeAll(1); this.SetBorderStyle(FRAME_STYLE_SIMPLE); this.SetBorderColor(CLR_DEF_BORDER_COLOR,true); this.SetForeColor(CLR_DEF_FORE_COLOR,true); this.CreateArrowButtons((w<DEF_ARROW_BUTTON_SIZE ? w : DEF_ARROW_BUTTON_SIZE),(h<DEF_ARROW_BUTTON_SIZE ? h : DEF_ARROW_BUTTON_SIZE)); } //+------------------------------------------------------------------+ //| Constructor indicating the chart and subwindow ID | //+------------------------------------------------------------------+ CArrowUpDownBox::CArrowUpDownBox(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CContainer(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetBorderSizeAll(1); this.SetBorderStyle(FRAME_STYLE_SIMPLE); this.SetBorderColor(CLR_DEF_BORDER_COLOR,true); this.SetForeColor(CLR_DEF_FORE_COLOR,true); this.CreateArrowButtons((w<DEF_ARROW_BUTTON_SIZE ? w : DEF_ARROW_BUTTON_SIZE),(h<DEF_ARROW_BUTTON_SIZE ? h : DEF_ARROW_BUTTON_SIZE)); } //+------------------------------------------------------------------+ //| Create ArrowButton Up and Down objects | //+------------------------------------------------------------------+ void CArrowUpDownBox::CreateArrowButtons(const int width,const int height) { //--- Calculate the width of the object from the width of the button plus the size of the frame on the left and right //--- and the height of the object from the height of two buttons plus the top and bottom frame sizes int w=width+this.BorderSizeLeft()+this.BorderSizeRight(); int h=height*2+this.BorderSizeTop()+this.BorderSizeBottom(); //--- If the received width or height is greater than the width or height of the object, resize it if(w>this.Width() || h>this.Height()) this.Resize((w>this.Width() ? w : this.Width()),(h>this.Height() ? h : this.Height()),false); //--- Create two buttons one above the other starting from the 0 : 0 coordinate of the container this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,0,0,width,height,clrNONE,255,true,false); this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,0,height,width,height,clrNONE,255,true,false); } //+------------------------------------------------------------------+ //| Create a new graphical object | //+------------------------------------------------------------------+ CGCnvElement *CArrowUpDownBox::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int obj_num, const string descript, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable, const bool activity) { CGCnvElement *element=NULL; switch(type) { case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP : element=new CArrowUpButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN : element=new CArrowDownButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; default: break; } if(element==NULL) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type)); return element; } //+------------------------------------------------------------------+
上記の2つのクラスの違いは、クラスコンストラクタで設定されるグラフィック要素のタイプと、2つのボタンを作成するためのメソッドのみです。2番目のクラスでは、このメソッドは垂直に配置されたボタンを作成し、2つのボタンの高さに合わせてコンテナのサイズを変更します。両方のメソッドは、コードの右側に完全にコメントされているので、追加の説明が必要ないことを願っています。
これらのオブジェクトはどちらも、次の記事で、タブが水平方向と垂直方向に1行に配置され、コントロールを超えて非表示になっている場合に、タブのヘッダーバーをスクロールするために使用されます。
新しいグラフィック要素を作成したので、コンテナオブジェクトを調整して、新しいオブジェクトを認識し、作成できるようにする必要があります。
コンテナオブジェクトクラスファイル(\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Container.mqh)で、作業領域のサイズと座標を返すメソッドの名前を変更して、それらの名前が同様のメソッドの名前に対応するようにするために、「Get」プレフィックスを削除します。
public: //--- Return the size and coordinates of the working area int WidthWorkspace(void) const { return this.Width()-::fmax(this.BorderSizeLeft(),this.PaddingLeft())-::fmax(this.BorderSizeRight(),this.PaddingRight()); } int HeightWorkspace(void) const { return this.Height()-::fmax(this.BorderSizeTop(),this.PaddingTop())-::fmax(this.BorderSizeBottom(),this.PaddingBottom()); } int CoordXWorkspace(void) const { return this.CoordX()+::fmax(this.BorderSizeLeft(),this.PaddingLeft()); } int CoordYWorkspace(void) const { return this.CoordY()+::fmax(this.BorderSizeTop(),this.PaddingTop()); } int RightEdgeWorkspace(void) const { return this.RightEdge()-::fmax(this.BorderSizeRight(),this.PaddingRight()); } int BottomEdgeWorkspace(void) const { return this.BottomEdge()-::fmax(this.BorderSizeBottom(),this.PaddingBottom()); } //--- Return the list of bound WinForms objects with (1) any and (2) specified WinForms object type (from the base one and higher)
非表示のオブジェクト領域を切り取りするための仮想メソッドを宣言します。
virtual void SetBorderSizeBottom(const uint value) { CForm::SetBorderSizeBottom(value); if(this.PaddingBottom()<this.BorderSizeBottom()) this.SetPaddingBottom(this.BorderSizeBottom()); } //--- Crop the image outlined by the specified rectangular visibility area virtual void Crop(void); protected:
このようなメソッドは、ライブラリのすべての主要なWinFormsオブジェクトに含まれている必要があります。
新しい接続された要素を作成するメソッドで、新しく作成されたオブジェクトのCrop()メソッドの呼び出しを追加します。
//+------------------------------------------------------------------+ //| Create a new attached element | //+------------------------------------------------------------------+ bool CContainer::CreateNewElement(const ENUM_GRAPH_ELEMENT_TYPE element_type, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool activity, const bool redraw) { //--- If the object type is less than the base WinForms object if(element_type<GRAPH_ELEMENT_TYPE_WF_BASE) { //--- report the error and return 'false' CMessage::ToLog(DFUN,MSG_PANEL_OBJECT_ERR_OBJ_MUST_BE_WFBASE); return false; } //--- If failed to create a new graphical element, return 'false' CWinFormBase *obj=CForm::CreateAndAddNewElement(element_type,x,y,w,h,colour,opacity,activity); if(obj==NULL) return false; //--- Set parameters for the created object this.SetObjParams(obj,colour); //--- If the panel has auto resize enabled and features bound objects, call the resize method if(this.AutoSize() && this.ElementsTotal()>0) this.AutoSizeProcess(redraw); //--- Crop along the edges of the visible part obj.Crop(); //--- return 'true' return true; } //+------------------------------------------------------------------+
新しいオブジェクトを作成し、その中に作成されたオブジェクトに合わせてコンテナのサイズを変更した後(コンテナの自動サイズ変更フラグを設定して)、新しく作成されたオブジェクトがコンテナ領域を超えていないかどうかを確認する必要があります。さらに、この領域の外に出る新しいオブジェクトの画像の部分を切り取る必要があります。
接続されたオブジェクトにパラメータを設定するメソッドで、基本オブジェクトとメインオブジェクトへのポインタの実装を追加し、作成されてコンテナに接続された矢印ボタンオブジェクトのパラメータを設定するためのコードブロックを記述します。
//+------------------------------------------------------------------+ //| Set parameters for the attached object | //+------------------------------------------------------------------+ void CContainer::SetObjParams(CWinFormBase *obj,const color colour) { obj.SetMain(this.GetMain()==NULL ? this.GetObject() : this.GetMain()); obj.SetBase(this.GetObject()); //--- Set the text color of the object to be the same as that of the base container obj.SetForeColor(this.ForeColor(),true); //--- If the created object is not a container, set the same group for it as the one for its base object if(obj.TypeGraphElement()<GRAPH_ELEMENT_TYPE_WF_CONTAINER || obj.TypeGraphElement()>GRAPH_ELEMENT_TYPE_WF_GROUPBOX) obj.SetGroup(this.Group()); //--- Depending on the object type switch(obj.TypeGraphElement()) { //--- For the Container, Panel and GroupBox WinForms objects case GRAPH_ELEMENT_TYPE_WF_CONTAINER : case GRAPH_ELEMENT_TYPE_WF_PANEL : case GRAPH_ELEMENT_TYPE_WF_GROUPBOX : //--- set the frame color equal to the background color obj.SetBorderColor(obj.BackgroundColor(),true); break; //--- For "Label", "CheckBox" and "RadioButton" WinForms objects case GRAPH_ELEMENT_TYPE_WF_LABEL : case GRAPH_ELEMENT_TYPE_WF_CHECKBOX : case GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON : //--- set the object text color depending on the one passed to the method: //--- either the container text color, or the one passed to the method. //--- The frame color is set equal to the text color //--- Set the background color to transparent obj.SetForeColor(colour==clrNONE ? this.ForeColor() : colour,true); obj.SetBorderColor(obj.ForeColor(),true); obj.SetBackgroundColor(CLR_CANV_NULL,true); obj.SetOpacity(0,false); break; //--- For "Button", "TabHeader", TabField and "ListBoxItem" WinForms objects case GRAPH_ELEMENT_TYPE_WF_BUTTON : case GRAPH_ELEMENT_TYPE_WF_TAB_HEADER : case GRAPH_ELEMENT_TYPE_WF_TAB_FIELD : case GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM : //--- set the object text color as a container text color depending on the one passed to the method: //--- set the background color depending on the one passed to the method: //--- either the default standard control background color, or the one passed to the method. //--- The frame color is set equal to the text color obj.SetForeColor(this.ForeColor(),true); obj.SetBackgroundColor(colour==clrNONE ? CLR_DEF_CONTROL_STD_BACK_COLOR : colour,true); obj.SetBorderColor(obj.ForeColor(),true); obj.SetBorderStyle(FRAME_STYLE_SIMPLE); break; //--- For "ListBox", "CheckedListBox" and "ButtonListBox" WinForms object case GRAPH_ELEMENT_TYPE_WF_LIST_BOX : case GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX : case GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX : //--- set the object text color as a container text color depending on the one passed to the method: //--- set the background color depending on the one passed to the method: //--- either the default standard control background color, or the one passed to the method. //--- The frame color is set equal to the text color obj.SetBackgroundColor(colour==clrNONE ? CLR_DEF_CONTROL_STD_BACK_COLOR : colour,true); obj.SetBorderColor(CLR_DEF_BORDER_COLOR,true); obj.SetForeColor(CLR_DEF_FORE_COLOR,true); break; //--- For the "TabControl", "ArrowButton" WinForms object case GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL : //--- set the object text color as a container text color depending on the one passed to the method: //--- set the background color depending on the one passed to the method: //--- either the default standard control background color, or the one passed to the method. //--- The frame color is set equal to the text color obj.SetBackgroundColor(colour==clrNONE ? CLR_DEF_CONTROL_TAB_BACK_COLOR : colour,true); obj.SetBorderColor(CLR_DEF_CONTROL_TAB_BORDER_COLOR,true); obj.SetForeColor(CLR_DEF_FORE_COLOR,true); obj.SetOpacity(CLR_DEF_CONTROL_TAB_OPACITY); break; //--- For the "ArrowButton" WinForms object case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON : case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP : case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN : case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT : case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT : //--- set the object text color as a container text color depending on the one passed to the method: //--- set the background color depending on the one passed to the method: //--- either the default standard control background color, or the one passed to the method. //--- The frame color is set equal to the text color obj.SetBorderColor(CLR_DEF_CONTROL_TAB_HEAD_BORDER_COLOR,true); obj.SetBorderStyle(FRAME_STYLE_SIMPLE); break; default: break; } obj.Crop(); } //+------------------------------------------------------------------+
メソッドの最後に、作成されたオブジェクトの非表示領域を切り取ります。
Crop()メソッドの呼び出しは、前のメソッドで接続要素を作成するとき、およびそのメソッドでデフォルトプロパティを設定した後に冗長になる可能性があります。さらにテストすると、Crop()メソッドの呼び出しを削除できるメソッドがわかります。
計算された長方形の可視範囲によって輪郭が描かれた画像を切り取るメソッドの実装を書きましょう。
//+------------------------------------------------------------------+ //| Crop the image outlined by the calculated | //| rectangular visibility scope | //+------------------------------------------------------------------+ void CContainer::Crop(void) { //--- Get the pointer to the base object CContainer *base=this.GetBase(); //--- If the object does not have a base object it is attached to, then there is no need to crop the hidden areas - leave if(base==NULL) return; //--- Set the initial coordinates and size of the visibility scope to the entire object int vis_x=0; int vis_y=0; int vis_w=this.Width(); int vis_h=this.Height(); //--- Set the size of the top, bottom, left and right areas that go beyond the container int crop_top=0; int crop_bottom=0; int crop_left=0; int crop_right=0; //--- Calculate the boundaries of the container area, inside which the object is fully visible int top=fmax(base.CoordYWorkspace(),base.CoordYVisibleArea()); int bottom=fmin(base.BottomEdgeWorkspace(),base.BottomEdgeVisibleArea()+1); int left=fmax(base.CoordXWorkspace(),base.CoordXVisibleArea()); int right=fmin(base.RightEdgeWorkspace(),base.RightEdgeVisibleArea()+1); //--- Calculate the values of the top, bottom, left and right areas, at which the object goes beyond //--- the boundaries of the container area, inside which the object is fully visible crop_top=this.CoordY()-top; if(crop_top<0) vis_y=-crop_top; crop_bottom=bottom-this.BottomEdge()-1; if(crop_bottom<0) vis_h=this.Height()+crop_bottom-vis_y; crop_left=this.CoordX()-left; if(crop_left<0) vis_x=-crop_left; crop_right=right-this.RightEdge()-1; if(crop_right<0) vis_w=this.Width()+crop_right-vis_x; //--- If there are areas that need to be hidden, call the cropping method with the calculated size of the object visibility scope if(crop_top<0 || crop_bottom<0 || crop_left<0 || crop_right<0) this.Crop(vis_x,vis_y,vis_w,vis_h); } //+------------------------------------------------------------------+
このメソッドは、CGCnvElementグラフィック要素オブジェクトクラスで記述したものと同じですが、基本オブジェクトタイプをCGCnvElementとして取得する代わりに、CContainerコンテナオブジェクトタイプで基本オブジェクトを取得します。内部でオブジェクトが完全に表示されるコンテナ領域の境界を計算するには、基本グラフィック要素には存在しないコンテナ作業領域の境界を返すメソッドを使用します。
ArrangeObjects()メソッドでは、以前に名前が変更されたメソッドの名前は、Getプレフィックスが既に削除されており、現在の名前に既に置き換えられています。
次は例です。
//+------------------------------------------------------------------+ //| Place bound objects in the order of their Dock binding | //+------------------------------------------------------------------+ bool CContainer::ArrangeObjects(const bool redraw) { //--- Get the list of bound objects with WinForms type basic and higher CArrayObj *list=this.GetListWinFormsObj(); CWinFormBase *prev=NULL, *obj=NULL, *elm=NULL; //--- In the loop by all bound objects, for(int i=0;i<list.Total();i++) { //--- Get the current and previous elements from the list obj=list.At(i); prev=list.At(i-1); //--- If the object is not received, move on if(obj==NULL) continue; int x=0, y=0; // Object binding coordinates //--- Depending on the current object binding mode... //--- Top if(obj.DockMode()==CANV_ELEMENT_DOCK_MODE_TOP) { //--- If failed to change the object size (for the entire working area width and by the initial object height), move on to the next one if(!obj.Resize(this.WidthWorkspace(),obj.GetHeightInit(),false)) continue; //--- Get the object binding coordinates x=this.CoordXWorkspace(); y=(prev!=NULL ? prev.BottomEdge()+1 : this.CoordYWorkspace()); //--- If failed to move the object to the obtained coordinates, move on to the next one if(!obj.Move(x,y,false)) continue; } //--- Bottom
メソッドにはそのような類似の置換が多数ありますが、それらはすべて既に作成されており、ここで説明する意味はありません。これらは、コードを記述する際のIntellisenseの使いやすさのカテゴリからの単なる改善であり、そのロジックには影響しません。
\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\Panel.mqhのパネルオブジェクトクラスを改善します。
今日作成されたすべての新しいクラスのファイルをそれにインクルードします。
//+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Container.mqh" #include "..\TabField.mqh" #include "..\ArrowButton.mqh" #include "..\ArrowUpButton.mqh" #include "..\ArrowDownButton.mqh" #include "..\ArrowLeftButton.mqh" #include "..\ArrowRightButton.mqh" #include "..\ArrowUpDownBox.mqh" #include "..\ArrowLeftRightBox.mqh" #include "GroupBox.mqh" #include "TabControl.mqh" #include "..\..\WForms\Common Controls\ListBox.mqh" #include "..\..\WForms\Common Controls\CheckedListBox.mqh" #include "..\..\WForms\Common Controls\ButtonListBox.mqh" //+------------------------------------------------------------------+
これで、これらのクラスは、それらを作成できるライブラリのすべてのグラフィカルオブジェクトで表示されるようになります。
新しいグラフィカルオブジェクトを作成するメソッドに、新しく作成されたすべてのオブジェクトを作成するためのコードブロックを追加します。
//+------------------------------------------------------------------+ //| Create a new graphical object | //+------------------------------------------------------------------+ CGCnvElement *CPanel::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int obj_num, const string descript, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable, const bool activity) { CGCnvElement *element=NULL; switch(type) { case GRAPH_ELEMENT_TYPE_ELEMENT : element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),descript,x,y,w,h,colour,opacity,movable,activity); break; case GRAPH_ELEMENT_TYPE_FORM : element=new CForm(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CONTAINER : element=new CContainer(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_GROUPBOX : element=new CGroupBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_PANEL : element=new CPanel(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LABEL : element=new CLabel(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CHECKBOX : element=new CCheckBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON : element=new CRadioButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_BUTTON : element=new CButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LIST_BOX : element=new CListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM : element=new CListBoxItem(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX : element=new CCheckedListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX : element=new CButtonListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_HEADER : element=new CTabHeader(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_FIELD : element=new CTabField(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL : element=new CTabControl(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON : element=new CArrowButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP : element=new CArrowUpButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN : element=new CArrowDownButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT : element=new CArrowLeftButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT : element=new CArrowRightButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX : element=new CArrowUpDownBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX : element=new CArrowLeftRightBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; default: break; } if(element==NULL) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type)); return element; } //+------------------------------------------------------------------+
アンダーレイオブジェクトを作成するメソッドで、呼び出された以前に名前が変更されたメソッドの名前を変更します。
//+------------------------------------------------------------------+ //| Create the underlay object | //+------------------------------------------------------------------+ bool CPanel::CreateUnderlayObj(void) { this.m_underlay=new CGCnvElement(GRAPH_ELEMENT_TYPE_WF_UNDERLAY,this.ID(),this.Number(),this.ChartID(),this.SubWindow(),this.NameObj()+"Underlay", this.CoordXWorkspace(),this.CoordYWorkspace(),this.WidthWorkspace(),this.HeightWorkspace(), CLR_CANV_NULL,0,false,false); if(m_underlay==NULL) { CMessage::ToLog(DFUN,MSG_PANEL_OBJECT_ERR_FAILED_CREATE_UNDERLAY_OBJ); return false; } if(!this.m_list_tmp.Add(this.m_underlay)) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST); delete this.m_underlay; return false; } this.SetUnderlayParams(); return true; } //+------------------------------------------------------------------+
GroupBoxコントロールクラスファイル(\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\GroupBox.mqh)にある新しいグラフィカルオブジェクトを作成するメソッドで、前のクラス:と同じように、ここで作成したすべての新しいオブジェクトを作成するためのコードブロックを追加します。
//+------------------------------------------------------------------+ //| Create a new graphical object | //+------------------------------------------------------------------+ CGCnvElement *CGroupBox::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int obj_num, const string descript, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable, const bool activity) { CGCnvElement *element=NULL; switch(type) { case GRAPH_ELEMENT_TYPE_ELEMENT : element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),descript,x,y,w,h,colour,opacity,movable,activity); break; case GRAPH_ELEMENT_TYPE_FORM : element=new CForm(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CONTAINER : element=new CContainer(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_GROUPBOX : element=new CGroupBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_PANEL : element=new CPanel(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LABEL : element=new CLabel(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CHECKBOX : element=new CCheckBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON : element=new CRadioButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_BUTTON : element=new CButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LIST_BOX : element=new CListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM : element=new CListBoxItem(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX : element=new CCheckedListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX : element=new CButtonListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_HEADER : element=new CTabHeader(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_FIELD : element=new CTabField(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL : element=new CTabControl(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON : element=new CArrowButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP : element=new CArrowUpButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN : element=new CArrowDownButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT : element=new CArrowLeftButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT : element=new CArrowRightButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX : element=new CArrowUpDownBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX : element=new CArrowLeftRightBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; default: break; } if(element==NULL) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type)); return element; } //+------------------------------------------------------------------+
要素をクリアするメソッドは、他のクラスの以前に最終化された同じメソッドに従って改善されました。
//+------------------------------------------------------------------+ //| Clear the element filling it with color and opacity | //+------------------------------------------------------------------+ void CGroupBox::Erase(const color colour,const uchar opacity,const bool redraw=false) { //--- Fill the element having the specified color and the redrawing flag CGCnvElement::EraseNoCrop(colour,opacity,false); //--- Draw a frame encasing a group of objects this.DrawFrame(); //--- Draw a header above the frame CGCnvElement::Text(6,0,this.Text(),this.ForeColor(),this.ForeColorOpacity()); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+ //| Clear the element with a gradient fill | //+------------------------------------------------------------------+ void CGroupBox::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false) { //--- Fill the element having the specified color array and the redrawing flag CGCnvElement::EraseNoCrop(colors,opacity,vgradient,cycle,false); //--- Draw a frame encasing a group of objects this.DrawFrame(); //--- Draw a header above the frame CGCnvElement::Text(6,0,this.Text(),this.ForeColor(),this.ForeColorOpacity()); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
通常どおり、背景色で塗りつぶし、必要なデザイン要素を描画し、表示領域外の余分な要素を切り取ります。
\MQL5\Include\DoEasy\Objects\Graph\WForms\TabHeader.mqhのTabControlタブのヘッダーオブジェクトクラスを改善します。
クラスのpublicセクションでオブジェクトを再描画するメソッドを宣言します。
//--- Sets the state of the control virtual void SetState(const bool flag); //--- Redraw the object virtual void Redraw(bool redraw); //--- Clear the element filling it with color and opacity
クラスコンストラクタで、要素のライブラリのグラフィカルオブジェクトの型を「補助WinFormsオブジェクト」として設定します。
//+------------------------------------------------------------------+ //| Protected constructor with an object type, | //| chart ID and subwindow | //+------------------------------------------------------------------+ CTabHeader::CTabHeader(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CButton(type,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_TAB_HEADER); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetAlignment(CANV_ELEMENT_ALIGNMENT_TOP); this.SetToggleFlag(true); //---... //---... this.SetSizes(w,h); this.SetState(false); } //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTabHeader::CTabHeader(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CButton(GRAPH_ELEMENT_TYPE_WF_TAB_HEADER,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_TAB_HEADER); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetAlignment(CANV_ELEMENT_ALIGNMENT_TOP); this.SetToggleFlag(true); //---... //---... this.SetSizes(w,h); this.SetState(false); } //+------------------------------------------------------------------+
コントロールの状態を設定するメソッドで、オブジェクトが表示されている場合にのみヘッダーをフォアグラウンドに追加します。同様に、タブフィールドオブジェクトを処理します。オブジェクトを表示し、前景に移動し、デザイン要素を描画し、オブジェクトが表示されている場合にのみ切り取りします。
//+------------------------------------------------------------------+ //| Set the state of the control | //+------------------------------------------------------------------+ void CTabHeader::SetState(const bool flag) { //--- Get the button state and set the new one passed to the method bool state=this.State(); CButton::SetState(flag); //--- If the previous state of the button does not match the set if(state!=this.State()) { //--- If the button is pressed if(this.State()) { //--- Call the button resizing method and bring it to the foreground this.WHProcessStateOn(); if(this.IsVisible()) this.BringToTop(); //--- Get the base object the tab title is attached to (TabControl) CWinFormBase *base=this.GetBase(); if(base==NULL) return; //--- Set the index of the selected tab to the TabControl object base.SetProperty(CANV_ELEMENT_PROP_TAB_PAGE_NUMBER,this.PageNumber()); //--- Get the list of tab field objects from the base object CArrayObj *list=base.GetListElementsByType(GRAPH_ELEMENT_TYPE_WF_TAB_FIELD); if(list==NULL) return; //--- In the loop through the received list, hide all fields that do not match the header for(int i=0;i<list.Total();i++) { //--- get the next tab field object CWinFormBase *obj=list.At(i); //--- If the object is not received or corresponds to the selected header, move on if(obj==NULL || obj.GetProperty(CANV_ELEMENT_PROP_TAB_PAGE_NUMBER)==this.PageNumber()) continue; //--- Set the ZOrder tab field as the base object and hide the field obj.SetZorder(base.Zorder(),false); obj.Hide(); } //--- Get the field object corresponding to the field header (this object) CWinFormBase *field=this.GetFieldObj(); if(field==NULL) return; //--- Display the field and set its ZOrder higher than other fields of the TabControl object, //--- draw the frame of the field object and bring it to the foreground field.SetZorder(base.Zorder()+1,false); if(this.IsVisible()) { field.Show(); field.DrawFrame(); field.Crop(); field.BringToTop(); } } //--- If the button is not pressed, call the method to restore the title size else { this.WHProcessStateOff(); CWinFormBase *field=this.GetFieldObj(); field.Hide(); } } } //+------------------------------------------------------------------+
ボタンが押されていない場合、タブフィールドオブジェクトは非表示になります。
すべてのグラフィック要素の新しい概念に従って、要素のクリーニングメソッドが改善されました。
//+------------------------------------------------------------------+ //| Clear the element filling it with color and opacity | //+------------------------------------------------------------------+ void CTabHeader::Erase(const color colour,const uchar opacity,const bool redraw=false) { //--- Fill the element having the specified color and the redrawing flag CGCnvElement::EraseNoCrop(colour,opacity,false); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE) this.DrawFrame(); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+ //| Clear the element with a gradient fill | //+------------------------------------------------------------------+ void CTabHeader::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false) { //--- Fill the element having the specified color array and the redrawing flag CGCnvElement::EraseNoCrop(colors,opacity,vgradient,cycle,false); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE) this.DrawFrame(); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
色で塗りつぶし、デザイン要素を描き、余分な部分を切り取ります。
以下は、オブジェクトを再描画するメソッドです。
//+------------------------------------------------------------------+ //| Redraw the object | //+------------------------------------------------------------------+ void CTabHeader::Redraw(bool redraw) { //--- Fill the object with the background color this.Erase(this.BackgroundColor(),this.Opacity(),false); //--- Declare the variables for X and Y coordinates and set their values depending on the text alignment int x=0,y=0; CLabel::SetTextParamsByAlign(x,y); //--- Draw the text within the set coordinates of the object and the binding point of the text, and update the object this.Text(x,y,this.Text(),this.ForeColor(),this.ForeColorOpacity(),this.TextAnchor()); this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
ここでは、オブジェクトを色で塗りつぶすメソッドを呼び出し、テキスト出力パラメータを設定し、テキストを描画してから、コンテナを超える画像の領域を切り取りします。
「カーソルがアクティブエリア内にあり、マウスの左ボタンがクリックされた」イベントのハンドラ(MouseActiveAreaReleasedHandler()メソッド)で、タブヘッダーをクリックした後に要素に表示するとき、
タブフィールドの切り取りを追加します。
//--- If this is the toggle button, else { //--- if the button does not work in the group, set its state to the opposite, if(!this.GroupButtonFlag()) this.SetState(!this.State()); //--- if the button is not pressed yet, set it to the pressed state else if(!this.State()) this.SetState(true); //--- set the background and text color for "The cursor is over the active area" status depending on whether the button is clicked or not this.SetBackgroundColor(this.State() ? this.BackgroundStateOnColorMouseOver() : this.BackgroundColorMouseOver(),false); this.SetForeColor(this.State() ? this.ForeStateOnColorMouseOver() : this.ForeColorMouseOver(),false); //--- Get the field object corresponding to the header CWinFormBase *field=this.GetFieldObj(); if(field!=NULL) { //--- Display the field, bring it to the front and draw a frame field.Show(); field.BringToTop(); field.DrawFrame(); field.Crop(); } //--- Redraw an object and a chart this.Redraw(true); } //--- Send the test message to the journal Print(DFUN_ERR_LINE,TextByLanguage("Щелчок","Click"),", this.State()=",this.State(),", ID=",this.ID(),", Group=",this.Group()); //--- Set the frame color for "The cursor is over the active area" status this.SetBorderColor(this.BorderColorMouseOver(),false); } } //+------------------------------------------------------------------+
\MQL5\Include\DoEasy\Objects\Graph\WForms\TabField.mqhのタブフィールドオブジェクトクラスを改善します。
クラスコンストラクタで、ライブラリグラフィカルオブジェクトの型を「補助WinFormsオブジェクト」として設定します。
//+------------------------------------------------------------------+ //| Protected constructor with an object type, | //| chart ID and subwindow | //+------------------------------------------------------------------+ CTabField::CTabField(const ENUM_GRAPH_ELEMENT_TYPE type, const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CContainer(type,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_TAB_FIELD); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetBorderSizeAll(1); this.SetBorderStyle(FRAME_STYLE_SIMPLE); //---... //---... this.SetForeColor(CLR_DEF_FORE_COLOR,true); this.SetPaddingAll(3); } //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTabField::CTabField(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CContainer(GRAPH_ELEMENT_TYPE_WF_TAB_FIELD,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_TAB_FIELD); this.m_type=OBJECT_DE_TYPE_GWF_HELPER; this.SetBorderSizeAll(1); this.SetBorderStyle(FRAME_STYLE_SIMPLE); //---... //---... this.SetForeColor(CLR_DEF_FORE_COLOR,true); this.SetPaddingAll(3); } //+------------------------------------------------------------------+
要素をクリアするメソッドは、WinFormsオブジェクトの以前のすべてのクラスと同じように改善されました。
//+------------------------------------------------------------------+ //| Clear the element filling it with color and opacity | //+------------------------------------------------------------------+ void CTabField::Erase(const color colour,const uchar opacity,const bool redraw=false) { //--- Fill the element having the specified color and the redrawing flag CGCnvElement::EraseNoCrop(colour,opacity,false); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE) this.DrawFrame(); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+ //| Clear the element with a gradient fill | //+------------------------------------------------------------------+ void CTabField::Erase(color &colors[],const uchar opacity,const bool vgradient,const bool cycle,const bool redraw=false) { //--- Fill the element having the specified color array and the redrawing flag CGCnvElement::EraseNoCrop(colors,opacity,vgradient,cycle,false); //--- If the object has a frame, draw it if(this.BorderStyle()!=FRAME_STYLE_NONE) this.DrawFrame(); //--- Update the element having the specified redrawing flag this.Crop(); this.Update(redraw); } //+------------------------------------------------------------------+
新しいグラフィカルオブジェクトを作成するメソッドに、ここで作成されたすべての新しいオブジェクトを構築するためのコードブロックを追加します。
//+------------------------------------------------------------------+ //| Create a new graphical object | //+------------------------------------------------------------------+ CGCnvElement *CTabField::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int obj_num, const string descript, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable, const bool activity) { CGCnvElement *element=NULL; switch(type) { case GRAPH_ELEMENT_TYPE_ELEMENT : element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),descript,x,y,w,h,colour,opacity,movable,activity); break; case GRAPH_ELEMENT_TYPE_FORM : element=new CForm(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CONTAINER : element=new CContainer(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_GROUPBOX : element=new CGroupBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_PANEL : element=new CPanel(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LABEL : element=new CLabel(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CHECKBOX : element=new CCheckBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON : element=new CRadioButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_BUTTON : element=new CButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LIST_BOX : element=new CListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM : element=new CListBoxItem(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX : element=new CCheckedListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX : element=new CButtonListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_HEADER : element=new CTabHeader(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_FIELD : element=new CTabField(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL : element=new CTabControl(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON : element=new CArrowButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP : element=new CArrowUpButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN : element=new CArrowDownButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT : element=new CArrowLeftButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT : element=new CArrowRightButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX : element=new CArrowUpDownBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX : element=new CArrowLeftRightBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; default: break; } if(element==NULL) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type)); return element; } //+------------------------------------------------------------------+
\MQL5\Include\DoEasy\Objects\Graph\WForms\Containers\TabControl.mqhのTabControl WinFormsオブジェクトを改善しましょう。
このオブジェクトについては、カスタムメソッドを作成して前面に移動し、表示する必要があります。このような親クラスのメソッドは、コンテナに接続されたすべてのオブジェクトをループして移動し、それらすべてを前面に移動してすべて表示します。このロジックは、TabControlには適していません。親クラスのメソッドによって表示され、最前面に表示される隠しフィールドが含まれていますが、これは容認できません。ここでは、最初にフィールドが選択したタブに属していることを確認する必要があります。このフィールドのみを表示して最前面に移動し、他のすべてを非表示にする必要があります。
クラスのpublicセクションでこれら2つの仮想メソッドを宣言しましょう。
//--- Returns the (1) index, (2) the pointer to the selected tab int SelectedTabPageNum(void) const { return (int)this.GetProperty(CANV_ELEMENT_PROP_TAB_PAGE_NUMBER);} CWinFormBase *SelectedTabPage(void) { return this.GetTabField(this.SelectedTabPageNum()); } //--- Set the object above all virtual void BringToTop(void); //--- Show the control virtual void Show(void); //--- Constructor
クラスコンストラクタでは、必ずPaddingを0に設定してください。そうしないと、接続されたオブジェクトが表示される領域のサイズが、両側で3ピクセルずつ切り取りされて(デフォルトでは、Paddingは3ピクセルに)フィールドが不適切な場所で切り取りされます(コンテナの輪郭に沿って、サイズが3ピクセル)。
//+------------------------------------------------------------------+ //| Constructor indicating the chart and subwindow ID | //+------------------------------------------------------------------+ CTabControl::CTabControl(const long chart_id, const int subwindow, const string descript, const int x, const int y, const int w, const int h) : CContainer(GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,chart_id,subwindow,descript,x,y,w,h) { this.SetTypeElement(GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL); this.m_type=OBJECT_DE_TYPE_GWF_CONTAINER; this.SetBorderSizeAll(0); this.SetBorderStyle(FRAME_STYLE_NONE); this.SetOpacity(0,true); this.SetBackgroundColor(CLR_CANV_NULL,true); this.SetBackgroundColorMouseDown(CLR_CANV_NULL); this.SetBackgroundColorMouseOver(CLR_CANV_NULL); this.SetBorderColor(CLR_CANV_NULL,true); this.SetBorderColorMouseDown(CLR_CANV_NULL); this.SetBorderColorMouseOver(CLR_CANV_NULL); this.SetForeColor(CLR_DEF_FORE_COLOR,true); this.SetAlignment(CANV_ELEMENT_ALIGNMENT_TOP); this.SetItemSize(58,18); this.SetTabSizeMode(CANV_ELEMENT_TAB_SIZE_MODE_NORMAL); this.SetPaddingAll(0); this.SetHeaderPadding(6,3); this.SetFieldPadding(3,3,3,3); } //+------------------------------------------------------------------+
指定した数のタブを作成するメソッドで、ヘッダーの座標とタブフィールドのサイズを2ピクセルずつ調整します。また、タブヘッダーの表示フラグは、コントロールの表示フラグと一致する必要があります。この場合、非表示のオブジェクトのタブヘッダーは表示されません。
//+------------------------------------------------------------------+ //| Create the specified number of tabs | //+------------------------------------------------------------------+ bool CTabControl::CreateTabPages(const int total,const int selected_page,const int tab_w=0,const int tab_h=0,const string header_text="") { //--- Calculate the size and initial coordinates of the tab title int w=(tab_w==0 ? this.ItemWidth() : tab_w); int h=(tab_h==0 ? this.ItemHeight() : tab_h); //--- In the loop by the number of tabs CTabHeader *header=NULL; CTabField *field=NULL; for(int i=0;i<total;i++) { //--- Depending on the location of tab titles, set their initial coordinates int header_x=2; int header_y=2; int header_w=w; int header_h=h; //--- Set the current X and Y coordinate depending on the location of the tab headers switch(this.Alignment()) { case CANV_ELEMENT_ALIGNMENT_TOP : header_w=w; header_h=h; header_x=(header==NULL ? 2 : header.RightEdgeRelative()); header_y=2; break; case CANV_ELEMENT_ALIGNMENT_BOTTOM : header_w=w; header_h=h; header_x=(header==NULL ? 2 : header.RightEdgeRelative()); header_y=this.Height()-header_h; break; case CANV_ELEMENT_ALIGNMENT_LEFT : header_w=h; header_h=w; header_x=2; header_y=(header==NULL ? this.Height()-header_h-2 : header.CoordYRelative()-header_h); break; case CANV_ELEMENT_ALIGNMENT_RIGHT : header_w=h; header_h=w; header_x=this.Width()-header_w-2; header_y=(header==NULL ? 2 : header.BottomEdgeRelative()); break; default: break; } //--- Create the TabHeader object if(!this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_TAB_HEADER,header_x,header_y,header_w,header_h,clrNONE,255,this.Active(),false)) { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(GRAPH_ELEMENT_TYPE_WF_TAB_HEADER),string(i+1)); return false; } header=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_TAB_HEADER,i); if(header==NULL) { ::Print(DFUN,CMessage::Text(MSG_ELM_LIST_ERR_FAILED_GET_GRAPH_ELEMENT_OBJ),this.TypeElementDescription(GRAPH_ELEMENT_TYPE_WF_TAB_HEADER),string(i+1)); return false; } header.SetBase(this.GetObject()); header.SetPageNumber(i); header.SetGroup(this.Group()+1); header.SetBackgroundColor(CLR_DEF_CONTROL_TAB_HEAD_BACK_COLOR,true); header.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_TAB_HEAD_MOUSE_DOWN); header.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_TAB_HEAD_MOUSE_OVER); header.SetBackgroundStateOnColor(CLR_DEF_CONTROL_TAB_HEAD_BACK_COLOR_ON,true); header.SetBackgroundStateOnColorMouseDown(CLR_DEF_CONTROL_TAB_HEAD_BACK_DOWN_ON); header.SetBackgroundStateOnColorMouseOver(CLR_DEF_CONTROL_TAB_HEAD_BACK_OVER_ON); header.SetBorderStyle(FRAME_STYLE_SIMPLE); header.SetBorderColor(CLR_DEF_CONTROL_TAB_HEAD_BORDER_COLOR,true); header.SetBorderColorMouseDown(CLR_DEF_CONTROL_TAB_HEAD_BORDER_MOUSE_DOWN); header.SetBorderColorMouseOver(CLR_DEF_CONTROL_TAB_HEAD_BORDER_MOUSE_OVER); header.SetAlignment(this.Alignment()); header.SetPadding(this.HeaderPaddingWidth(),this.HeaderPaddingHeight(),this.HeaderPaddingWidth(),this.HeaderPaddingHeight()); if(header_text!="" && header_text!=NULL) this.SetHeaderText(header,header_text+string(i+1)); else this.SetHeaderText(header,"TabPage"+string(i+1)); if(this.Alignment()==CANV_ELEMENT_ALIGNMENT_LEFT) header.SetFontAngle(90); if(this.Alignment()==CANV_ELEMENT_ALIGNMENT_RIGHT) header.SetFontAngle(270); header.SetTabSizeMode(this.TabSizeMode()); //--- Save the initial height of the header and set its size in accordance with the header size setting mode int h_prev=header_h; header.SetSizes(header_w,header_h); //--- Get the Y offset of the header position after changing its height and //--- shift it by the calculated value only for headers on the left int y_shift=header.Height()-h_prev; if(header.Move(header.CoordX(),header.CoordY()-(this.Alignment()==CANV_ELEMENT_ALIGNMENT_LEFT ? y_shift : 0))) { header.SetCoordXRelative(header.CoordX()-this.CoordX()); header.SetCoordYRelative(header.CoordY()-this.CoordY()); } header.SetVisibleFlag(this.IsVisible(),false); //--- Depending on the location of the tab headers, set the initial coordinates of the tab fields int field_x=0; int field_y=0; int field_w=this.Width(); int field_h=this.Height()-header.Height()-2; int header_shift=0; switch(this.Alignment()) { case CANV_ELEMENT_ALIGNMENT_TOP : field_x=0; field_y=header.BottomEdgeRelative(); field_w=this.Width(); field_h=this.Height()-header.Height()-2; break; case CANV_ELEMENT_ALIGNMENT_BOTTOM : field_x=0; field_y=0; field_w=this.Width(); field_h=this.Height()-header.Height(); break; case CANV_ELEMENT_ALIGNMENT_LEFT : field_x=header.RightEdgeRelative(); field_y=0; field_h=this.Height(); field_w=this.Width()-header.Width()-2; break; case CANV_ELEMENT_ALIGNMENT_RIGHT : field_x=0; field_y=0; field_h=this.Height(); field_w=this.Width()-header.Width()-2; break; default: break; } //--- Create the TabField object (tab field) if(!this.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_TAB_FIELD,field_x,field_y,field_w,field_h,clrNONE,255,true,false)) { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(GRAPH_ELEMENT_TYPE_WF_TAB_FIELD),string(i+1)); return false; } field=this.GetElementByType(GRAPH_ELEMENT_TYPE_WF_TAB_FIELD,i); if(field==NULL) { ::Print(DFUN,CMessage::Text(MSG_ELM_LIST_ERR_FAILED_GET_GRAPH_ELEMENT_OBJ),this.TypeElementDescription(GRAPH_ELEMENT_TYPE_WF_TAB_FIELD),string(i+1)); return false; } field.SetBase(this.GetObject()); field.SetPageNumber(i); field.SetGroup(this.Group()+1); field.SetBorderSizeAll(1); field.SetBorderStyle(FRAME_STYLE_SIMPLE); field.SetOpacity(CLR_DEF_CONTROL_TAB_PAGE_OPACITY,true); field.SetBackgroundColor(CLR_DEF_CONTROL_TAB_PAGE_BACK_COLOR,true); field.SetBackgroundColorMouseDown(CLR_DEF_CONTROL_TAB_PAGE_MOUSE_DOWN); field.SetBackgroundColorMouseOver(CLR_DEF_CONTROL_TAB_PAGE_MOUSE_OVER); field.SetBorderColor(CLR_DEF_CONTROL_TAB_PAGE_BORDER_COLOR,true); field.SetBorderColorMouseDown(CLR_DEF_CONTROL_TAB_PAGE_BORDER_MOUSE_DOWN); field.SetBorderColorMouseOver(CLR_DEF_CONTROL_TAB_PAGE_BORDER_MOUSE_OVER); field.SetForeColor(CLR_DEF_FORE_COLOR,true); field.SetPadding(this.FieldPaddingLeft(),this.FieldPaddingTop(),this.FieldPaddingRight(),this.FieldPaddingBottom()); field.Hide(); } //--- Arrange all titles in accordance with the specified display modes and select the specified tab this.ArrangeTabHeaders(); this.Select(selected_page,true); return true; } //+------------------------------------------------------------------+
ヘッダーを2ピクセル分オフセットすると、ヘッダーがコンテナの内側に配置されます。選択したヘッダーが2ピクセル増加するため、コンテナの外側に移動します。その後、2ピクセル増加した部分はコンテナを超えて見えなくなるため、安全に切り取りされます。ヘッダー座標をシフトすることでこの問題は解決しますが、同時に、タブフィールドは現在2ピクセルシフトされているヘッダーの座標から座標を取得するため、コンテナ内に収まるようにタブフィールドも2ピクセル縮小する必要があります。
コントロールの幅に合わせてタブヘッダーを拡大するメソッド(StretchHeadersByWidth())でヘッダーの幅の計算を変更します。これで、幅は最も近い整数に丸められて計算されるようになり、行内の配置が少し見やすくなります。
//--- Get the width of the container, as well as the number of headers in a row, and calculate the width of each header int base_size=this.Width()-4; int num=list_row.Total(); int w=(int)round((double)base_size/double(num>0 ? num : 1)); //--- In the loop by row headers for(int j=0;j<list_row.Total();j++) {
タブを選択状態に設定するメソッドでは、残りのタブは強制的にリリース状態に設定されます。
//+------------------------------------------------------------------+ //| Set the tab as selected | //+------------------------------------------------------------------+ void CTabControl::SetSelected(const int index) { //--- Get the header by index and CTabHeader *header=this.GetTabHeader(index); if(header==NULL) return; //--- set it to the "selected" state if(!header.State()) { CArrayObj *list=this.GetListHeaders(); if(list==NULL) return; for(int i=0;i<list.Total();i++) { if(i==index) continue; this.SetUnselected(i); } header.SetState(true); } //--- save the index of the selected tab this.SetSelectedTabPageNum(index); } //+------------------------------------------------------------------+
選択したタブのインデックスがメソッドに渡されます。すべてのタブヘッダーのリストによるループで、ループインデックスを確認します。選択したタブのインデックスと等しい場合、ループは次の反復に送られます。ループインデックスが選択したタブのインデックスと等しくない場合は、ループインデックスで指定されたタブを解放状態に設定するメソッドを呼び出します。
テキストを設定したら、指定したタブのヘッダーテキストを設定するメソッドで、ヘッダーの非表示領域を切り取りするメソッドを呼び出します。
//+------------------------------------------------------------------+ //| Set the title text of the specified tab | //+------------------------------------------------------------------+ void CTabControl::SetHeaderText(CTabHeader *header,const string text) { if(header==NULL) return; header.SetText(text); header.Crop(); } //+------------------------------------------------------------------+
これにより、ヘッダーのテキストが部分的に範囲外にある場合に切り取りされます。
新しいグラフィカルオブジェクトを作成するメソッドに、ここで作成されたすべての新しいオブジェクトを構築するためのコードブロックを追加します。
//+------------------------------------------------------------------+ //| Create a new graphical object | //+------------------------------------------------------------------+ CGCnvElement *CTabControl::CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int obj_num, const string descript, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable, const bool activity) { CGCnvElement *element=NULL; switch(type) { case GRAPH_ELEMENT_TYPE_ELEMENT : element=new CGCnvElement(type,this.ID(),obj_num,this.ChartID(),this.SubWindow(),descript,x,y,w,h,colour,opacity,movable,activity); break; case GRAPH_ELEMENT_TYPE_FORM : element=new CForm(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CONTAINER : element=new CContainer(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_GROUPBOX : element=new CGroupBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_PANEL : element=new CPanel(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LABEL : element=new CLabel(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CHECKBOX : element=new CCheckBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON : element=new CRadioButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_BUTTON : element=new CButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LIST_BOX : element=new CListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM : element=new CListBoxItem(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX : element=new CCheckedListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX : element=new CButtonListBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_HEADER : element=new CTabHeader(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_FIELD : element=new CTabField(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL : element=new CTabControl(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON : element=new CArrowButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP : element=new CArrowUpButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN : element=new CArrowDownButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT : element=new CArrowLeftButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT : element=new CArrowRightButton(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX : element=new CArrowUpDownBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; case GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX : element=new CArrowLeftRightBox(this.ChartID(),this.SubWindow(),descript,x,y,w,h); break; default: break; } if(element==NULL) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),this.TypeElementDescription(type)); return element; } //+------------------------------------------------------------------+
以下は、コントロールを表示するメソッドです。
//+------------------------------------------------------------------+ //| Show the control | //+------------------------------------------------------------------+ void CTabControl::Show(void) { //--- Get the list of all tab headers CArrayObj *list=this.GetListHeaders(); if(list==NULL) return; //--- If the object has a shadow, display it if(this.m_shadow_obj!=NULL) this.m_shadow_obj.Show(); //--- Display the container CGCnvElement::Show(); //--- Move all elements of the object to the foreground this.BringToTop(); } //+------------------------------------------------------------------+
最初に、オブジェクトのコンテナが表示され(通常の状態では透明色ですが、ユーザーが指定した任意の色にすることができます)、次に、オブジェクトのすべての要素を前面に表示するメソッドが呼び出されます。以下でこのメソッドについて考えてみます。
以下は、オブジェクトを一番上(フォアグラウンド)に設定するメソッドです。
//+------------------------------------------------------------------+ //| Set the object above all the rest | //+------------------------------------------------------------------+ void CTabControl::BringToTop(void) { //--- Move all elements of the object to the foreground CForm::BringToTop(); //--- Get the index of the selected tab int selected=this.SelectedTabPageNum(); //--- Declare the pointers to tab header objects and tab fields CTabHeader *header=NULL; CTabField *field=NULL; //--- Get the list of all tab headers CArrayObj *list=this.GetListHeaders(); if(list==NULL) return; //--- In a loop by the list of tab headers, for(int i=0;i<list.Total();i++) { //--- get the next header, and if failed to get the object, //--- or this is the header of the selected tab, skip it header=list.At(i); if(header==NULL || header.PageNumber()==selected) continue; //--- bring the header to the foreground header.BringToTop(); //--- get the tab field corresponding to the current header field=header.GetFieldObj(); if(field==NULL) continue; //--- Hide the tab field field.Hide(); } //--- Get the pointer to the title of the selected tab header=this.GetTabHeader(selected); if(header!=NULL) { //--- bring the header to the front header.BringToTop(); //--- get the tab field corresponding to the selected tab header field=header.GetFieldObj(); //--- Display the tab field on the foreground if(field!=NULL) field.BringToTop(); } } //+------------------------------------------------------------------+
メソッドのロジックは、コードコメントで詳しく説明されています。つまり、現在選択されているタブのすべてのヘッダーとフィールドを前面に表示する必要があります。これをおこなうには、選択したタブのヘッダーを除くすべてのヘッダーをループでフォアグラウンドに表示し、これらのタブのフィールドを非表示にします。
最後に、選択したタブのヘッダーとそのフィールドをフォアグラウンドに表示します。
これらの調整により、TabControlは、選択されていないタブのフィールドをフォアグラウンドに誤って切り替えることなく機能し、非表示から表示に切り替えたときに正しく表示されます。
\MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqhのグラフィック要素のコレクションクラスにあるカーソル下のフォームへのポインタを返すメソッドで、非表示のオブジェクトの選択を回避するために、オブジェクト可視性フラグのチェックを追加します。
//+------------------------------------------------------------------+ //| Return the pointer to the form located under the cursor | //+------------------------------------------------------------------+ CForm *CGraphElementsCollection::GetFormUnderCursor(const int id, const long &lparam, const double &dparam, const string &sparam, ENUM_MOUSE_FORM_STATE &mouse_state, long &obj_ext_id, int &form_index) { //--- Set the ID of the extended standard graphical object to -1 //--- and the index of the anchor point managed by the form to -1 obj_ext_id=WRONG_VALUE; form_index=WRONG_VALUE; //--- Initialize the mouse status relative to the form mouse_state=MOUSE_FORM_STATE_NONE; //--- Declare the pointers to graphical element collection class objects CGCnvElement *elm=NULL; CForm *form=NULL; //--- Get the list of objects the interaction flag is set for (there should be only one object) CArrayObj *list=CSelect::ByGraphCanvElementProperty(GetListCanvElm(),CANV_ELEMENT_PROP_INTERACTION,true,EQUAL); //--- If managed to obtain the list and it is not empty, if(list!=NULL && list.Total()>0) { //--- Get the only graphical element there elm=list.At(0); //--- If the element is a form object or its descendants if(elm.TypeGraphElement()>=GRAPH_ELEMENT_TYPE_WF_BASE && elm.IsVisible()) { //--- Assign the pointer to the element for the form object pointer form=elm; //--- Get the mouse status relative to the form mouse_state=form.MouseFormState(id,lparam,dparam,sparam); //--- If the cursor is inside the form, if(mouse_state>MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL) { //--- Find the interaction object. //--- This will be either the found object or the same form form=this.SearchInteractObj(form,id,lparam,dparam,sparam); //--- Return the form object //Comment(form.TypeElementDescription()," ",form.Name()); return form; } } } //--- If there is no a single form object with a specified interaction flag, //--- in the loop by all graphical element collection class objects int total=this.m_list_all_canv_elm_obj.Total(); for(int i=0;i<total;i++) { //--- get the next element elm=this.m_list_all_canv_elm_obj.At(i); if(elm==NULL || !elm.IsVisible() || !elm.Enabled()) continue; //--- if the obtained element is a form object or its descendants if(elm.TypeGraphElement()>=GRAPH_ELEMENT_TYPE_WF_BASE) { //--- Assign the pointer to the element for the form object pointer form=elm; //--- Get the mouse status relative to the form mouse_state=form.MouseFormState(id,lparam,dparam,sparam); //--- If the cursor is within the form, return the pointer to the form if(mouse_state>MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL) { //--- Find the interaction object. //--- This will be either the found object or the same form form=this.SearchInteractObj(form,id,lparam,dparam,sparam); //--- Return the form object //Comment(form.TypeElementDescription()," ",form.Name()); return form; } } } //--- ... //--- ... //---... //--- Nothing is found - return NULL return NULL; } //+------------------------------------------------------------------+
カーソルの下にある以前のアクティブなフォームを後処理するメソッドで、可視性フラグの確認とTabControlオブジェクトの処理を追加します。
//+------------------------------------------------------------------+ //| Post-processing of the former active form under the cursor | //+------------------------------------------------------------------+ void CGraphElementsCollection::FormPostProcessing(CForm *form,const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Get the main object the form is attached to CForm *main=form.GetMain(); if(main==NULL) main=form; //--- Get all the elements attached to the form CArrayObj *list=main.GetListElements(); if(list==NULL) return; //--- In the loop by the list of received elements int total=list.Total(); for(int i=0;i<total;i++) { //--- get the pointer to the object CForm *obj=list.At(i); //--- if failed to get the pointer, move on to the next one in the list if(obj==NULL || !obj.IsVisible() || !obj.Enabled()) continue; obj.OnMouseEventPostProcessing(); //--- Create the list of interaction objects and get their number int count=obj.CreateListInteractObj(); //--- In the loop by the obtained list for(int j=0;j<count;j++) { //--- get the next object CWinFormBase *elm=obj.GetInteractForm(j); if(elm==NULL || !elm.IsVisible() || !elm.Enabled()) continue; if(elm.TypeGraphElement()==GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL) { CTabControl *tab_ctrl=elm; CForm *selected=tab_ctrl.SelectedTabPage(); if(selected!=NULL) elm=selected; } //--- determine the location of the cursor relative to the object //--- and call the mouse event handling method for the object elm.MouseFormState(id,lparam,dparam,sparam); elm.OnMouseEventPostProcessing(); } } ::ChartRedraw(main.ChartID()); } //+------------------------------------------------------------------+
ループ内の現在のオブジェクトがTabControlの場合、処理のために選択されたタブのみを見つける必要があります。それを見つけてポインタを割り当てると、選択されたタブのみがマウスイベントハンドラによって処理されます。
現在、ライブラリクラスの改善はこれですべてです。
検証
テストを実行するには、前の記事のEAを\MQL5\Experts\TestDoEasy\Part117\でTestDoEasy117.mq5として保存します。
メインパネルに1つのTabControlを作成しましょう。最初のタブに、ここで作成した矢印ボタンオブジェクトクラスのすべてのオブジェクトを配置します。水平方向の二重の左右矢印は、サイズを変更できるかどうかを確認するために、デフォルトの幅に比べて小さくなります。TabControlの位置座標に2つの入力変数を追加しましょう。次に、作成されたオブジェクトがコンテナの外に出るように初期座標を設定して、可視範囲外に出る画像を切り取りするメソッドをテストできます。ただし、これは既にタブヘッダーから確認できます。11個あり、1行に配置するとコントロールのサイズに収まりません。
入力ブロックで2つの新しい変数を宣言します。
//--- input parameters sinput bool InpMovable = true; // Panel Movable flag sinput ENUM_INPUT_YES_NO InpAutoSize = INPUT_YES; // Panel Autosize sinput ENUM_AUTO_SIZE_MODE InpAutoSizeMode = AUTO_SIZE_MODE_GROW; // Panel Autosize mode sinput ENUM_BORDER_STYLE InpFrameStyle = BORDER_STYLE_SIMPLE; // Label border style sinput ENUM_ANCHOR_POINT InpTextAlign = ANCHOR_CENTER; // Label text align sinput ENUM_INPUT_YES_NO InpTextAutoSize = INPUT_NO; // Label autosize sinput ENUM_ANCHOR_POINT InpCheckAlign = ANCHOR_LEFT; // Check flag align sinput ENUM_ANCHOR_POINT InpCheckTextAlign = ANCHOR_LEFT; // Check label text align sinput ENUM_CHEK_STATE InpCheckState = CHEK_STATE_UNCHECKED; // Check flag state sinput ENUM_INPUT_YES_NO InpCheckAutoSize = INPUT_YES; // CheckBox autosize sinput ENUM_BORDER_STYLE InpCheckFrameStyle = BORDER_STYLE_NONE; // CheckBox border style sinput ENUM_ANCHOR_POINT InpButtonTextAlign = ANCHOR_CENTER; // Button text align sinput ENUM_INPUT_YES_NO InpButtonAutoSize = INPUT_YES; // Button autosize sinput ENUM_AUTO_SIZE_MODE InpButtonAutoSizeMode= AUTO_SIZE_MODE_GROW; // Button Autosize mode sinput ENUM_BORDER_STYLE InpButtonFrameStyle = BORDER_STYLE_NONE; // Button border style sinput bool InpButtonToggle = true ; // Button toggle flag sinput bool InpButtListMSelect = false; // ButtonListBox Button MultiSelect flag sinput bool InpListBoxMColumn = true; // ListBox MultiColumn flag sinput bool InpTabCtrlMultiline = true; // Tab Control Multiline flag sinput ENUM_ELEMENT_ALIGNMENT InpHeaderAlignment = ELEMENT_ALIGNMENT_TOP; // TabHeader Alignment sinput ENUM_ELEMENT_TAB_SIZE_MODE InpTabPageSizeMode = ELEMENT_TAB_SIZE_MODE_NORMAL; // TabHeader Size Mode sinput int InpTabControlX = 10; // TabControl X coord sinput int InpTabControlY = 20; // TabControl Y coord //--- global variables CEngine engine; color array_clr[]; //+------------------------------------------------------------------+
OnInit()EAハンドラで、パネルを作成してTabControlを接続するための次のコードを実装します。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Set EA global variables ArrayResize(array_clr,2); // Array of gradient filling colors array_clr[0]=C'26,100,128'; // Original ≈Dark-azure color array_clr[1]=C'35,133,169'; // Lightened original color //--- Create the array with the current symbol and set it to be used in the library string array[1]={Symbol()}; engine.SetUsedSymbols(array); //--- Create the timeseries object for the current symbol and period, and show its description in the journal engine.SeriesCreate(Symbol(),Period()); engine.GetTimeSeriesCollection().PrintShort(false); // Short descriptions //--- Create WinForms Panel object CPanel *pnl=NULL; pnl=engine.CreateWFPanel("WFPanel",50,50,410,200,array_clr,200,true,true,false,-1,FRAME_STYLE_BEVEL,true,false); if(pnl!=NULL) { pnl.Hide(); Print(DFUN,"Panel visibility: ",pnl.IsVisible(),": ",pnl.TypeElementDescription()," ",pnl.Name()); //--- Set Padding to 4 pnl.SetPaddingAll(3); //--- Set the flags of relocation, auto resizing and auto changing mode from the inputs pnl.SetMovable(InpMovable); pnl.SetAutoSize(InpAutoSize,false); pnl.SetAutoSizeMode((ENUM_CANV_ELEMENT_AUTO_SIZE_MODE)InpAutoSizeMode,false); pnl.CreateNewElement(GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,InpTabControlX,InpTabControlY,pnl.Width()-30,pnl.Height()-40,clrNONE,255,true,false); CTabControl *tc=pnl.GetElementByType(GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,0); if(tc!=NULL) { tc.SetTabSizeMode((ENUM_CANV_ELEMENT_TAB_SIZE_MODE)InpTabPageSizeMode); tc.SetAlignment((ENUM_CANV_ELEMENT_ALIGNMENT)InpHeaderAlignment); tc.SetMultiline(InpTabCtrlMultiline); tc.SetHeaderPadding(6,0); tc.CreateTabPages(11,0,56,16,TextByLanguage("Вкладка","TabPage")); //--- tc.CreateNewElement(0,GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,10,10,15,15,clrNONE,255,true,false); tc.CreateNewElement(0,GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,30,10,15,15,clrNONE,255,true,false); tc.CreateNewElement(0,GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,50,10,15,15,clrNONE,255,true,false); tc.CreateNewElement(0,GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,70,10,15,15,clrNONE,255,true,false); tc.CreateNewElement(0,GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX,10,30,13,13,clrNONE,255,true,false); tc.CreateNewElement(0,GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX,40,30,9,13,clrNONE,255,true,false); } //--- Redraw all objects according to their hierarchy pnl.Show(); pnl.Redraw(true); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
パネルを作成したらすぐに非表示にします。それに関する他のすべての構成は非表示モードでおこなわれます。パネル上にTabControlを作成し、11個のタブを作成し、すべての矢印ボタンオブジェクトを作成します。そのクラスはここで最初のタブに追加されています。必要な要素をすべて追加したら、パネルを表示して再描画します。
EAをコンパイルし、チャート上で起動します。
表示範囲を超える領域の切り取りは正しく機能し、コンテナを超えるヘッダーはその端に沿って切り取られます。要素が左側のコンテナを超えるようにTabControlの座標を設定すると、ここですべてが正しく切り取られます。要素自体がパネルの端に沿って切り取られ、コントロールに配置されたボタンも、コンテナではなく、パネルの可視性範囲の端によって切り取られます。ここではすべてが正しく機能します。横方向の左右ボタンの幅は、デフォルト(9ピクセル)よりも小さくなっています。それにもかかわらず、それらは正しく表示されます。
何を修正する必要があるのでしょうか。影オブジェクトは、それをキャストするパネルの前に表示されます。これについては後で扱います。
次の段階
次の記事では、TabControlに取り組みます。さらに、コントロールを超えてタブヘッダーをスクロールする機能を実装します。
連載のこれまでの記事
DoEasy.コントロール(第10部):WinFormsオブジェクト—インターフェイスのアニメーション化
DoEasy.コントロール(第11部):WinFormsオブジェクト—グループ、CheckedListBox WinFormsオブジェクト
DoEasy.コントロール(第12部):基本リストオブジェクト、ListBoxおよびButtonListBox WinFormsオブジェクト
DoEasy.コントロール(第13部):WinFormsオブジェクトとマウスの相互作用を最適化し、TabControl WinFormsオブジェクトの開発を開始
DoEasy.コントロール(第14部):グラフィック要素に名前を付けるための新しいアルゴリズム。TabControl WinFormsオブジェクトの継続作業
DoEasy.コントロール(第15部):TabControl WinFormsオブジェクト — 複数行のタブヘッダー、タブ処理メソッド
DoEasy.コントロール(第16部):TabControl WinFormsオブジェクト - 複数行のタブヘッダー、コンテナに合わせてヘッダーをストレッチ
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/11408





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