图形界面VII:表格控件(第1章)

2016年8月24日,13:22
阿纳托利·卡扎斯基(Anatoly Kazharski)
0
662

内容

 

 

介绍

第一篇 图形界面I:准备库结构(第1章) 详细描述此库的作用。在每章的结尾,您将找到与该文章相关的链接的完整列表。在这里,您还可以根据当前的开发状态下载项目。文件必须与存储在归档文件中的文件放置在相同的目录中。

本文是关于三个类的,这些类使您可以为MQL应用程序的二维数据集编程不同的表类型:

  • 文字标签表;
  • 编辑框表;
  • 渲染表。

每种类型的表都有其自身的特殊属性和优点,我们将在下面进行描述。

在下面的文章(第七部分,第2章)中,我们将讨论以下控件:

  • 标签;
  • 带有图片的标签。

 


文本标签表控件

表格是一个复杂的GUI控件,因为它还包含其他控件-水平和垂直滚动条。由于可能发生数据量超出控件内可用可见空间的情况,因此滚动条为您提供了沿水平和垂直方向来回移动数据的选项。

文本标签表由以下组件组成:

  1. 背景
  2. 文字标签。
  3. 垂直滚动条。
  4. 水平滚动条。

 图1.文本标签控件的组件

图1.文本标签表控件的组件

让我们仔细看看此控件的类。

 


标签表 类的开发

产生 标签表 归档并从库中获取(WndContainer.mqh ),其中包含:

//+------------------------------------------------------------------+
//|                                                 WndContainer.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              //www.mql5.com |
//+------------------------------------------------------------------+
#include "标签表"

在中生成它们 标签表 备课 标签表 该库中每个控件应具有的标准方法集,以及用于保存添加了控件的表单的指针的方法。使用本文中讨论的所有控件来执行此操作。

//+------------------------------------------------------------------+
//| Class for creating a text label table                            |
//+------------------------------------------------------------------+
class  标签表  :  上市  CElement
  {
 私人的 :
   //--- Ein Pointer zu  的  Form zu welchem das Element hinzugefügt worden ist
   CWindow          *m_wnd;
   //---
 上市 :
                      标签表 (void);
                    ~CLabelsTable(void);
   //--- (1) Speichert den Pointer das Formulars, (2) Gibt den Pointer zu den Scrollbars zurück
   void              WindowPointer(CWindow &object)               { m_wnd=::GetPointer(object);      }
   //---
 上市 :
   //--- Chart Eventhandler
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Timer
   virtual void      OnEventTimer(void);
   //--- Bewegen des Elementes
   virtual void      Moving(const int x,const int y);
   //--- (1) Anzeigen, (2) verstecken, (3) zurücksetzen, (4) löschen
   virtual void      Show(void);
   virtual void      Hide(void);
   virtual void      Reset(void);
   virtual void      Delete(void);
   //--- (1) Setzen, (2) Zurücksetzen  的  Prioritäten  的  linken Maustaste
   virtual void      SetZorders(void);
   virtual void      ResetZorders(void);
   //--- Zurücksetzen  的  Farbe
   virtual void      ResetColors(void) {}
  };
//+------------------------------------------------------------------+
//| Konstruktor                                                      |
//+------------------------------------------------------------------+
CLabelsTable::CLabelsTable(void)
  {
  }
//+------------------------------------------------------------------+
//| Destruktor                                                       |
//+------------------------------------------------------------------+
CLabelsTable::~CLabelsTable(void)
  {
  }

在创建表之前,让我们指定其某些属性。我们命名这些

  • 线的高度
  • 从控件的左边缘开始的第一列缩进
  • 列之间的距离
  • 背景色
  • 文字颜色
  • 第一行锁定模式
  • 第一栏的锁定方式
  • 总列数
  • 总行数
  • 可见列数
  • 可见线数

对于这种类型的表格,文本标签的坐标是根据中心锚点(ANCHOR_CENTER)。因此,从控件的左上角开始计算文本标签第一列的缩进,并从每列的中心计算每列文本标签之间的距离。

在锁定模式下,即使用户移动了垂直和水平滚动条的滑块,第一行和/或每一行(用户在其中指定每个列和行的名称)也必须保持可见。锁定模式可以一起使用,也可以单独使用。 

class  标签表  :  上市  CElement
  {
 私人的 :
   //--- 线的高度
   int               m_row_y_size;
   //--- 背景色  的  Tabelle
   color             m_area_color;
   //---  的  Standardfarbe des Textes  的  Tabelle
   color             m_text_color;
   //--- Der Abstand zwischen dem Ankerpunkt  的  ersten Spalte  和   的  linken Ecke des Controls
   int               m_x_offset;
   //--- Der Abstand zwischen den Ankerpunkten  的  Spalten
   int               m_column_x_offset;
   //--- Sperrmodus  的  ersten Zeile
   bool              m_fix_first_row;
   //--- Sperrmodus  的  ersten Spalte
   bool              m_fix_first_column; 
   //--- Priorität für die linke Maustaste
   int               m_zorder;
   int               m_area_zorder;
   //---
 上市 :
   //--- (1)  背景 farbe, (2) Textfarbe
   void              AreaColor(const color clr)                   { m_area_color=clr;                }
   void              TextColor(const color clr)                   { m_text_color=clr;                }
   //--- (1) Höhe  的  Zeile, (2) Festlegen des Abstandes zwischen dem Ankerpunkt  的  ersten Spalte  和   的  linken Ecke  的  Tabelle,
   //    (3) festlegen  的  Abstände zwischen den Ankerpunkten  的  Spalten
   void              RowYSize(const int y_size)                   { m_row_y_size=y_size;             }
   void              XOffset(const int x_offset)                  { m_x_offset=x_offset;             }
   void              ColumnXOffset(const int x_offset)            { m_column_x_offset=x_offset;      }
   //--- (1) Abfrage  和  (2) des Sperrmodus für die erste Zeile
   bool              FixFirstRow(void)                      const { return(m_fix_first_row);         }
   void              FixFirstRow(const bool flag)                 { m_fix_first_row=flag;            }
   //--- (1) Abfrage  和  (2) des Sperrmodus für die erste Spalte
   bool              FixFirstColumn(void)                   const { return(m_fix_first_column);      }
   void              FixFirstColumn(const bool flag)              { m_fix_first_column=flag;         }
  };

来做吧 标签表 :: TableSize () 标签表 :: VisibleTableSize () 获得方法 才能定义可见的列数和行数。我们还需要结构形式的二维动态数组。这些结构之一( LT标签 )为表格的可见区域创建带有文本标签的数组,而另一个( LT选项 )保存表中每个单元格的所有值和属性。在我们的实现中,这将保存显示的值(线条)和文本颜色

标签表 :: TableSize () 标签表 :: VisibleTableSize () 方法传递两个参数(列数和行数)。在方法开始时,将检查值以查看列数是否小于一以及行数是否小于两。然后定义所有arrayd的大小,并初始化数组的属性。

除了用于表大小的方法外,我们还需要用于查询具有列和行的总可见大小的方法。 

class  标签表  :  上市  CElement
  {
 私人的 :
   //--- Array mit Objekten für den sichtbaren Bereich  的  Tabelle
   struct  LT标签 
     {
      CLabel            m_rows[];
     };
    LT标签           m_columns[];
   //--- Array mit den Werten  和  Eigenschaften  的  Tabelle
   struct  LT选项 
     {
      string            m_vrows[];
      color             m_colors[];
     };
    LT选项          m_vcolumns[];
   //---
 上市 :
   //--- Gib die gesamte Anzahl von (1) Zeilen  和  (2) Spalten zurück
   int               RowsTotal(void)                        const { return(m_rows_total);            }
   int               ColumnsTotal(void)                     const { return(m_columns_total);         }
   //--- Gibt die Anzahl von (1) Zeilen  和  (2) Spalten des sichtbaren Bereichs  的  Tabelle zurück
   int               VisibleRowsTotal(void)                 const { return(m_visible_rows_total);    }
   int               VisibleColumnsTotal(void)              const { return(m_visible_columns_total); }

   //--- Setzen  的  (1) Größe  的  Tabelle  和  (2) Der Größe des sichtbaren Bereiches
   void              TableSize(const int columns_total,const int rows_total);
   void              VisibleTableSize(const int visible_columns_total,const int visible_rows_total);
  };
//+------------------------------------------------------------------+
//| Legt die Größe  的  Tabelle fest                                  |
//+------------------------------------------------------------------+
void  标签表  :: TableSize(const int columns_total,const int rows_total)
  {
//--- Es muss mindestens eine Spalte geben
   m_columns_total=(columns_total<1) ? 1 : columns_total;
//--- Es muss mindestens zwei Zeilen geben
   m_rows_total=(rows_total<2) ? 2 : rows_total;
//--- Festlegen  的  Größe  的  Spalten-Arrays
   ::ArrayResize(m_vcolumns,m_columns_total);
//--- Festlegen  的  Größe  的  Zeilen-Arrays
   for(int i=0; i<m_columns_total; i++)
     {
      ::ArrayResize(m_vcolumns[i].m_vrows,m_rows_total);
      ::ArrayResize(m_vcolumns[i].m_colors,m_rows_total);
      //--- Initialisieren des Arrays  的  Textfarben mit den Standardwerten
      ::ArrayInitialize(m_vcolumns[i].m_colors,m_text_color);
     }
  }
//+-----------------------------------------------------------------+
//| Festlegen  的  Größe des sichtbaren Teils  的  Tabelle            |
//+-----------------------------------------------------------------+
void  标签表  :: VisibleTableSize(const int visible_columns_total,const int visible_rows_total)
  {
//--- Es muss mindestens eine Spalte geben
   m_visible_columns_total=(visible_columns_total<1) ? 1 : visible_columns_total;
//--- Es muss mindestens zwei Zeilen geben
   m_visible_rows_total=(visible_rows_total<2) ? 2 : visible_rows_total;
//--- Festlegen  的  Größe  的  Spalten-Arrays
   ::ArrayResize(m_columns,m_visible_columns_total);
//--- Festlegen  的  Größe  的  Zeilen-Arrays
   for(int i=0; i<m_visible_columns_total; i++)
      ::ArrayResize(m_columns[i].m_rows,m_visible_rows_total);
  }

在创建控件之前,应使用标准值初始化所有属性。我建议直接在类构造函数中执行此操作:

//+----------------------------------------------------------------+
//| Konstruktor                                                    |
//+----------------------------------------------------------------+
CLabelsTable::CLabelsTable(void) : m_fix_first_row(false),
                                   m_fix_first_column(false),
                                   m_row_y_size(18),
                                   m_x_offset(30),
                                   m_column_x_offset(60),
                                   m_area_color(clrWhiteSmoke),
                                   m_text_color(clrBlack),
                                   m_rows_total(2),
                                   m_columns_total(1),
                                   m_visible_rows_total(2),
                                   m_visible_columns_total(1)
  {
//--- Abspeichern des namens  的  Elementklasse in  的  Basisklasse
   CElement::ClassName(CLASS_NAME);
//--- Setzen  的  Priorität eines Klicks mit  的  linken Maustaste
   m_zorder      =0;
   m_area_zorder =1;
//--- Festlegen  的  Größe  的  Tabelle  和  seines sichtbaren Bereiches
   TableSize(m_columns_total,m_rows_total);
   VisibleTableSize(m_visible_columns_total,m_visible_rows_total);
  }

我们四个 私人的 和一个 上市 生成用于外部调用的控件的开发方法。为了使用户能够配置表的滚动条,我们必须添加一个返回其指针的方法。 

class  标签表  :  上市  CElement
  {
 私人的 :
   //--- Objekte für die Erzeugung einer Tabelle
   CRectLabel        m_area;
   CScrollV          m_scrollv;
   CScrollH          m_scrollh;
   //--- Array mit Objekten für den sichtbaren Bereich  的  Tabelle
   struct  LT标签 
     {
      CLabel            m_rows[];
     };
    LT标签           m_columns[];
   //---
 上市 :
   //--- Gibt die Pointer  的  Scrollbars zurück
   CScrollV         *GetScrollVPointer(void)                const { return(::GetPointer(m_scrollv)); }
   CScrollH         *GetScrollHPointer(void)                const { return(::GetPointer(m_scrollh)); }
   //--- Methoden für die Erzeugung  的  Tabelle
   bool              CreateLabelsTable(const long chart_id,const int subwin,const int x,const int y);
   //---
 私人的 :
   bool              CreateArea(void);
   bool              CreateLabels(void);
   bool              CreateScrollV(void);
   bool              CreateScrollH(void);
  };

在所有生成方法中,这里仅讨论那些方法 标签表 :: CreateLabels()显示为文本标签数组的开发。确保你有 向列和行添加索引 建立对象名称时。其他所有方法都可以在附件中找到。 

//+-----------------------------------------------------------------+
//| Erzeugung eines Arrays mit Text-Labeln                          |
//+-----------------------------------------------------------------+
bool  标签表  :: CreateLabels(void)
  {
//--- Koordinaten  和  Offset
   int x      =CElement::X();
   int y      =0;
   int offset =0;
//--- Spalten
   for(int c=0; c<m_visible_columns_total; c++)
     {
      //--- Berechnung des Tabellen-Offsets
      offset=(c>0) ? m_column_x_offset : m_x_offset;
      //--- Berechnung  的  x-Koordinate
      x=x+offset;
      //--- Zeilen
      for(int r=0; r<m_visible_rows_total; r++)
        {
         //--- Bilden des Objektnamens
         string name=CElement::ProgramName()+"_labelstable_label_"+(string)c+"_"+(string)r+"__"+(string)CElement::Id();
         //--- Berechne die Y Koordinate
         y=(r>0) ? y+m_row_y_size-1 : CElement::Y()+10;
         //--- Erzeugen des Objektes
         if(!m_columns[c].m_rows[r].Create(m_chart_id,name,m_subwin,x,y))
            return(false);
         //--- Festlegen  的  Eigenschaften
         m_columns[c].m_rows[r].Description(m_vcolumns[c].m_vrows[r]);
         m_columns[c].m_rows[r].Font(FONT);
         m_columns[c].m_rows[r].FontSize(FONT_SIZE);
         m_columns[c].m_rows[r].Color(m_text_color);
         m_columns[c].m_rows[r].Corner(m_corner);
         m_columns[c].m_rows[r].Anchor(ANCHOR_CENTER);
         m_columns[c].m_rows[r].Selectable(false);
         m_columns[c].m_rows[r].Z_Order(m_zorder);
         m_columns[c].m_rows[r].Tooltip("\n");
         //--- Abstände von  的  Ecke des Formulars
         m_columns[c].m_rows[r].XGap(x-m_wnd.X());
         m_columns[c].m_rows[r].YGap(y-m_wnd.Y());
         //--- Koordinaten
         m_columns[c].m_rows[r].X(x);
         m_columns[c].m_rows[r].Y(y);
         //--- Abspeichern des Objekt-Pointers
         CElement::AddToArray(m_columns[c].m_rows[r]);
        }
     }
//---
   return(true);
  }

我们仍然需要能够随时更改表中每个单元格的值和属性的方法。来做吧 标签表 :: SetValue () 标签表 :: GetValue () 创建用于设置和查询单元格值的方法。使用这两种方法时,必须将列和行的索引作为第一个参数传递。然后将要保存在数组中的值用作以下项的第三个参数: 标签表 :: SetValue () 通过方法。首先当然要强制检查索引值是否超过数组的限制。 

class  标签表  :  上市  CElement
  {
 上市 :
   //--- Festlegen eines Wertes in  的  spezifizierten Zelle einer Tabelle
   void              SetValue(const int column_index,const int row_index,const string value);
   //--- 查询值 einer bestimmten Zelle einer Tabelle
   string            GetValue(const int column_index,const int row_index);
  };
//+-----------------------------------------------------------------+
//| Setzen des Wertes bei den angegebenen Indizes                   |
//+-----------------------------------------------------------------+
void  标签表  :: SetValue(const int column_index,const int row_index,const string value)
  {
//--- Überprüfung auf Überschreitung des Indexbereiches  的  Spalten
   int csize=::ArraySize(m_vcolumns);
   if(csize<1 || column_index<0 || column_index>=csize)
      return;
//--- Überprüfung  的  Überschreitung des Indexbereiches  的  Zeilen
   int rsize=::ArraySize(m_vcolumns[column_index].m_vrows);
   if(rsize<1 || row_index<0 || row_index>=rsize)
      return;
//--- Setzen des Wertes
   m_vcolumns[column_index].m_vrows[row_index]=value;
  }
//+-----------------------------------------------------------------+
//| Rückgabe des Wertes an den angegebenen Indizes                  |
//+-----------------------------------------------------------------+
string  标签表  :: GetValue(const int column_index,const int row_index)
  {
//--- Überprüfung auf Überschreitung des Indexbereiches  的  Spalten
   int csize=::ArraySize(m_vcolumns);
   if(csize<1 || column_index<0 || column_index>=csize)
      return("");
//--- Überprüfung  的  Überschreitung des Indexbereiches  的  Zeilen
   int rsize=::ArraySize(m_vcolumns[column_index].m_vrows);
   if(rsize<1 || row_index<0 || row_index>=rsize)
      return("");
//--- Rückgabe des Wertes
   return(m_vcolumns[column_index].m_vrows[row_index]);
  }

除了更改表中的值之外,库用户还可能希望更改文本的颜色。例如,正值可以用绿色显示,负值可以用红色显示。为此, 标签表 :: TextColor()创建方法。她就是那个 标签表 :: SetValue()方法非常相似,唯一的区别在于颜色是第三个参数。 

class  标签表  :  上市  CElement
  {
 上市 :
   //--- 文字颜色 einer bestimmten Zelle ändern
   void              TextColor(const int column_index,const int row_index,const color clr);
  };
//+-----------------------------------------------------------------+
//| Ändert die Farbe einer bestimmten Zelle                         |
//+-----------------------------------------------------------------+
void  标签表  :: TextColor(const int column_index,const int row_index,const color clr)
  {
//--- Überprüfung auf Überschreitung des Indexbereiches  的  Spalten
   int csize=::ArraySize(m_vcolumns);
   if(csize<1 || column_index<0 || column_index>=csize)
      return;
//--- Überprüfung  的  Überschreitung des Indexbereiches  的  Zeilen
   int rsize=::ArraySize(m_vcolumns[column_index].m_vrows);
   if(rsize<1 || row_index<0 || row_index>=rsize)
      return;
//--- Festlegen  的  Farbe
   m_vcolumns[column_index].m_colors[row_index]=clr;
  }

仅在更新表后才接受/显示更改。为此,我们创建了一种通用方法,该方法在必须根据滑块在滚动条上的位置移动数据时也可以使用。 

让我们做这个方法 标签表 :: UpdateTable()致电。如果标题已锁定,则移位将从第二个(1)数组索引开始,以确保第一行或第一列始终保持可见。的 tl 变量在方法开始时声明,其值0或1根据当前使用的模式设置。

为了能够定义必须从中开始换档或更新的索引, 必须查询滚动条滑块的当前位置。左列和顶行的标题在单独的循环中移动(如果激活了此模式)。

在方法结束时,表格的主要数据和单元格的颜色以双循环方式移动。 

class  标签表  :  上市  CElement
  {
 上市 :
   //--- Aktualisierung  的   那里 ten  的  Tabelle unter Berücksichtigung  的  letzten Veränderungen
   void              UpdateTable(void);
  };
//+-----------------------------------------------------------------------------------------+
//| Aktualisierung  的   那里 ten  的  Tabelle unter Berücksichtigung  的  letzten Veränderungen   |
//+-----------------------------------------------------------------------------------------+
void  标签表  :: UpdateTable(void)
  {
//--- Verschieben um einen Index, falls  的  fixierte Kopfzeilen-Modus aktiviert ist
   int t=(m_fix_first_row) ? 1 : 0;
   int l=(m_fix_first_column) ? 1 : 0;
//--- Abfrage  的  aktuellen Positionen  的  Schieberegler  的  vertikalen  和  horizontalen Scrollbars
   int h=m_scrollh.CurrentPos()+l;
   int v=m_scrollv.CurrentPos()+t;
//--- Verschieben  的  Kopfzeile in  的  linken Spalte
   if(m_fix_first_column)
     {
      m_columns[0].m_rows[0].Description(m_vcolumns[0].m_vrows[0]);
      //--- Zeilen
      for(int r=t; r<m_visible_rows_total; r++)
        {
         if(r>=t && r<m_rows_total)
            m_columns[0].m_rows[r].Description(m_vcolumns[0].m_vrows[v]);
         //---
         v++;
        }
     }
//--- Verschieben  的  Kopfzeile in  的  obersten Zeile
   if(m_fix_first_row)
     {
      m_columns[0].m_rows[0].Description(m_vcolumns[0].m_vrows[0]);
      //--- Spalten
      for(int c=l; c<m_visible_columns_total; c++)
        {
         if(h>=l && h<m_columns_total)
            m_columns[c].m_rows[0].Description(m_vcolumns[h].m_vrows[0]);
         //---
         h++;
        }
     }
//--- Abfrage  的  aktuellen Position des Schiebereglers  的  Horizontalen Scrollbar
   h=m_scrollh.CurrentPos()+l;
//--- Spalten
   for(int c=l; c<m_visible_columns_total; c++)
     {
      //--- Abfrage  的  aktuellen Position des Schiebereglers  的  vertikalen Scrollbar
      v=m_scrollv.CurrentPos()+t;
      //--- Zeilen
      for(int r=t; r<m_visible_rows_total; r++)
        {
         //--- Verschiebung  的  Tabellendaten
         if(v>=t && v<m_rows_total && h>=l && h<m_columns_total)
           {
            //--- Einstellung  的  Farbe
            m_columns[c].m_rows[r].Color(m_vcolumns[h].m_colors[v]);
            //--- Einstellen  的  Werte
            m_columns[c].m_rows[r].Description(m_vcolumns[h].m_vrows[v]);
            v++;
           }
        }
      //---
      h++;
     }
  }

正如我们对输入框和列表控件所做的那样,让我们​​实现快速滚动,只要在滚动条按钮上方按下鼠标左键即可。无需阅读 标签表 ::快速切换()这里的方法,因为它对应于以前文章中方法的程序代码( CListView , CSpin编辑 其他 CCheckBox编辑 类)。 

下面的列表中显示了用于处理控制事件的方法的程序代码: 

//+-----------------------------------------------------------------+
//| Even handler                                                    |
//+-----------------------------------------------------------------+
void  标签表 ::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeiten  的  Events über die Bewegung des Mauszeigers
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Abbrechen, falls das Element versteckt ist
      if(!CElement::IsVisible())
         return;
      //---Koordinaten  和   的  Status  的  linken Maustaste
      int x=(int)lparam;
      int y=(int)dparam;
      m_mouse_state=(bool)int(sparam);
      //--- Überprüfen des Fokus über  的  Tabelle
      CElement::MouseFocus(x>X() && x<X2() && y>Y() && y<Y2());
      //--- Bewege die Liste, falls die Verwaltung des Schiebereglers aktiviert ist
      if(m_scrollv.ScrollBarControl(x,y,m_mouse_state) || m_scrollh.ScrollBarControl(x,y,m_mouse_state))
         UpdateTable();
      //---
      return;
     }
//--- Verarbeitung von Klicks auf Objekte
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Falls auf einen Button  的  Tabellen-Scrollbars gedrückt wurde
      if(m_scrollv.OnClickScrollInc(sparam) || m_scrollv.OnClickScrollDec(sparam) ||
         m_scrollh.OnClickScrollInc(sparam) || m_scrollh.OnClickScrollDec(sparam))
         //--- Verschiebe die Tabelle relativ zu  的  Scrollbar
         UpdateTable();
      //---
      return;
     }
  }
//+-----------------------------------------------------------------+
//| Timer                                                           |
//+-----------------------------------------------------------------+
void  标签表 ::OnEventTimer(void)
  {
//--- Falls es sich um einen DropDown-Element handelt
   if(CElement::IsDropdown())
      FastSwitching();
//--- Falls es sich nicht um ein Dropdown-Element handelt, berücksichtige die aktuelle Verfügbarkeit des Formulars
   else
     {
      //--- Verfolge den schnellen Vorlauf  的  Tabelle nur, falls das Formular nicht gesperrt ist
      if(!m_wnd.IsLocked())
         FastSwitching();
     }
  }

表是一个复杂的GUI控件。因此,其他控件(水平和垂直滚动条)的指针应包含在指针数据库中。我们应该为表指针创建一个独立的数组。您可以在 WndContainer.mqh 的档案 CWnd容器 大。本系列的其他文章中已经讨论了该主题。因此,我将跳过这一步并继续测试文本标签表。 

 


测试文字标签表

为了进行测试,我们将使用上一篇文章中的EA交易,并仅保留主菜单和状态栏。为了能够将文本标签表添加到MQL应用程序, 标签表 声明了类型类实例,以及到表单最顶端的方法和距离(您可以在下面的程序代码中看到它们)。

class  C程序  :  上市  CWndEvents
  {
 私人的 :
   //--- Text-Label-Tabelle
    标签表       m_labels_table;
   //---
 私人的 :
   //--- Text-Label-Tabelle
#define LABELS_TABLE1_GAP_X   (1)
#define LABELS_TABLE1_GAP_Y   (42)
   bool              CreateLabelsTable(void);
  };

现在,让我们运行 C程序 :: CreateLabelsTable()仔细研究该方法。我们想要一个组成的桌子 21 列和 100 线条由设计组成。可见列数为 5,可见线数为 10. 我们修复了顶行和左列,以免它们移动。创建表后,它会填充随机值(来自-10001000),并且颜色仍然定义。正值显示为绿色,负值显示为红色。 您更新表格,以便可以看到最新的更改

//+-----------------------------------------------------------------+
//| Erzeugung  的  Text Label Tabelle                                |
//+-----------------------------------------------------------------+
bool  C程序  :: CreateLabelsTable(void)
  {
#define COLUMNS1_TOTAL (21)
#define ROWS1_TOTAL    (100)
//--- Abspeichern des pointers zu dem Formular
   m_labels_table.WindowPointer(m_window1);
//--- Koordinaten
   int x=m_window1.X()+LABELS_TABLE1_GAP_X;
   int y=m_window1.Y()+LABELS_TABLE1_GAP_Y;
//--- 可见列数  和  Zeilen
   int visible_columns_total =5;
   int visible_rows_total    =10;
//--- Setzen  的  Eigenschaften
   m_labels_table.XSize(400);
   m_labels_table.XOffset(40);
   m_labels_table.ColumnXOffset(75);
   m_labels_table.FixFirstRow(true);
   m_labels_table.FixFirstColumn(true);
   m_labels_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
   m_labels_table.VisibleTableSize(visible_columns_total,visible_rows_total);
//--- Erzeugen  的  Tabelle
   if(!m_labels_table.CreateLabelsTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- Einfügen in die Tabelle:
//    Die erste Zelle ist leer
   m_labels_table.SetValue(0,0,"-");
//---  的  Überschriften  的  Spalten
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=0; r<1; r++)
         m_labels_table.SetValue(c,r,"SYMBOL "+string(c));
     }
//---  的  Überschriften  的  Zeilen, die Ausrichtung ist Rechts
   for(int c=0; c<1; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        m_labels_table.SetValue(c,r,"PARAMETER "+string(r));
     }
//---  那里 ten  和  Tabellen-Formatierung (Hintergrund  和  Farben  的  Zellen)
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
         m_labels_table.SetValue(c,r,string(::rand () %1000-::rand () %1000));
     }
//--- 文字颜色 in den Zellen setzen
   for(int c=1; c<m_labels_table.ColumnsTotal(); c++)
      for(int r=1; r<m_labels_table.RowsTotal(); r++)
         m_labels_table.TextColor(c,r,((double)m_labels_table.GetValue(c,r)>=0) ? clrGreen : clrRed);
//--- Aktualisieren  的  Tabelle
   m_labels_table.UpdateTable();
//--- Hinzufügen des Pointers des Elementes zu  的  Basis
   CWnd容器::AddToElementsArray(0,m_labels_table);
   return(true);
  }

当程序在终端图表上运行时,我们还应该测试表值如何更改。去做这个 成为以下程序代码 C程序 :: OnTimerEvent()将Timer方法添加到应用程序中。看一下下面的清单:  

//+----------------------------------------------------------------+
//| Timer                                                          |
//+----------------------------------------------------------------+
void  C程序  :: OnTimerEvent(void)
  {
   CWndEvents::OnTimerEvent();
//--- Aktualisierung des zweiten Punktes  的  Statuszeile alle 500 Millisekunden
   static int count=0;
   if(count<500)
     {
      count+=TIMER_STEP_MSC;
      return;
     }
//--- Zurücksetzen des Timers
   count=0;
//--- Veränderung des Wertes in dem zweiten Punkt  的  Statuszeile.
   m_status_bar.ValueToItem(1,::TimeToString(::TimeLocal () ,TIME_DATE|TIME_SECONDS));
//--- Tabelle mit  那里 ten auffüllen
   for(int c=1; c<m_labels_table.ColumnsTotal(); c++)
      for(int r=1; r<m_labels_table.RowsTotal(); r++)
         m_labels_table.SetValue(c,r,string(::rand () %1000-::rand () %1000));
//--- 文字颜色 in den Zellen setzen
   for(int c=1; c<m_labels_table.ColumnsTotal(); c++)
      for(int r=1; r<m_labels_table.RowsTotal(); r++)
         m_labels_table.TextColor(c,r,((double)m_labels_table.GetValue(c,r)>=0) ? clrGreen : clrRed);
//--- Aktualisieren  的  Tabelle
   m_labels_table.UpdateTable();
  }

创建文本标签表的方法应该在main方法中 C程序 :: CreateExpertPanel()的应用。该过程的简短版本如下所示: 

//+----------------------------------------------------------------+
//| Erzeugung des Expert-Bedienfeldes                              |
//+----------------------------------------------------------------+
bool  C程序  :: CreateExpertPanel(void)
  {
//--- Erzeugen des Formulars 1 für die Controls
//--- Erzeugen  的  Controls:
//    Hauptmenü
//--- Kontextmenüs
//--- Erzeugen  的  Statuszeile
//--- Text-Label-Tabelle
   if(!CreateLabelsTable())
      return(false);
//--- Neuzeichnen des  图表 
   m_chart.Redraw();
   return(true);
  }

编译程序代码并将程序加载到图表上。以下屏幕截图显示了结果:

 图2.文本标签表的测试

图2.文本标签表的测试

一切正常。现在,让我们继续创建第二种类型的表的类。 

 


编辑框表控件

与文本标签表不同,editbox表具有更大的灵活性和更多的属性。除了可以更改文本颜色外,它还提供: 

  • 单元格内文本的对齐方式(左/中/右)
  • 更改背景颜色和编辑框的框架;
  •  如果激活了相应的模式,则可以在编辑框中手动更改值。

所有这些要点使此表更加用户友好,并且易于执行大量任务。文本标签表由以下组件组成:

  1. 背景
  2. 编辑框
  3. 垂直滚动条。
  4. 水平滚动条。

 图3.表格控件编辑框的组件

图3.表格控件编辑框的组件

让我们看看程序代码与上表有何不同。

 


表格 类的开发

让我们描述表的特征,突出显示与上一张表的区别。该表中可见图形对象的数组来自另一种类型-( 编辑 )。换句话说,它由编辑框而不是文本标签组成(请参见下面的代码)。

class  表格  :  上市  CElement
  {
 私人的 :
   //--- Array mit Objekten für den sichtbaren Bereich  的  Tabelle
   struct TEdits
     {
       编辑              m_rows[];
     };
   TEdits            m_columns[];
  };

由于表格允许您执行此操作,因此每个单元格都有更多独特的属性 文字对齐编辑框的背景色 改变。

class  表格  :  上市  CElement
  {
 私人的 :
   //--- Arrays mit den Tabellenwerten  和  Eigenschaften
   struct TOptions
     {
      string            m_vrows[];
      ENUM_ALIGN_MODE   m_text_align[];
      color             m_text_color[];
      color             m_cell_color[];
     };
   TOptions          m_vcolumns[];
  };

下面是文本标签表中不可用的模式和属性的列表。

  • “可编辑”表模式
  • 当鼠标指针悬停在一行上时突出显示该行的模式。
  • 所选行的模式
  • 线的高度
  • 表格网格颜色
  • 标题的背景色
  • 标题文字颜色
  • 鼠标指针悬停在单元格上方时的颜色。
  • 单元格的默认颜色
  • 单元格的默认对齐方式
  • 行的突出显示的背景色
  • 突出显示时文本的颜色

这种类型的表还允许您固定第一行和第一列的标题。选择此模式后,当移动滑块时它们将保留在原位。以下程序代码显示了完整的编辑框和用于设置表属性的方法: 

class  表格  :  上市  CElement
  {
 私人的 :
   //--- Höhe  的  Zeilen  的  Tabelle
   int               m_row_y_size;
   //--- (1)  的  Farbe des  背景 es  和  (2) Des Rahmens des  背景 es  的  Tabelle
   color             m_area_color;
   color             m_area_border_color;
   //--- Farbe des Gitters
   color             m_grid_color;
   //---  背景 farbe  的  Überschrift
   color             m_headers_color;
   //--- Textfarbe  的  Überschrift
   color             m_headers_text_color;
   //---  的  Farben  的  Zellen in den unterschiedlichen Zuständen
   color             m_cell_color;
   color             m_cell_color_hover;
   //---  的  Standardfarbe für den Text einer Zelle
   color             m_cell_text_color;
   //--- Farbe des (1)  背景 es  和  (2) des Textes  的  selektierten Zeile
   color             m_selected_row_color;
   color             m_selected_row_text_color;
   //--- Modus für die Editierbarkeit  的  Tabelle
   bool              m_read_only;
   //--- Modus für das Hervorheben von Zeilen, wenn sich  的  Mauszeiger darüber befindet
   bool              m_lights_hover;
   //--- Modus für die Auswählbarkeit einer Zeile
   bool              m_selectable_row;
   //--- Sperrmodus  的  ersten Zeile
   bool              m_fix_first_row;
   //--- Sperrmodus  的  ersten Spalte
   bool              m_fix_first_column;
   //---  的  Standard-Textausrichtung in den Edit-Boxen
   ENUM_ALIGN_MODE   m_align_mode;
   //---
 上市 :
   //--- Farbe des (1)  背景 es  和  (2) des Rahmens  的  Tabelle
   void              AreaColor(const color clr)                        { m_area_color=clr;                }
   void              BorderColor(const color clr)                      { m_area_border_color=clr;         }
   //--- (1) Abfrage  和  (2) des Sperrmodus für die erste Zeile
   bool              FixFirstRow(void)                           const { return(m_fix_first_row);         }
   void              FixFirstRow(const bool flag)                      { m_fix_first_row=flag;            }
   //--- (1) Abfrage  和  (2) des Sperrmodus für die erste Spalte
   bool              FixFirstColumn(void)                        const { return(m_fix_first_column);      }
   void              FixFirstColumn(const bool flag)                   { m_fix_first_column=flag;         }
   //--- Farbe des (1)  背景 es  的  Überschriften, (2) Text  的  Überschriften  和  (3) Dis Tabellengitters
   void              HeadersColor(const color clr)                     { m_headers_color=clr;             }
   void              HeadersTextColor(const color clr)                 { m_headers_text_color=clr;        }
   void              GridColor(const color clr)                        { m_grid_color=clr;                }
   //---  的  Größe  的  Zeilen entlang  的  y-Achse
   void              RowYSize(const int y_size)                        { m_row_y_size=y_size;             }
   void              CellColor(const color clr)                        { m_cell_color=clr;                }
   void              CellColorHover(const color clr)                   { m_cell_color_hover=clr;          }
   //--- (1) "Nur lesen", (2) Hervorheben  的  Zeilen, wenn sich die Maus darüber befindet, (3) Modus für die Auswertbarkeit  的  Zeile
   void              ReadOnly(const bool flag)                         { m_read_only=flag;                }
   void              LightsHover(const bool flag)                      { m_lights_hover=flag;             }
   void              SelectableRow(const bool flag)                    { m_selectable_row=flag;           }
   //--- 文字对齐 in  的  Zelle
   void              TextAlign(const ENUM_ALIGN_MODE align_mode)       { m_align_mode=align_mode;         }
  };

下面列出了用于设置或查询表值的方法的属性,具体取决于列索引和行索引。

  • 表的总大小(列和行的总数)
  • 表格可见区域的大小(可见列和行的数量)
  • 单元格的文本对齐方式(左/右/中心)
  • 文字颜色
  • 背景色
  • 定义/更改值
  • 查询值

这里没有理由重复此方法的代码,因为我们已经在文本标签表的部分中进行了讨论。设置所有值后,必须通过调用来确保拥有该表 表格 :: UpdateTable () 更新方法,以便所有更改都可见。 

class  表格  :  上市  CElement
  {
 上市 :
   //--- Setzen  的  (1) Größe  的  Tabelle  和  (2) Der Größe des sichtbaren Bereiches
   void              TableSize(const int columns_total,const int rows_total);
   void              VisibleTableSize(const int visible_columns_total,const int visible_rows_total);
   //--- Setzen (1) des Ausrichtungs-Modus, (2) Textfarbe, (3)  背景 farbe  的  Zelle
   void              TextAlign(const int column_index,const int row_index,const ENUM_ALIGN_MODE mode);
   void              TextColor(const int column_index,const int row_index,const color clr);
   void              CellColor(const int column_index,const int row_index,const color clr);
   //--- Festlegen eines Wertes in  的  spezifizierten Zelle einer Tabelle
   void              SetValue(const int column_index,const int row_index,const string value);
   //--- 查询值 einer bestimmten Zelle einer Tabelle
   string            GetValue(const int column_index,const int row_index);
   //--- Aktualisierung  的   那里 ten  的  Tabelle unter Berücksichtigung  的  letzten Veränderungen
   void              UpdateTable(void);
  };

现在让我们讨论管理表的方法。这些是排他性的 私人的 内部使用的类方法。它们的功能范围包括:

  • 单击表中一行的处理。
  • 将值输入到表的单元格中。
  • 从对象名称查询ID
  • 从对象名称查询列的索引
  • 从对象名称查询行的索引
  • 突出显示所选行
  • 当鼠标指针悬停在按钮上时更改线条颜色。
  • 快速向后滚动表格。

让我们处理一下 表格 :: OnClickTableRow()单击表中一行的启动方法。在方法开始时,需要进行一些检查。在以下情况下,程序将退出该方法:

  • 选择用于编辑表格的模式;
  • 滚动条之一处于活动状态时;
  • 单击事件不属于此表的单元格。这可以根据对象名称,程序名称以及单元格与表的关联来确定;
  • 控件ID不适用。要从对象名称获取ID, 表格 :: IdFromObjectName () 使用的方法。我们在检查其他控件时已经描述了此过程。

现在是时候在所有单元格中搜索并查找单击的单元格,同时考虑到标题的锁定线和垂直滚动条的滑块的当前位置。如果找到了按下的单元格,则行索引和该单元格的值将保存在该类的变量中。

如果单击标题(第一行),程序将退出该方法。除此以外 生成自定义消息。它包含(1)图表ID,(2)事件ID(ON_CLICK_LIST_ITEM),(3)控件ID和(4)单击的行的索引。 

class  表格  :  上市  CElement
  {
 私人的 :
   //--- Verarbeiten eines Klicks auf eine Tabellenzeile
   bool              OnClickTableRow(const string clicked_object);
   //---  的  Bezeichner aus dem Objektnamen entnehmen
   int               IdFromObjectName(const string object_name);
  };
//+-----------------------------------------------------------------+
//| Verarbeiten eines Klicks auf eine Tabellenzeile                 |
//+-----------------------------------------------------------------+
bool  表格  :: OnClickTableRow(const string clicked_object)
  {
//--- Abbrechen, falls  的  Modus für das Editieren einer Tabelle aktiv ist
   if(!m_read_only)
      return(false);
//--- Abbrechen, falls die Scrollbar aktiv ist
   if(m_scrollv.ScrollState() || m_scrollh.ScrollState())
      return(false);
//--- Abbrechen, falls es sich nicht um einen Klick auf eine Zelle dieser Tabelle handelt
   if(::StringFind(clicked_object,CElement::ProgramName()+"_table_edit_",0)<0)
      return(false);
//---  的  Bezeichner aus dem Objektnamen entnehmen
   int id=IdFromObjectName(clicked_object);
//--- Abbrechen, falls  的  Bezeichner nicht übereinstimmt
   if(id!=CElement::Id())
      return(false);
//--- Suche nach den Zeilenindex
   int row_index=0;
//--- Verschieben um einen Index, falls  的  fixierte Kopfzeilen-Modus aktiviert ist
   int t=(m_fix_first_row) ? 1 : 0;
//--- Spalten
   for(int c=0; c<m_visible_columns_total; c++)
     {
      //--- Abfrage  的  aktuellen Position des Schiebereglers  的  vertikalen Scrollbar
      int v=m_scrollv.CurrentPos()+t;
      //--- Zeilen
      for(int r=t; r<m_visible_rows_total; r++)
        {
         //--- Falls nicht auf diese Zelle geklickt wurde
         if(m_columns[c].m_rows[r].Name()==clicked_object)
           {
            //--- Speichere den Index  的  Zeile
            m_selected_item=row_index=v;
            //--- Speichere die Linie  的  Zelle
            m_selected_item_text=m_columns[c].m_rows[r].Description();
            break;
           }
         //--- Erhöhe den Zähler für die Zeilen
         if(v>=t && v<m_rows_total)
            v++;
        }
     }
//--- Abbrechen, falls auf die Überschrift geklickt wurde
   if(m_fix_first_row && row_index<1)
      return(false);
//--- Eine Nachricht darüber senden
   ::EventChartCustom(m_chart_id,ON_CLICK_LIST_ITEM,CElement::Id(),m_selected_item,"");
   return(true);
  }

来做吧 表格 :: OnEndEditCell()用于处理单元格中值输入的写方法。该方法还需要首先进行一些检查。在以下情况下退出该方法:

  • 未激活可编辑模式;
  • 程序名称或该单元格与表格的从属关系不匹配。
  • 控件ID不匹配。

如果所有检查都成功,那么我们将使用辅助方法 表格 :: ColumnIndexFromObjectName () 表格 :: RowIndexFromObjectName () 可见区域的单元格列和行(图形对象数组中的索引)。现在我们必须 将滚动条的滑块的当前位置添加到对象的索引 这样我们就可以得到数据数组的正确索引。然后,如果激活了固定标题的模式并且数组的索引= 0,我们仍然必须更正行索引。然后,我们需要检查单元格的值是否已更改。如果是这样,则将新值保存在相应的数据数组中,并显示一条消息,其中包含(1)图表ID,(2)事件ID( ON_END_EDIT ),(3)从列和行的索引以及当前单元格的值生成的控件ID和(4)行。 “ _”符号用作该行内的分隔符。 

class  表格  :  上市  CElement
  {
 私人的 :
   //--- Verarbeiten  的  manuellen Eingabe eines Wertes in eine Zelle
   bool              OnEndEditCell(const string edited_object);
   //--- Abfrage des Spaltenindex aus dem Objektnamen
   int               ColumnIndexFromObjectName(const string object_name);
   //--- 从对象名称查询行的索引
   int               RowIndexFromObjectName(const string object_name);
  };
//+----------------------------------------------------------------------+
//| Event für das Abschließen einer Eingabe eines Wertes in eine Zelle   |
//+----------------------------------------------------------------------+
bool  表格  :: OnEndEditCell(const string edited_object)
  {
//--- Abbrechen, falls  的  Modus für die Editierbarkeit deaktiviert ist
   if(m_read_only)
      return(false);
//--- Abbrechen, falls es sich nicht um einen Klick auf eine Zelle dieser Tabelle handelt
   if(::StringFind(edited_object,CElement::ProgramName()+"_table_edit_",0)<0)
      return(false);
//---  的  Bezeichner aus dem Objektnamen entnehmen
   int id=IdFromObjectName(edited_object);
//--- Abbrechen, falls  的  Bezeichner nicht übereinstimmt
   if(id!=CElement::Id())
      return(false);
//--- Abfrage des Spalten-  和  Zeilen- Index  的  Zelle
   int c =ColumnIndexFromObjectName(edited_object);
   int r =RowIndexFromObjectName(edited_object);
//--- Abfrage des Spalten-  和  Zeilen-Index in dem  那里 ta-Array
   int vc =c+m_scrollh.CurrentPos();
   int vr =r+m_scrollv.CurrentPos();
//--- Korrektur des Zeilenindex, falls auf eine Kopfzeile geklickt wird
   if(m_fix_first_row && r==0)
      vr=0;
//--- Abfrage des eingegebenen Wertes
   string cell_text=m_columns[c].m_rows[r].Description();
//--- Falls sich  的  Wert  的  Zelle geändert hat
   if(cell_text!=m_vcolumns[vc].m_vrows[vr])
     {
      //--- Abspeichern des Wertes in dem Array
      SetValue(vc,vr,cell_text);
      //--- Eine Nachricht darüber senden
      ::EventChartCustom(m_chart_id,ON_END_EDIT,CElement::Id(),0,string(vc)+"_"+string(vr)+"_"+cell_text);
     }
//---
   return(true);
  }
//+-----------------------------------------------------------------+
//| Abfrage des Spaltenindex aus dem Objektnamen                    |
//+-----------------------------------------------------------------+
int  表格  :: ColumnIndexFromObjectName(const string object_name)
  {
   ushort u_sep=0;
   string result[];
   int    array_size=0;
//---  的  Code des Trennzeichens erhalten
   u_sep=::StringGetCharacter("_",0);
//---  的  String aufteilen
   ::StringSplit(object_name,u_sep,result);
   array_size=::ArraySize(result)-1;
//--- Überprüfung  的  Überschreitung des ABCs
   if(array_size-3<0)
     {
      ::Print(PREVENTING_OUT_OF_RANGE);
      return(WRONG_VALUE);
     }
//--- Rückgabe des Index des Elementes
   return((int)result[array_size-3]);
  }
//+-----------------------------------------------------------------+
//| Abfrage des Zeilenindex aus dem Objektnamen                     |
//+-----------------------------------------------------------------+
int  表格  :: RowIndexFromObjectName(const string object_name)
  {
   ushort u_sep=0;
   string result[];
   int    array_size=0;
//---  的  Code des Trennzeichens erhalten
   u_sep=::StringGetCharacter("_",0);
//---  的  String aufteilen
   ::StringSplit(object_name,u_sep,result);
   array_size=::ArraySize(result)-1;
//--- Überprüfung  的  Überschreitung des ABCs
   if(array_size-2<0)
     {
      ::Print(PREVENTING_OUT_OF_RANGE);
      return(WRONG_VALUE);
     }
//--- Rückgabe des Index des Elementes
   return((int)result[array_size-2]);
  }

表格 :: HighlightSelectedItem()如果通过相应的模式激活了线条的高亮显示,则使用此方法。突出显示的行具有不同的背景和文本颜色。这些可编辑的属性已经过检查。

在方法开始时,将进行两次检查(请看下面的程序代码)。如果满足以下条件,程序将在此处终止:

  • 如果激活了单元格的可编辑模式;
  • 突出显示一行的模式被禁用。

如果这些检查成功,则如果冻结列或行的标题,则再次移动索引。现在,我们应该找到选定的行,并考虑滚动条滑块图像的当前位置,为带有两个计数器(用于列和行)的双循环中的单元格背景设置适当的颜色。对于其他线条的对象,使用数组中的颜色。 

class  表格  :  上市  CElement
  {
 私人的 :
   //--- 突出显示所选行
   void              HighlightSelectedItem(void);
  };
//+-----------------------------------------------------------------+
//| 突出显示所选行                              |
//+-----------------------------------------------------------------+
void  表格  :: HighlightSelectedItem(void)
  {
//--- Abbrechen, falls einer  的  Modi ("Nur lesen", "Auswählbare Zeile") deaktiviert ist.
   if(!m_read_only || !m_selectable_row)
      return;
//--- Verschieben um einen Index, falls  的  fixierte Kopfzeilen-Modus aktiviert ist
   int t=(m_fix_first_row) ? 1 : 0;
   int l=(m_fix_first_column) ? 1 : 0;
//--- Abfrage  的  aktuellen Position des Schiebereglers  的  Horizontalen Scrollbar
   int h=m_scrollh.CurrentPos()+l;
//--- Spalten
   for(int c=l; c<m_visible_columns_total; c++)
     {
      //--- Abfrage  的  aktuellen Position des Schiebereglers  的  vertikalen Scrollbar
      int v=m_scrollv.CurrentPos()+t;
      //--- Zeilen
      for(int r=t; r<m_visible_rows_total; r++)
        {
         //--- Verschiebung  的  Tabellendaten
         if(v>=t && v<m_rows_total)
           {
            //--- Einstellungen unter Berücksichtigung  的  ausgewählten Zeile
            color back_color=(m_selected_item==v) ? m_selected_row_color : m_vcolumns[h].m_cell_color[v];
            color text_color=(m_selected_item==v) ? m_selected_row_text_color : m_vcolumns[h].m_text_color[v];
            //--- Einstellung  的  Text-  和   背景 farbe  的  Zelle
            m_columns[c].m_rows[r].Color(text_color);
            m_columns[c].m_rows[r].BackColor(back_color);
            v++;
           }
        }
      //---
      h++;
     }
  }

另一个有用的模式是当鼠标指针悬停在其上方时突出显示该行的模式。为此, 表格 :: RowColorByHover()使用的方法。它还包括一些检查。如果没有成功完成,程序将在此时终止该方法。在以下情况下将终止:

  • 当鼠标指针悬停在突出显示行的模式时,将被禁用。
  • 表格编辑模式被激活。
  • 当添加了控件的表单被阻止时
  • 滚动条之一处于活动状态时(滑块当前正在移动)。

如果所有检查均已成功通过,则应在所有单元格中进行双循环,并根据鼠标指针当前位于哪个单元格上来更改其颜色。唯一的例外是突出显示的行。当我们到达这样的行时,仅该行的计数器增加一个,但单元格不变。 

class  表格  :  上市  CElement
  {
 私人的 :
   //--- Veränderung  的  Farbe  的  Zeile, wenn sich  的  Mauszeiger darüber befindet
   void              RowColorByHover(const int x,const int y);
  };
//+-------------------------------------------------------------------------+
//| Veränderung  的  Zeilenfarbe, wenn sich  的  Mauszeiger darüber befindet  |
//+-------------------------------------------------------------------------+
void  表格  :: RowColorByHover(const int x,const int y)
  {
//--- Abbrechen, wenn  的  Modus für das Hervorheben  的  Zeile deaktiviert ist  要么  wenn das Formular gesperrt ist
   if(!m_lights_hover || !m_read_only || m_wnd.IsLocked())
      return;
//--- Abbrechen, falls sich  的  Schieberegler einer Scrollbar gerade bewegt
   if(m_scrollv.ScrollState() || m_scrollh.ScrollState())
      return;
//--- Verschieben um einen Index, falls  的  fixierte Kopfzeilen-Modus aktiviert ist
   int t=(m_fix_first_row) ? 1 : 0;
   int l=(m_fix_first_column) ? 1 : 0;
//--- Abfrage  的  aktuellen Position des Schiebereglers  的  Horizontalen Scrollbar
   int h=m_scrollh.CurrentPos()+l;
//--- Spalten
   for(int c=l; c<m_visible_columns_total; c++)
     {
      //--- Abfrage  的  aktuellen Position des Schiebereglers  的  vertikalen Scrollbar
      int v=m_scrollv.CurrentPos()+t;
      //--- Zeilen
      for(int r=t; r<m_visible_rows_total; r++)
        {
         //--- Überprüfen, ob die Bandbreite des Arrays überschritten wird
         if(v>=t && v<m_rows_total)
           {
            //--- Überspringen, falls wir uns in dem "nur lesen"-Modus befinden, das Selektieren einer Zeile aktiviert ist  和  wir das selektierte Element erreicht haben
            if(m_selected_item==v && m_read_only && m_selectable_row)
              {
               v++;
               continue;
              }
            //--- Hervorheben  的  Zeile, falls sich  的  Mauszeiger darüber befindet
            if(x>m_columns[0].m_rows[r].X() && x<m_columns[m_visible_columns_total-1].m_rows[r].X2() &&
               y>m_columns[c].m_rows[r].Y() && y<m_columns[c].m_rows[r].Y2())
              {
               m_columns[c].m_rows[r].BackColor(m_cell_color_hover);
              }
            //--- Wiederherstellen  的  Standard Farbe, falls sich  的  Mauszeiger außerhalb des Bereiches dieser Zeile befindet
            else
              {
               if(v>=t && v<m_rows_total)
                  m_columns[c].m_rows[r].BackColor(m_vcolumns[h].m_cell_color[v]);
              }
            //---
            v++;
           }
        }
      //---
      h++;
     }
  }

现在,我们已经检查了表的所有管理方法。您可以查看 表格 :: OnEvent()在以下程序代码中查看事件处理程序。请注意方法 表格 :: HighlightSelectedItem()之后 处理垂直滚动条滑块的运动称为.

//+-----------------------------------------------------------------+
//| Event handler                                                   |
//+-----------------------------------------------------------------+
void  表格  :: OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Verarbeiten des Mauszeiger Bewegungs Events
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Abbrechen, falls das Element versteckt ist
      if(!CElement::IsVisible())
         return;
      //---Koordinaten  和   的  Status  的  linken Maustaste
      int x=(int)lparam;
      int y=(int)dparam;
      m_mouse_state=(bool)int(sparam);
      CElement::MouseFocus(x>X() && x<X2() && y>Y() && y<Y2());
      //--- Falls die Scrollbar aktiv ist
      if(m_scrollv.ScrollBarControl(x,y,m_mouse_state) || m_scrollh.ScrollBarControl(x,y,m_mouse_state))
         //--- Verschieben  的  Tabelle
         UpdateTable();
      //--- 突出显示所选行
      HighlightSelectedItem();
      //--- Veränderung  的  Farbe  的  Zeile, wenn sich  的  Mauszeiger darüber befindet
      RowColorByHover(x,y);
      return;
     }
//--- Verarbeitung von Klicks auf Objekte
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Falls eine Zeile  的  Tabelle geklickt wurde
      if(OnClickTableRow(sparam))
        {
         //--- 突出显示所选行
         HighlightSelectedItem();
         return;
        }
      //--- Falls ein Scrollbar-Button geklickt wurde
      if(m_scrollv.OnClickScrollInc(sparam) || m_scrollv.OnClickScrollDec(sparam) ||
         m_scrollh.OnClickScrollInc(sparam) || m_scrollh.OnClickScrollDec(sparam))
        {
         //--- Aktualisierung  的   那里 ten  的  Tabelle unter Berücksichtigung  的  letzten Veränderungen
         UpdateTable();
         //--- 突出显示所选行
         HighlightSelectedItem();
         return;
        }
      return;
     }
//--- Verarbeiten des Events über die Veränderung des Wertes in dem Eingabefeld
   if(id==CHARTEVENT_OBJECT_ENDEDIT)
     {
      OnEndEditCell(sparam);
      //--- Zurücksetzen  的  Farben  的  Tabelle
      ResetColors();
      return;
     }
  }

 


测试编辑框表

现在一切准备就绪,可以测试editbox表了,复制上一个示例中的EA交易,并删除与文本标签表相关的所有元素。现在在自定义中创建 C程序 类的实例 表格 类并声明用于创建表的方法:

class  C程序  :  上市  CWndEvents
  {
 私人的 :
   //---  的  Editbox-Tabelle
    表格             m_table;
   //---
 私人的 :
   //---  的  Editbox-Tabelle
#define TABLE1_GAP_X          (1)
#define TABLE1_GAP_Y          (42)
   bool              CreateTable(void);
  };

让我们创建一个包含以下内容的表 100 列和 1000 行组成。可见列数为 6,可见线数为 15。让我们修复标题(第一行和第一列),以便在滚动滚动条的滑块时它们不会移动。鼠标指针悬停在上方时,我们将激活选择线和突出显示线的模式。 

创建控件后,表数组将填充数据并进行格式化。我们以身作则 ALIGN_RIGHT 第一列的对齐方法。让我们以“斑马”样式绘制行的单元格,并且列文本的颜色以红色和蓝色完成。确保你有更新表使更改可见。 

//+-----------------------------------------------------------------+
//| Erzeugung  的  Tabelle                                           |
//+-----------------------------------------------------------------+
bool  C程序  :: CreateTable(void)
  {
#define COLUMNS1_TOTAL (100)
#define ROWS1_TOTAL    (1000)
//--- Abspeichern des Pointers des Formulars
   m_table.WindowPointer(m_window1);
//--- Koordinaten
   int x=m_window1.X()+TABLE1_GAP_X;
   int y=m_window1.Y()+TABLE1_GAP_Y;
//--- 可见列数  和  Zeilen
   int visible_columns_total =6;
   int visible_rows_total    =15;
//--- Vor  的  Erzeugung die Eigenschaften festlegen
   m_table.XSize(600);
   m_table.RowYSize(20);
   m_table.FixFirstRow(true);
   m_table.FixFirstColumn(true);
   m_table.LightsHover(true);
   m_table.SelectableRow(true);
   m_table.TextAlign( 居中对齐 );
   m_table.HeadersColor(C'255,244,213');
   m_table.HeadersTextColor(clrBlack);
   m_table.GridColor(clrLightGray);
   m_table.CellColorHover(clrGold);
   m_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
   m_table.VisibleTableSize(visible_columns_total,visible_rows_total);
//--- Erzeugung des Control-Elementes
   if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- Einfügen in die Tabelle:
//    Die erste Zelle ist leer
   m_table.SetValue(0,0,"-");
//---  的  Überschriften  的  Spalten
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=0; r<1; r++)
         m_table.SetValue(c,r,"SYMBOL "+string(c));
     }
//---  的  Überschriften  的  Zeilen, die Ausrichtung ist Rechts
   for(int c=0; c<1; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,"PARAMETER "+string(r));
         m_table.TextAlign(c,r,  ALIGN_RIGHT  );
        }
     }
//---   那里 ten-  和  Tabellen-Formatierung (Hintergrund  和  Zellenfarben)
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,string(c)+":"+string(r));
         m_table.TextColor(c,r,(c%2==0)? clrRed : clrRoyalBlue);
         m_table.CellColor(c,r,(r%2==0)? clrWhiteSmoke : clrWhite);
        }
     }
//--- Aktualisierung  的  Tabelle um die Änderungen sichtbar zu machen
   m_table.UpdateTable();
//--- Hinzufügen des Objektes zu dem Array aller Objektgruppen
   CWnd容器::AddToElementsArray(0,m_table);
   return(true);
  }

C程序 :: CreateTable()方法应在应用程序的主方法中调用。 (请看下面的程序代码的缩写版): 

//+----------------------------------------------------------------+
//| Erzeugung des Expert-Bedienfeldes                              |
//+----------------------------------------------------------------+
bool  C程序  :: CreateExpertPanel(void)
  {
//--- Erzeugen des Formulars 1 für die Controls
//--- Erzeugen  的  Controls:
//    Hauptmenü
//--- Kontextmenüs
//--- Erzeugen  的  Statuszeile
//--- Editbox-Tabelle
   if(!CreateTable())
      return(false);
//--- Neuzeichnen des  图表 
   m_chart.Redraw();
   return(true);
  }

编译程序并在图表上运行。如果正确填写了所有内容,我们将获得类似于以下屏幕截图所示的结果:

 图4.测试editbox表

图4.测试editbox表

一切正常。但是,如果您的文字超过 63 字符长,如果在单个单元格中输入,则文本不会完全显示。终端中可以显示文本的所有图形对象的限制为 63 符号。我们用那个 C画布 非常适合解决这个问题。此类包含用于显示文本的方法,没有任何限制。我们已经将该类用于某些控件(“ Trendy me”和“上下文”菜单)。项目:

那里 63 字符经常不足,第三个表是使用 C画布 类绘制。 

 


渲染表控件

呈现的表对每个单元格的字符数没有限制。此外,无需更改表格的可见区域即可配置每列的宽度。对于我们前面讨论的其他类型的表,这非常困难。这样我们就可以显示呈现表的一些优点:

  • 每个单元的符号数没有限制;
  • 每个列的宽度可以分别指定。
  • 只会有一个物体(OBJ_BITMAP_LABEL)用来生成表格,而不是生成各种对象,就像文本标签( OBJ_LABEL )或编辑框( OBJ_EDIT )的情况是。

文本标签表由以下组件组成:

  1. 背景
  2. 渲染表
  3. 垂直滚动条。
  4. 水平滚动条。

图5.呈现表的组件
 

图5.呈现表的组件

让我们检查用于创建此类表的类的代码。

 


C画布 Table 类的开发

来做吧 CT选项 创建一个结构以保存表的值和属性:

//+-----------------------------------------------------------------+
//| Klasse für die Erzeugung einer gerenderten Tabelle              |
//+-----------------------------------------------------------------+
class   C画布 Table  :  上市  CElement
  {
 私人的 :
   //--- Array für die Werte  和  Eigenschaften  的  Tabelle
   struct  CT选项 
     {
      string            m_vrows[];
      int               m_width;
      ENUM_ALIGN_MODE   m_text_align;
     };
    CT选项          m_vcolumns[];
  };

CT选项 设置表的基本大小(列和行的总数)时,用标准值初始化结构的变量。我们把所有列的宽度 100 像素固定,并且单元格中的对齐方式为 居中对齐

class   C画布 Table  :  上市  CElement
  {
 上市 :
   //--- Festlegen  的  Größe  的  Tabelle
   void              TableSize(const int columns_total,const int rows_total);
  };
//+-----------------------------------------------------------------+
//| Legt die Größe  的  Tabelle fest                                 |
//+-----------------------------------------------------------------+
void   C画布 Table ::TableSize(const int columns_total,const int rows_total)
  {
//--- Es muss mindestens eine Spalte geben
   m_columns_total=(columns_total<1) ? 1 : columns_total;
//--- Es muss mindestens zwei Zeilen geben
   m_rows_total=(rows_total<2) ? 2 : rows_total;
//--- Festlegen  的  Größe  的  Spalten-Arrays
   ::ArrayResize(m_vcolumns,m_columns_total);
//--- Festlegen  的  Größe  的  Zeilen-Arrays
   for(int i=0; i<m_columns_total; i++)
     {
      ::ArrayResize(m_vcolumns[i].m_vrows,m_rows_total);
      //--- Initialisierung  的  Spalteneigenschaften mit den Standardwerten
      m_vcolumns[i].m_width      =100;
      m_vcolumns[i].m_text_align = 居中对齐 ;
     }
  }

让我们只使用允许我们的方法 宽度 要么 文字对齐 设置表的大小后,对某些列(如有必要)进行设置。为此,您要做的就是初始化数组并将其传递给适当的方法。一个例子如下所示: 

class   C画布 Table  :  上市  CElement
  {
 上市 :
   //--- Festlegen  的  (1) 文字对齐  和  (2)  的  Breite für jede Spalte
   void              TextAlign(const ENUM_ALIGN_MODE &array[]);
   void              ColumnsWidth(const int &array[]);
  };
//+----------------------------------------------------------------+
//| Füllt das array mit den Textausrichtungs-Modi                  |
//+----------------------------------------------------------------+
void   C画布 Table ::TextAlign(const ENUM_ALIGN_MODE &array[])
  {
   int total=0;
   int array_size=::ArraySize(array);
//--- Abbrechen, falls ein Array  的  Größe 0 übergeben wurde
   if(array_size<1)
      return;
//--- Einstellen des Wertes, um ein Überschreiten  的  Bandbreite des Arrays zu verhindern
   total=(array_size<m_columns_total)? array_size : m_columns_total;
//--- Abspeichern  的  Werte in  的  Struktur
   for(int c=0; c<total; c++)
      m_vcolumns[c].m_text_align=array[c];
  }
//+----------------------------------------------------------------+
//| Sylt das Array mit den Spaltenbreiten                          |
//+----------------------------------------------------------------+
void   C画布 Table ::ColumnsWidth(const int &array[])
  {
   int total=0;
   int array_size=::ArraySize(array);
//--- Abbrechen, falls ein Array  的  Größe 0 übergeben wurde
   if(array_size<1)
      return;
//--- Einstellen des Wertes, um ein Überschreiten  的  Bandbreite des Arrays zu verhindern 
   total=(array_size<m_columns_total)? array_size : m_columns_total;
//--- Abspeichern  的  Werte in  的  Struktur
   for(int c=0; c<total; c++)
      m_vcolumns[c].m_width=array[c];
  }

在继续创建表之前,必须指定相对于指定参数(所有列的宽度,所有行的高度和滚动条的存在)的总大小以及可见区域的大小。为此,我们编写如下所示的方法 C画布 Table :: CalculateTableSize ():  

class   C画布 Table  :  上市  CElement
  {
 私人的 :
   //--- Gesamtgröße  和  die Größe des sichtbaren Bereiches  的  Tabelle
   int               m_table_x_size;
   int               m_table_y_size;
   int               m_table_visible_x_size;
   int               m_table_visible_y_size;
//---
 私人的 :
   //--- Berechnung  的  Größe  的  Tabelle
   void              CalculateTableSize(void);
  };
//+-----------------------------------------------------------------+
//| Berechnung  的  Größe  的  Tabelle                                |
//+-----------------------------------------------------------------+
void   C画布 Table  :: CalculateTableSize(void)
  {
//--- Berechnung  的  Gesamtbreite  的  Tabelle
   m_table_x_size=0;
   for(int c=0; c<m_columns_total; c++)
      m_table_x_size=m_table_x_size+m_vcolumns[c].m_width;
//--- Breite  的  Tabelle mit einer vertikalen Scrollbar
   int x_size=(m_rows_total>m_visible_rows_total) ? m_x_size-m_scrollh.ScrollWidth() : m_x_size-2;
//--- Falls  宽度  aller Spalten kleiner ist als  宽度   的  Tabelle, dann wird  宽度   的  Tabelle verwendet
   if(m_table_x_size<m_x_size)
      m_table_x_size=x_size;
//--- Berechnung  的  Gesamthöhe  的  Tabelle
   m_table_y_size=m_cell_y_size*m_rows_total-(m_rows_total-1);
//--- Festlegen  的  Rahmengröße, um einen Teil des Bildes anzuzeigen (sichtbarer Bereich  的  Tabelle)
   m_table_visible_x_size=x_size;
   m_table_visible_y_size=m_cell_y_size*m_visible_rows_total-(m_visible_rows_total-1);
//--- Falls es eine horizontale Scrollbar gibt, dann wird die Größe des Controls entlang  的  y-Achse angepasst
   int y_size=m_cell_y_size*m_visible_rows_total+2-(m_visible_rows_total-1);
   m_y_size=(m_table_x_size>m_table_visible_x_size) ? y_size+m_scrollh.ScrollWidth()-1 : y_size;
  }

在计算了表格的大小并创建了画布之后,我们需要开发一种绘制表格网格和单元格文本的方法。为了绘制网格,我们将其写为 C画布 Table :: DrawGrid() 方法。首先在第一个循环中绘制水平网格线,然后在第二个循环中绘制垂直网格线。  

class   C画布 Table  :  上市  CElement
  {
 私人的 :
   //--- Farbe des Gitters
   color             m_grid_color;
   //---  的  Größe (Höhe)  的  Zellen
   int               m_cell_y_size;
//---
 上市 :
   //--- Farbe des Gitters
   void              GridColor(const color clr)           { m_grid_color=clr;                }
//---
 私人的 :
   //--- Zeichnen des Gitters
   void              DrawGrid(void);
  };
//+-----------------------------------------------------------------+
//| Zeichnen des Gitters                                            |
//+-----------------------------------------------------------------+
void   C画布 Table  :: DrawGrid(void)
  {
//--- Farbe des Gitters
   uint clr=::ColorToARGB(m_grid_color,255);
//---  的  Größe des Canvas für das Zeichnen
   int x_size =m_canvas.XSize()-1;
   int y_size =m_canvas.YSize()-1;
//--- Koordinaten
   int x1=0,x2=0,y1=0,y2=0;
//--- Horizontale Linien
   x1=0;
   y1=0;
   x2=x_size;
   y2=0;
   for(int i=0; i<=m_rows_total; i++)
     {
      m_canvas.Line(x1,y1,x2,y2,clr);
      y2=y1+=m_cell_y_size-1;
     }
//--- Vertikale Linien
   x1=0;
   y1=0;
   x2=0;
   y2=y_size;
   for(int i=0; i<m_columns_total; i++)
     {
      m_canvas.Line(x1,y1,x2,y2,clr);
      x2=x1+=m_vcolumns[i].m_width;
     }
//--- Rechts
   x1=x_size;
   y1=0;
   x2=x_size;
   y2=y_size;
   m_canvas.Line(x1,y1,x2,y2,clr);
  }

C画布 Table :: DrawText()绘制文本的方法比绘制网格的方法稍微复杂一些。我们不仅应考虑当前列中文本的对齐方式,而且还应考虑前一列中文本的对齐方式,以便能够正确计算缩进量。我们从 10 像素 从单元格的角处进行左右对齐。单元格顶部的缩进是 3 像素点 。下面是此方法的详细程序代码: 

class   C画布 Table  :  上市  CElement
  {
 私人的 :
   //--- 文字颜色
   color             m_cell_text_color;
//---
 上市 :
   //--- Textfarbe  的  Tabelle
   void              TextColor(const color clr)           { m_cell_text_color=clr;           }
//---
 私人的 :
   //--- Zeichnen des Textes
   void              DrawText(void);
  };
//+-----------------------------------------------------------------+
//| Zeichnen des Textes                                             |
//+-----------------------------------------------------------------+
void   C画布 Table  :: DrawText(void)
  {
//--- Für die Berechnung  的  Koordinaten  和  des Offsets
   int  x             =0;
   int  y             =0;
   uint text_align    =0;
   int  column_offset =0;
   int  cell_x_offset =10;
   int  cell_y_offset =3;
//--- 文字颜色
   uint clr=::ColorToARGB(m_cell_text_color,255);
//--- Eigenschaften  的  Schrift
   m_canvas.FontSet(FONT,-80,FW_NORMAL);
//--- Spalten
   for(int c=0; c<m_columns_total; c++)
     {
      //--- Berechnung des Offsets für die erste Spalte
      if(c==0)
        {
         //---  的  Ausrichtung  内容  einer Zelle basiert auf dem Modus  的  für die Spalte gesetzt ist
         switch(m_vcolumns[0].m_text_align)
           {
            //--- Mittig
            case  居中对齐  :
               column_offset=column_offset+m_vcolumns[0].m_width/2;
               x=column_offset;
               break;
               //--- Rechts
            case   ALIGN_RIGHT   :
               column_offset=column_offset+m_vcolumns[0].m_width;
               x=column_offset-cell_x_offset;
               break;
               //---  链接 s
            case ALIGN_LEFT :
               x=column_offset+cell_x_offset;
               break;
           }
        }
      //---  的  Berechnung  的  Offset für alle Spalten mit Ausnahme  的  ersten
      else
        {
         //---  的  Ausrichtung  内容  einer Zelle basiert auf dem Modus  的  für die Spalte gesetzt ist
         switch(m_vcolumns[c].m_text_align)
           {
            //--- Mittig
            case  居中对齐  :
               //---  的  Berechnung des Offset relativ zu  的  Ausrichtung in  的  vorherigen Spalte
               switch(m_vcolumns[c-1].m_text_align)
                 {
                  case  居中对齐  :
                     column_offset=column_offset+(m_vcolumns[c-1].m_width/2)+(m_vcolumns[c].m_width/2);
                     break;
                  case   ALIGN_RIGHT   :
                     column_offset=column_offset+(m_vcolumns[c].m_width/2);
                     break;
                  case ALIGN_LEFT :
                     column_offset=column_offset+m_vcolumns[c-1].m_width+(m_vcolumns[c].m_width/2);
                     break;
                 }
               //---
               x=column_offset;
               break;
               //--- Rechts
            case   ALIGN_RIGHT   :
               //---  的  Berechnung des Offset relativ zu  的  Ausrichtung in  的  vorherigen Spalte
               switch(m_vcolumns[c-1].m_text_align)
                 {
                  case  居中对齐  :
                     column_offset=column_offset+(m_vcolumns[c-1].m_width/2)+m_vcolumns[c].m_width;
                     x=column_offset-cell_x_offset;
                     break;
                  case   ALIGN_RIGHT   :
                     column_offset=column_offset+m_vcolumns[c].m_width;
                     x=column_offset-cell_x_offset;
                     break;
                  case ALIGN_LEFT :
                     column_offset=column_offset+m_vcolumns[c-1].m_width+m_vcolumns[c].m_width;
                     x=column_offset-cell_x_offset;
                     break;
                 }
               //---
               break;
               //---  链接 s
            case ALIGN_LEFT :
               //---  的  Berechnung des Offset relativ zu  的  Ausrichtung in  的  vorherigen Spalte
               switch(m_vcolumns[c-1].m_text_align)
                 {
                  case  居中对齐  :
                     column_offset=column_offset+(m_vcolumns[c-1].m_width/2);
                     x=column_offset+cell_x_offset;
                     break;
                  case   ALIGN_RIGHT   :
                     x=column_offset+cell_x_offset;
                     break;
                  case ALIGN_LEFT :
                     column_offset=column_offset+m_vcolumns[c-1].m_width;
                     x=column_offset+cell_x_offset;
                     break;
                 }
               //---
               break;
           }
        }
      //--- Zeilen
      for(int r=0; r<m_rows_total; r++)
        {
         //---
         y+=(r>0) ? m_cell_y_size-1 : cell_y_offset;
         //---
         switch(m_vcolumns[c].m_text_align)
           {
            case  居中对齐  :
               text_align=TA_CENTER|TA_TOP;
               break;
            case   ALIGN_RIGHT   :
               text_align=TA_RIGHT|TA_TOP;
               break;
            case ALIGN_LEFT :
               text_align=TA_LEFT|TA_TOP;
               break;
           }
         //--- Zeichnen des Textes
         m_canvas.TextOut(x,y,m_vcolumns[c].m_vrows[r],clr,text_align);
        }
      //--- Zurücksetzen  的  y-Koordinate für den nächsten Durchlauf
      y=0;
     }
  }

在前两种表格类型中,我们研究了使用滚动条通过更改表格可见区域中的对象(文本标签和编辑框)的值来完成移动。在这里,我们移动矩形框以获得图像的可见性。换句话说,表(图像)的大小最初等于所有列的总和和所有行的高度。这是原始图像的大小,可以在其中移动框以提高可见度。可见性框架的大小可以随时更改,但在此处创建控件后将直接更改。 C画布 Table :: CreateCells()方法已建立。 

框架的大小可以通过属性进行调整 OBJPROP_XSIZEOBJPROP_YSIZE 可以通过属性设置框架的位移(在图像内) OBJPROP_XOFFSETOBJPROP_YOFFSET 被控制。 (请参见下面的示例): 

//--- Festlegen  的  Größe des sichtbaren Bereiches
   ::ObjectSetInteger(m_chart_id,name,OBJPROP_XSIZE,m_table_visible_x_size);
   ::ObjectSetInteger(m_chart_id,name,OBJPROP_YSIZE,m_table_visible_y_size);
//--- Festlegen des Offsets für den Rahmen innerhalb des Bildes entlang  的  X  和  Y-Achse
   ::ObjectSetInteger(m_chart_id,name,OBJPROP_XOFFSET,0);
   ::ObjectSetInteger(m_chart_id,name,OBJPROP_YOFFSET,0);

让我们做个简单的方法 C画布 Table :: ShiftTable()相对于滚动条滑块的当前位置移动框架。垂直移位等于线的高度,但是水平移位以像素为单位(请参见以下程序示例): 

class   C画布 Table  :  上市  CElement
  {
 上市 :
   //--- Verschiebung  的  Tabelle, relativ zu den Positionen  的  Scrollbars
   void              ShiftTable(void);
  };
//+-----------------------------------------------------------------+
//| Verschiebung  的  Tabelle relativ zu den Scrollbars              |
//+-----------------------------------------------------------------+
void   C画布 Table  :: ShiftTable(void)
  {
//--- Abfrage  的  aktuellen Positionen  的  Schieberegler  的  vertikalen  和  horizontalen Scrollbars
   int h=m_scrollh.CurrentPos();
   int v=m_scrollv.CurrentPos();
//--- Berechnung  的  Position  的  Tabelle in Relation zu den Schiebereglern  的  Scrollbars
   long c=h;
   long r=v*(m_cell_y_size-1);
//--- Verschieben  的  Tabelle
   ::ObjectSetInteger(m_chart_id,m_canvas.Name(),OBJPROP_XOFFSET,c);
   ::ObjectSetInteger(m_chart_id,m_canvas.Name(),OBJPROP_YOFFSET,r);
  }

一般 C画布 Table :: DrawTable()绘制表格的方法如下: 

class   C画布 Table  :  上市  CElement
  {
 上市 :
   //--- Zeichne die Tabelle unter Berücksichtigung  的  letzten Änderungen
   void              DrawTable(void);
  };
//+-----------------------------------------------------------------+
//| Zeichnen  的  Tabelle                                            |
//+-----------------------------------------------------------------+
void   C画布 Table  :: DrawTable(void)
  {
//---  的   背景  transparent machen
   m_canvas.Erase(::ColorToARGB(clrNONE,0));
//--- Zeichnen des Gitters
   DrawGrid();
//--- Zeichnen des Textes
   DrawText();
//---  那里 rstellen  的  zuletzt gezeichneten Veränderungen
   m_canvas.Update();
//--- Verschiebung  的  Tabelle in Relation zu den Scrollbars
   ShiftTable();
  }

现在一切就绪,可以测试该表了。 

 


测试渲染的表

复制以前的EA,并删除与 表格 餐桌架。现在在自定义中创建 C程序 类的实例 C画布 Table 类并声明(1) C程序 :: CreateCanvasTable()创建表的方法以及(2)缩进,如以下示例所示:

class  C程序  :  上市  CWndEvents
  {
 私人的 :
   //--- 渲染表
     C画布 Table       m_canvas_table;
   //---
 私人的 :
   //--- 渲染表
#define TABLE1_GAP_X          (1)
#define TABLE1_GAP_Y          (42)
   bool              CreateCanvasTable(void);
  };

我们用一张桌子 15 列和 1000 生成线。可见线数为 16。我们不需要设置可见列的数量,因为水平移动以像素为单位。在这种情况下,应明确指定表格可见区域的宽度。让他们上 601 设置像素。 

例如,让我们设置所有列的宽度(前两列除外) 70 设置像素。第一和第二列的宽度等于 10090 像素集。在所有列中(前三列除外),文本均显示在中间。在第一和第三列中,对齐方式是正确的,而在第二列中,对齐方式则是左侧。完整的程序代码 C程序 :: CreateCanvasTable()方法显示在以下程序代码中:

//+-----------------------------------------------------------------+
//| Erzeugung  的  gerenderten Tabelle                               |
//+-----------------------------------------------------------------+
bool  C程序  :: CreateCanvasTable(void)
  {
#define COLUMNS1_TOTAL 15
#define ROWS1_TOTAL    1000
//--- Abspeichern des Pointers des Formulars
   m_canvas_table.WindowPointer(m_window1);
//--- Koordinaten
   int x=m_window1.X()+TABLE1_GAP_X;
   int y=m_window1.Y()+TABLE1_GAP_Y;
//--- Anzahl  的  sichtbaren Zeilen
   int visible_rows_total=16;
//--- Array mit Spaltenbreiten
   int width[COLUMNS1_TOTAL];
   ::ArrayInitialize(width,70);
   width[0]=100;
   width[1]=90;
//--- Array für die Textausrichtung in den Spalten
   ENUM_ALIGN_MODE align[COLUMNS1_TOTAL];
   ::ArrayInitialize(align, 居中对齐 );
   align[0]=  ALIGN_RIGHT  ;
   align[1]=ALIGN_LEFT;
   align[2]=  ALIGN_RIGHT  ;
//--- Vor  的  Erzeugung die Eigenschaften festlegen
   m_canvas_table.XSize(601);
   m_canvas_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
   m_canvas_table.VisibleTableSize(0,visible_rows_total);
   m_canvas_table.TextAlign(align);
   m_canvas_table.ColumnsWidth(width);
   m_canvas_table.GridColor(clrLightGray);
//--- Tabelle mit  那里 ten auffüllen
   for(int c=0; c<COLUMNS1_TOTAL; c++)
      for(int r=0; r<ROWS1_TOTAL; r++)
         m_canvas_table.SetValue(c,r,string(c)+":"+string(r));
//--- Erzeugen des Controls
   if(!m_canvas_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- Hinzufügen des Objektes zu dem Array aller Objektgruppen
   CWnd容器::AddToElementsArray(0,m_canvas_table);
   return(true);
  }

该方法必须在用于生成图形界面的main方法中调用。 

//+-----------------------------------------------------------------+
//| Erzeugung des Trading-Panels                                    |
//+-----------------------------------------------------------------+
bool  C程序  :: CreateExpertPanel(void)
  {
//--- Erzeugen des Formulars 1 für die Controls
//--- Erzeugen  的  Controls:
//    Hauptmenü
//--- Kontextmenüs
//--- Erzeugen  的  Statuszeile
//--- Erzeugung  的  gerenderten Tabelle
   if(!CreateCanvasTable())
      return(false);
//--- Neuzeichnen des  图表 
   m_chart.Redraw();
   return(true);
  }

编译程序并在图表上运行。以下屏幕截图显示了结果:

 图6.在EA中测试呈现的表

图6.在EA中测试呈现的表

在本系列第一部分的第五章中,我们测试了脚本中表单的使用。没有滚动条的表可以在这种类型的MQL应用程序中使用。例如,您可以将呈现的表添加到表单的脚本中,并将数据全部 250 更新毫秒。将前面显示的表添加到自定义类。此外,程序代码必须与 C程序 :: OnEvent()脚本事件处理程序,如下所示, 要添加。现在,第二列中的数据以指定的时间间隔更改。 

//+-----------------------------------------------------------------+
//| Events                                                          |
//+-----------------------------------------------------------------+
void  C程序  :: OnEvent(const int milliseconds)
  {
   static int count =0;  // Counter
   string     str   =""; // Header row
//---  的  Kopfzeile zeigt den Prozess
   switch(count)
     {
      case 0 : str="SCRIPT PANEL";     break;
      case 1 : str="SCRIPT PANEL .";   break;
      case 2 : str="SCRIPT PANEL ..";  break;
      case 3 : str="SCRIPT PANEL  ... "; break;
     }
//--- Aktualisierung  的  Kopfzeile
   m_window.CaptionText(str);
//--- Änderung  的   那里 ten  的  ersten Spalte
   for(int r=0; r<13; r++)
      m_canvas_table.SetValue(1,r,string(::rand () ));
//--- Anzeigen  的  neuen Tabellendaten
   m_canvas_table.DrawTable();
//--- Neuzeichnen des  图表 
   m_chart.Redraw();
//--- Erhöhung des Zählers
   count++;
//--- Zurücksetzen auf Null, falls 3 überschritten wird
   if(count>3)
      count=0;
//--- Pause
   ::Sleep(milliseconds);
  }

编译程序并在图表上运行此脚本现在,您应该看到以下内容: 

 图7.在脚本中测试呈现的表

图7.在脚本中测试呈现的表

我们一直在开发 C画布 Table 用于创建渲染表的完整类。现在该是一些初步结果的时候了。 

 


结论

在本文中,我们讨论了用于创建重要接口元素(表)的三个类。这些类别中的每一个都有自己的特定特征,最适合特定情况。例如,CTable类提供了开发带有可编辑框的表的可能性,从而可以对这些框进行格式化,从而使它们看起来非常用户友好。另一方面,CCanvasTable类使您可以绕过单元格中字符数的限制,并提供为每列指定单独宽度的选项。这些不是表的最终版本。如有必要,可以在以后进行扩展。

在下一篇文章中,我们将讨论用于开发选项卡控件的类,这些类在图形界面中通常使用。

您可以下载并测试第七部分的所有材料。如果您对本材料的使用有任何疑问,可以先参考该库中文章的详细说明,或者在本文的评论中提出您的问题。

第七部分文章(章节)清单:

由MetaQuotes Software Corp.从俄语翻译而来。
来源文章: //www.tbxfkj.com/ru/articles/2500

附加的文件 |
easyandfastgui_mql4.zip (313.25 KB)
easyandfastgui_mql5.zip (313.88 KB)
哪一个Überprü交易之前的交易机器人ö市场上的出版物应该存在 哪一个Überprü交易之前的交易机器人ö市场上的出版物应该存在

Ver之前的所有Markets产品ö有一个强制性的初步äufige Überprü真菌,达到标准质量ä拥有。在本文中,我们将讨论äufigsten Fehlern erzä制造商在交易机器人和技术指标时做出的选择。我们还将向您展示如何在产品投放市场之前将其投放到Market中ändig überprüfen soll.

对于交易者:一种回溯测试是好的,而第四种则更好 救生衣ür交易员:一项回测是好的,而四项则是更好

在每个交易者进行第一次单独测试之前,都会有一个相同的问题-"我应该使用四种模式中的哪一种?"所提供的每种模式都有其自身的优势和特色,这就是我们让它变得更容易的原因-我们将通过一个按钮直接启动所有模式!它显示在文章中ü借助Win API和小魔术,聆听如何同时查看测试的所有四个图。

Universal Expert Advisor:事件模型和交易策略原型(第2部分) Universal Expert Advisor:事件模型和交易策略原型(第2部分)

这篇文章ü继续由一位通用专家顾问撰写的一系列出版物。本部分介绍了ü基于集中式数据处理的原始事件模型确定了此交易引擎的基类CStrategy的结构。

了解CCanvas类。边缘等效ä抗锯齿和阴影 了解CCanvas类。边缘等效ä抗锯齿和阴影

边缘方程的算法äCCanvas类是为此的基础ür所有具有边方程的构造ä使用杀戮。本文介绍了该算法的工作原理并提供了ä可视化的好例子。它还处理图形对象的绘图底纹并具有执行ü开发了在画布上绘制底纹的算法。数值库ALGLIB是fü使用r计算。