概述
在本文中,我将创建一个可以显示开发人员指定的数据的仪表板。这样的面板将便于在图表上直观地显示数据和进行可视化调试,因为在面板上查看必要的值比在调试器中跟踪它们更方便。我指的是根据某些数据值调试策略的情况。
我将以终端数据窗口原型的形式制作面板,并用相同的数据填充
用于获取表格数据的类
由于根据可见的或者虚拟的预先确定的坐标在面板上排列数据很方便,我们将首先创建用于排列表格数据的类。表格可以表示为一个简单的网格,其线交点将是表格单元格的坐标。可以将任何可见数据放置在这样的坐标处。该表具有一定数量的行(水平行),每行具有一定数量(垂直行)的单元格。在一个简单的网格表中,所有行都有相同数量的单元格。
基于此,我们需要三个类:
表格单元格类,
表格行类,
表格类。
表格单元格类包括表格中的行索引和列索引,以及面板中表格单元格视觉位置的坐标——相对于面板左上角表格原点的X和Y坐标。
表格行类包括表单元格类。我们可以在一行中创建所需数量的单元格。
表格类包括一个表行列表。可以创建表中的行,并添加所需数量的行。
让我们简单地看一下这三个类。
表格单元格类
//+------------------------------------------------------------------+
//| Table cell class |
//+------------------------------------------------------------------+
class CTableCell : public CObject
{
private:
int m_row; // Row
int m_col; // Column
int m_x; // X coordinate
int m_y; // Y coordinate
public:
//--- Methods of setting values
void SetRow(const uint row) { this.m_row=(int)row; }
void SetColumn(const uint col) { this.m_col=(int)col; }
void SetX(const uint x) { this.m_x=(int)x; }
void SetY(const uint y) { this.m_y=(int)y; }
void SetXY(const uint x,const uint y)
{
this.m_x=(int)x;
this.m_y=(int)y;
}
//--- Methods of obtaining values
int Row(void) const { return this.m_row; }
int Column(void) const { return this.m_col; }
int X(void) const { return this.m_x; }
int Y(void) const { return this.m_y; }
//--- Virtual method for comparing two objects
virtual int Compare(const CObject *node,const int mode=0) const
{
const CTableCell *compared=node;
return(this.Column()>compared.Column() ? 1 : this.Column()<compared.Column() ? -1 : 0);
}
//--- Constructor/destructor
CTableCell(const int row,const int column) : m_row(row),m_col(column){}
~CTableCell(void){}
};
该类继承自基类,用于构建MQL5标准库,因为它将搭配MQL5 标准库的CArrayObj列表,而列表只能包含CObject对象或从基本CObject继承的对象。
所有变量和方法的函数都非常透明且易于理解。变量用于存储表格行(Row)和列(Column)的值,而坐标是面板中表格单元格左上角的相对坐标。使用这些坐标,可以绘制一些东西或将其放置在面板上。
需要Compare虚拟方法来查找和比较两个表单元格对象,该方法是在基类CObject类中声明的:
//--- method of comparing the objects
virtual int Compare(const CObject *node,const int mode=0) const { return(0); }
它返回空值,应在继承的类中重写。
由于表格单元格是添加到表格行中的,即在视觉上是水平的,因此搜索和比较应按水平单元格编号进行,即按列值进行。这正是重写的虚拟Compare方法在这里所做的:
//--- Virtual method for comparing two objects
virtual int Compare(const CObject *node,const int mode=0) const
{
const CTableCell *compared=node;
return(this.Column()>compared.Column() ? 1 : this.Column()<compared.Column() ? -1 : 0);
}
如果当前对象的列值大于正在比较的对象的值(传递给方法的指针),则返回1。如果列值小于要比较的列值,则返回-1。否则,返回零。因此,该方法返回的零值表示被比较的对象的值相等。
表格行类
单元格对象将添加到表格行中。如果一行中的单元格是水平相邻的,则表中的行就是垂直排列的。
这里我们只需要知道行索引及其在面板上的Y坐标:
//+------------------------------------------------------------------+
//| Table row class |
//+------------------------------------------------------------------+
class CTableRow : public CObject
{
private:
CArrayObj m_list_cell; // Cell list
int m_row; // Row index
int m_y; // Y coordinate
public:
//--- Return the list of table cells in a row
CArrayObj *GetListCell(void) { return &this.m_list_cell; }
//--- Return (1) the number of table cells in a row (2) the row index in the table
int CellsTotal(void) const { return this.m_list_cell.Total(); }
int Row(void) const { return this.m_row; }
//--- (1) Set and (2) return the Y row coordinate
void SetY(const int y) { this.m_y=y; }
int Y(void) const { return this.m_y; }
//--- Add a new table cell to the row
bool AddCell(CTableCell *cell)
{
this.m_list_cell.Sort();
if(this.m_list_cell.Search(cell)!=WRONG_VALUE)
{
::PrintFormat("%s: Table cell with index %lu is already in the list",__FUNCTION__,cell.Column());
return false;
}
if(!this.m_list_cell.InsertSort(cell))
{
::PrintFormat("%s: Failed to add table cell with index %lu to list",__FUNCTION__,cell.Column());
return false;
}
return true;
}
//--- Return the pointer to the specified cell in the row
CTableCell *GetCell(const int column)
{
const CTableCell *obj=new CTableCell(this.m_row,column);
int index=this.m_list_cell.Search(obj);
delete obj;
return this.m_list_cell.At(index);
}
//--- Virtual method for comparing two objects
virtual int Compare(const CObject *node,const int mode=0) const
{
const CTableRow *compared=node;
return(this.Row()>compared.Row() ? 1 : this.Row()<compared.Row() ? -1 : 0);
}
//--- Constructor/destructor
CTableRow(const int row) : m_row(row) { this.m_list_cell.Clear(); }
~CTableRow(void) { this.m_list_cell.Clear(); }
};
包含新添加的单元格对象的CArrayObj列表在类中声明。
在Compare虚拟方法中,我们按行索引值(Row)比较对象,因为添加新行时,我们只需要按行索引进行搜索。如果未找到具有此类索引的行,则搜索方法(Search)将返回-1,否则搜索将返回列表中找到的对象位置的索引。Search方法在CArrayObj类中声明和实现:
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::Search(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos].Compare(element,m_sort_mode)==0)
return(pos);
//--- not found
return(-1);
}
正如我们所看到的,它使用比较两个对象的虚拟Compare方法来确定对象的相等性。