文章 "图形界面 X: 标准图表控件 (集成编译 4)"

 

新文章 图形界面 X: 标准图表控件 (集成编译 4)已发布:

这一次我们将研究标准图表控件。它可以创建具有同步水平滚动功能的子图表数组。此外, 我们将继续优化库代码以降低 CPU 负载。

以下的屏幕截图显示了最终结果。在这个示例中, 子图表数据可以水平地滚动, 类似于主图表那样的实现方式。此外, 子图表之间的导航通过日历操纵, 包括快速日期跳转。

 图例. 2. 标准图表控件测试。

图例. 2. 标准图表控件测试。

作者:Anatoli Kazharski

 
Если к этому прибавить ещё перемещение курсора мыши в области графика и активное взаимодействие с графическим интерфейсом MQL-приложения, то потребление вырастет ещё больше. Задача состоит в том, чтобы ограничить работу таймера движка библиотеки и исключить перерисовку графика по приходу события перемещения курсора мыши.

对于OBJ_CHART 滚动,为什么要使用计时器?对于与界面的交互,也有类似的问题。看来使用鼠标事件就足够了。

 
fxsaber:

对于OBJ_CHART 滚动,为什么要使用计时器?对于与界面的交互,也有类似的问题。毕竟,鼠标事件似乎已经足够了。

您引用的内容并不是指OBJ_CHART,而是指整个库引擎的计时器。这就是为什么这个问题的解决方案被放在 "优化库引擎的定时器和事件处理程序 "一文的一个单独部分,作为主主题的补充。

定时器用于在鼠标移动时改变控件的颜色,以及加速滚动列表、表格、日历和输入字段中的值。

//---

附注: OBJ_CHART 的滚动只是通过鼠标光标移动事件CHARTEVENT_MOUSE_MOVE 来 实现的。下面列出的是 "标准图表 "元素(类CStandardChart)事件的处理程序(精简版)代码:

//+------------------------------------------------------------------+
//| 事件处理|
//+------------------------------------------------------------------+
void CStandardChart::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- 处理光标移动事件
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- 如果项目被隐藏,则退出
      if(!CElement::IsVisible())
         return;
      //--- 如果处于调整子窗口大小模式,则退出
      if(CheckDragBorderWindowMode())
         return;
      //--- 如果子窗口编号不匹配,则退出
      if(CElement::m_subwin!=CElement::m_mouse.SubWindowNumber())
         return;
      //--- 如果表单被其他元素挡住,则退出
      if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
         return;
      //--- 重点检查
      CElement::MouseFocus(m_mouse.X()>X() && m_mouse.X()<X2() && m_mouse.Y()>Y() && m_mouse.Y()<Y2());
      //--- 如果有一个焦点
      if(CElement::MouseFocus())
         //-- 图表的水平滚动
         HorizontalScroll();
      //--- 如果没有焦点且鼠标左键被释放
      else if(!m_mouse.LeftButtonState())
        {
         //--- 隐藏水平滚动指针
         m_x_scroll.Hide();
         //--- 解锁表格
         if(m_wnd.IdActivatedElement()==CElement::Id())
           {
            m_wnd.IsLocked(false);
            m_wnd.IdActivatedElement(WRONG_VALUE);
           }
        }
      //---
      return;
     }
//...
  }
 
Anatoli Kazharski:

控制元素在鼠标移动时的定时颜色变化安排

为什么这里不能使用鼠标?
 
fxsaber:
为什么这里不能使用鼠标?

因为颜色的变化是平滑的(步数由用户设定)。

这也适用于列表的滚动。如果使用 SB 中实现的方法,则会出现锯齿状(不均匀)滚动。

 
Anatoli Kazharski:

因为可以提供平滑的颜色变化(步数由用户设定)。

这也适用于列表的滚动。如果使用 SB 中实现的方法,就会出现锯齿状(不均匀)滚动。

为什么OBJ_CHART 没有锯齿状滚动?
 
fxsaber:
为什么OBJ_CHART 不会出现撕裂?

在什么情况下(相对于文章中的测试智能交易系统)?

  1. 在滚动日历时?
  2. 在项目事件处理程序(CStandardChart) 中通过CHARTEVENT_MOUSE_MOVE 事件手动滚动时

如果是前者,则图表滚动与日历滚动一样是定时的。也就是说,日历日期更改事件(ON_CHANGE_DATE) 的生成时间间隔为16 毫秒。

如果是第二种情况,则会计算出偏移量,但并不总是等于1 bar。因此,通过CHARTEVENT_MOUSE_MOVE 事件进行的手动滚动似乎才是流畅的。

 
Anatoli Kazharski:

如果是第二种情况,移位是经过计算的,并不总是等于1 小节。这样看来,通过CHARTEVENT_MOUSE_MOVE 事件手动滚动是很流畅的。

明白了,谢谢!

 
感谢您的文章。我很期待它。没有失望:)
 

阿纳托利,请告诉我错误的原因是什么?

2016.10.19 03:09:04.993 TestTable (EURUSD,H1)   invalid pointer access in 'Scrolls.mqh' (698,10)

更新前一切正常。现在,在创建CTable 表时却出现了这个错误。

请告诉我哪里出错了--我已经打印了每一行--界面是建好了,但在某个地方出了问题,....。错误。

归档文件中有一个示例。

附加的文件:
TestTable.zip  734 kb
 

找到了。

以 MQL4\Experts\Article07\TestLibrary02\TestLibrary02.mq4 为例。

从你上面的例子来看:

使列数和可见列数相同 ,编译,运行,然后出错。

//+------------------------------------------------------------------+
//|| 创建表格|
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
  {
//#define COLUMNS1_TOTAL (100)
//#define ROWS1_TOTAL (1000)
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL    (1000)
//--- 保存指向表单的指针
   m_table.WindowPointer(m_window1);
//--- 坐标
   int x=m_window1.X()+TABLE1_GAP_X;
   int y=m_window1.Y()+TABLE1_GAP_Y;
//--- 可见列数和行数
   int visible_columns_total =6;
   int visible_rows_total    =15;
//--- 创建前设置属性
   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(ALIGN_CENTER);
   m_table.HeadersColor(C'255,244,213');
   m_table.HeadersTextColor(clrBlack);
   m_table.CellColorHover(clrGold);
   m_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
   m_table.VisibleTableSize(visible_columns_total,visible_rows_total);
//--- 创建一个控件
   if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- 让我们填写表格:
// 第一个单元格为空
   m_table.SetValue(0,0,"-");
//--- 栏目标题
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=0; r<1; r++)
         m_table.SetValue(c,r,"SYMBOL "+string(c));
     }
//--- 行标题,文本对齐方式 - 向右
   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);
        }
     }
//--- 数据和表格格式化(背景颜色和单元格颜色)
   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);
        }
     }
//-- 更新表格以显示变化
   m_table.UpdateTable();
//--- 将对象添加到对象组的通用数组中
   CWndContainer::AddToElementsArray(0,m_table);
   return(true);
  }
//+------------------------------------------------------------------+
实际上,如果行数和可见行数相同,也会出现同样的错误。