感谢您的分享。
如果需要继承该类,这种实现方式有一个很大的缺点。
1.没有默认构造函数,参数构造函数按大小设置重要参数。例如,如果需要根据类的子类中的参数来计算面板的大小,那么这个逻辑就必须在类外实现,或者在类中实现,但计算要在一个单独的函数中进行,这在一定程度上破坏了逻辑,因为参数构造函数的调用(没有默认构造函数)会出现在初始化列表中。也许更好的解决办法是将初始化从构造函数移到类函数中。
2.带参数的部分被声明为私有,这就不允许后代实现不同的颜色方案或更改页眉大小等功能。
3.我知道这项工作尚未完成,但有些函数还没有实现,例如 SetButtonClose(开/关)、SetButtonMinimize(开/关)。
有了源代码,最终完成它就不成问题了,但还是......
感谢您的分享。
如果需要继承该类,这种实现方式有一个很大的缺点。
1.没有默认构造函数,参数构造函数按大小设置重要参数。例如,如果需要根据类的子类中的参数来计算面板的大小,那么这个逻辑就必须在类外实现,或者在类中实现,但计算要在一个单独的函数中进行,这在一定程度上破坏了逻辑,因为参数构造函数的调用(没有默认构造函数)将会出现在初始化列表中。也许更好的解决办法是将初始化从构造函数移到类函数中。
2.带参数的部分被声明为私有,这就不允许后代实现不同的颜色方案或改变页眉的大小等。
3.3. 我知道工作还没有完成,但有些函数还没有实现,例如 SetButtonClose(开/关)、SetButtonMinimize(开/关)。
有了源代码,最终完成它就不成问题了,但还是......
这篇文章是一篇教程。其中,面板涵盖了最基本的需求。
1.子代有自己的构造函数,其初始化列表中必须包含父代的构造函数。您可以在其中指定所需的尺寸。
我还没有考虑过颜色方案)以及标题的大小。
这些方法在公共部分声明。奇怪的是,它们并没有被实现。我记得当时我正在测试它们的启用/禁用....。我不得不凭记忆从头开始重写这个类,因为它的第一个版本在磁盘空间耗尽时被 Windows 销毁了。我一定是忘了还原它们。谢谢,我会修好的。
是的,有了源代码--所有的牌都掌握在读者手中。这正是教程文章的目的所在。
这篇文章具有指导性。在这篇文章中,专家小组介绍了最起码的需求。
1.子代有自己的构造函数,其初始化列表必须包含父代的构造函数。在其中指定所需的尺寸。
我甚至还没有考虑过配色方案)以及页眉的尺寸。
这些方法在公共部分声明。奇怪的是,它们并没有被实现。我清楚地记得,我当时正在测试它们的启用/禁用....。我不得不凭记忆从头开始重写这个类,因为它的第一个版本在磁盘空间耗尽时被 Windows 销毁了。我一定是忘了还原它们。谢谢,我会修好的。
是的,有了源代码--所有的牌都掌握在读者手中。这正是教程文章的目的所在。
1.是的,但只要在初始化列表 中调用了祖先构造函数,就必须在某个地方对传入的参数进行计算。特别是如果它不是最原始的。
例如,计算右下角初始显示的 X、Y 位置,根据预期的表格行数计算高度....。这将需要 3 个额外的类函数,而不是在其构造函数中调用祖先构造函数的一段代码中完成的。 虽然它可以工作,但看起来更像一根拐杖。如果能让类的架构更适应进一步的变化,那么这样的代码就不太美观了。(当然,这是一个完美主义者的观点)。
2.小的修饰会使产品更有质量。但总的来说,您的代码很漂亮,您的解决方案也很有趣,读起来很舒服。
3.我很同情您,数据丢失总是令人很不愉快,所以可靠的备份是我们的一切。
谢谢您,我们期待着您的新文章。
感谢您提供非常好的教程
我将其修改为深色外观,还想进一步更改标题和数据的颜色。
此外,我还创建了一个函数,可以轻松添加文本
void DrawData(int cell, string title, string data, color clr ) { dashboard.DrawText(title, dashboard.CellX(cell,0)+2, dashboard.CellY(cell,0)+2, clr); dashboard.DrawText(data, dashboard.CellX(cell,1)+2, dashboard.CellY(cell,1)+2,90, clr); ChartRedraw(ChartID()); }
但发现很难改变这些文本的颜色,不知道哪里出了问题,因为颜色看起来很暗淡,下面是修改后的 DrawText 函数
//+------------------------------------------------------------------+ //| 在指定坐标处显示文本信息 //+------------------------------------------------------------------+ void CDashboard::DrawText(const string text,const int x,const int y,const color clr,const int width=WRONG_VALUE,const int height=WRONG_VALUE) { //-- 声明变量以记录文本的宽度和高度 int w=width; int h=height; //--- 如果传递给方法的文本宽度和高度值为零、 //--- 然后使用透明色完全清除整个工作空间 if(width==0 && height==0) this.m_workspace.Erase(0x00FFFFFF); //--- 否则 else { //--- 如果传递的宽度和高度为默认值(-1),我们将从文本中获取其宽度和高度。 if(width==WRONG_VALUE && height==WRONG_VALUE) this.m_workspace.TextSize(text,w,h); //--- 否则、 else { //--- 如果传递给方法的宽度为默认值 (-1) --从文本中获取宽度,或者 //--- 如果传递给方法的宽度值大于零,则使用传递给方法的宽度,或者 //--- 如果传递给方法的宽度值为零,则使用宽度值 1 w=(width ==WRONG_VALUE ? this.m_workspace.TextWidth(text) : width>0 ? width : 1); //--- 如果传递给方法的高度为默认值(-1),则从文本中获取高度,或者 //--- 如果传递给方法的高度值大于零,则使用传递给方法的高度,或者 //--- 如果传递给该方法的高度值为零,则使用高度值 1 h=(height==WRONG_VALUE ? this.m_workspace.TextHeight(text) : height>0 ? height : 1); } //--- 根据指定的坐标和由此产生的宽度和高度,用透明色填充空间(擦除上一条记录) this.m_workspace.FillRectangle(x,y,x+w,y+h,0x00FFFFFF); } //--- 将文本显示到清除了之前文本的空间,并在不重绘屏幕的情况下更新工作空间 this.m_workspace.TextOut(x,y,text,::ColorToARGB(clr,this.m_alpha)); this.m_workspace.Update(false); }
Arpit T # :
//--- 将文本显示到清除了之前文本的空间,并更新工作空间,而无需重绘屏幕 this .m_workspace. TextOut (x,y,text,:: ColorToARGB (clr, this .m_alpha )); this .m_workspace.Update( false );
高亮显示的颜色 是面板本身的透明度,而不是文本的透明度。对于文本,最好将透明度(或者说不透明度)设置为默认值 255 - 文本完全不透明。但您也可以通过输入 0 至 255 之间的常规数值来 "玩弄 "不透明度值,而不是输入this.m_alpha。0 表示完全透明的颜色,255 表示完全不透明的颜色。
高亮显示的颜色 是面板本身的透明度,而不是文本的透明度。对于文本,最好将透明度(或者说不透明度)设置为默认值 255 - 文本完全不透明。但您也可以通过输入 0 至 255 之间的常规数值来 "玩弄 "不透明度值,而不是输入this.m_alpha。0 表示完全透明的颜色,255 表示完全不透明的颜色。
谢谢,现在一切正常了
void DrawData(int cell, string title, string data, color clr ) { dashboard.DrawText(title, dashboard.CellX(cell,0)+2, dashboard.CellY(cell,0)+2, clr); dashboard.DrawText(data, dashboard.CellX(cell,1)+2, dashboard.CellY(cell,1)+2,90, clr); ChartRedraw(ChartID()); }
高亮显示的代码是问题所在,我删除后一切正常。
做得很好,颜色很深
谢谢
如果您想使用该主题,这里是 dashboard.mqh 中经过修改的暗色外观构造函数
//+------------------------------------------------------------------+ //| 构造函数| //+------------------------------------------------------------------+ CDashboard::CDashboard(const uint id,const int x,const int y, const int w,const int h,const int wnd=-1) : m_id(id), m_chart_id(::ChartID()), m_program_type((ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE)), m_program_name(::MQLInfoString(MQL_PROGRAM_NAME)), m_wnd(wnd==-1 ? GetSubWindow() : wnd), m_chart_w((int)::ChartGetInteger(m_chart_id,CHART_WIDTH_IN_PIXELS,m_wnd)), m_chart_h((int)::ChartGetInteger(m_chart_id,CHART_HEIGHT_IN_PIXELS,m_wnd)), m_mouse_state(MOUSE_STATE_NOT_PRESSED), m_x(x), m_y(::ChartGetInteger(m_chart_id,CHART_SHOW_ONE_CLICK) ? (y<79 ? 79 : y) : y), m_w(w), m_h(h), m_x_dock(m_x), m_y_dock(m_y), m_header(true), m_butt_close(true), m_butt_minimize(true), m_butt_pin(true), m_header_h(18), //--- 面板页眉实现 m_header_alpha(255), m_header_alpha_c(m_header_alpha), m_header_back_color(clrBlack), m_header_back_color_c(m_header_back_color), m_header_fore_color(clrSnow), m_header_fore_color_c(m_header_fore_color), m_header_border_color(clrSnow), m_header_border_color_c(m_header_border_color), m_title("Dashboard"), m_title_font("Calibri"), m_title_font_size(-100), //--- 关闭按钮 m_butt_close_back_color(clrBlack), m_butt_close_back_color_c(m_butt_close_back_color), m_butt_close_fore_color(clrSnow), m_butt_close_fore_color_c(m_butt_close_fore_color), //--- 折叠/展开按钮 m_butt_min_back_color(clrBlack), m_butt_min_back_color_c(m_butt_min_back_color), m_butt_min_fore_color(clrSnow), m_butt_min_fore_color_c(m_butt_min_fore_color), //--- 针式按钮 m_butt_pin_back_color(clrBlack), m_butt_pin_back_color_c(m_butt_min_back_color), m_butt_pin_fore_color(clrSnow), m_butt_pin_fore_color_c(m_butt_min_fore_color), //--- 小组实施 m_alpha(255), m_alpha_c(m_alpha), m_fore_alpha(255), m_fore_alpha_c(m_fore_alpha), m_back_color(clrBlack), m_back_color_c(m_back_color), m_fore_color(clrSnow), m_fore_color_c(m_fore_color), m_border_color(clrSnow), m_border_color_c(m_border_color), m_font("Calibri"), m_font_size(-100), m_minimized(false), m_movable(true) { //--- 设置图表发送有关移动和按下鼠标按钮事件信息的权限、 //--- 鼠标滚动事件,以及图形对象的创建/删除 ::ChartSetInteger(this.m_chart_id,CHART_EVENT_MOUSE_MOVE,true); ::ChartSetInteger(this.m_chart_id,CHART_EVENT_MOUSE_WHEEL,true); ::ChartSetInteger(this.m_chart_id,CHART_EVENT_OBJECT_CREATE,true); ::ChartSetInteger(this.m_chart_id,CHART_EVENT_OBJECT_DELETE,true); //--- 设置全局终端变量的名称,以存储面板坐标、折叠/展开状态和固定状态 this.m_name_gv_x=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_X"; this.m_name_gv_y=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Y"; this.m_name_gv_m=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Minimize"; this.m_name_gv_u=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Unpin"; //--- 如果不存在全局变量,则创建该变量并写入当前值、 //--- 否则 - 将终端全局变量的值读入其中 //--- X 坐标 if(!::GlobalVariableCheck(this.m_name_gv_x)) ::GlobalVariableSet(this.m_name_gv_x,this.m_x); else this.m_x=(int)::GlobalVariableGet(this.m_name_gv_x); //--- Y 坐标 if(!::GlobalVariableCheck(this.m_name_gv_y)) ::GlobalVariableSet(this.m_name_gv_y,this.m_y); else this.m_y=(int)::GlobalVariableGet(this.m_name_gv_y); //--- 折叠/展开 if(!::GlobalVariableCheck(this.m_name_gv_m)) ::GlobalVariableSet(this.m_name_gv_m,this.m_minimized); else this.m_minimized=(int)::GlobalVariableGet(this.m_name_gv_m); //-- 折叠/未折叠 if(!::GlobalVariableCheck(this.m_name_gv_u)) ::GlobalVariableSet(this.m_name_gv_u,this.m_movable); else this.m_movable=(int)::GlobalVariableGet(this.m_name_gv_u); //--- 设置面板大小超过图表窗口大小的标志 this.m_higher_wnd=this.HigherWnd(); this.m_wider_wnd=this.WiderWnd(); //--- 如果创建了面板图形资源、 if(this.m_canvas.CreateBitmapLabel(this.m_chart_id,this.m_wnd,"P"+(string)this.m_id,this.m_x,this.m_y,this.m_w,this.m_h,COLOR_FORMAT_ARGB_NORMALIZE)) { //--- 设置画布字体并用透明色填充画布 this.m_canvas.FontSet(this.m_title_font,this.m_title_font_size,FW_BOLD); this.m_canvas.Erase(0x00FFFFFF); } //--- 否则--向日志报告对象创建不成功 else ::PrintFormat("%s: Error. CreateBitmapLabel for canvas failed",(string)__FUNCTION__); //--- 如果创建了图形资源的工作空间、 if(this.m_workspace.CreateBitmapLabel(this.m_chart_id,this.m_wnd,"W"+(string)this.m_id,this.m_x+1,this.m_y+this.m_header_h,this.m_w-2,this.m_h-this.m_header_h-1,COLOR_FORMAT_ARGB_NORMALIZE)) { //--- 为工作区设置字体并填充透明色 this.m_workspace.FontSet(this.m_font,this.m_font_size); this.m_workspace.Erase(0x00FFFFFF); } //--- 否则--向日志报告对象创建不成功 else ::PrintFormat("%s: Error. CreateBitmapLabel for workspace failed",(string)__FUNCTION__); }
您好。
是这样的
CDashboard *dashboard = NULL;
一个指向未来新的、动态创建的类对象的指针变量被声明,并立即以NULL 值初始化。
这样声明的只是类的一个实例:
CDashboard dashboard;
但在这种情况下,你不能用这种方法声明和创建实例--该类没有不带形式参数的构造函数。
因此,在以这种方式声明实例时,必须指定类对象的所有必要参数,这些参数必须传递给类的构造函数:
CDashboard dashboard(InpUniqID, InpPanelX, InpPanelY, 200, 250);
------------------------
在使用类的示例中,首先会在指示器中创建一个指向未来对象的空指针,然后在 OnInit() 中创建一个面板对象,并将指向已创建对象的指针写入指针变量:
//--- Создаём объект панели dashboard=new CDashboard(InpUniqID,InpPanelX,InpPanelY,200,250); if(dashboard==NULL) { Print("Error. Failed to create dashboard object"); return INIT_FAILED; }
然后,在 OnDeinit() 中,使用该指针删除内存中的对象:
//--- Если объект панели существует - удаляем if(dashboard!=NULL) delete dashboard;
如果我们只是通过new 操作符创建了一个新对象,而没有将指向已创建对象的指针写入变量,那么之后就无法删除该对象,这将导致内存泄漏。
因此,简而言之,在文章的示例中
- 声明一个指向未来类对象的变量指针,并将其初始化为NULL 值、
- 创建一个新的类对象,并将其指针写入之前创建的 dashboard 变量中、
- 访问创建的对象时,我们使用指针变量和一个点(dashboard.AnyMethod()
- 工作结束时,通过指针删除动态创建的类对象。
如果立即创建了必要的类(CDashboard dashboard)实例,就不需要指向它的指针了--使用 "point "操作符就可以以同样的方式访问它。工作完成后也不需要删除它--终端子系统会自行删除。但它将是程序中唯一的类实例。
通过动态创建,可以快速创建所需类的新对象,并通过指针对其进行引用。这就是例子中使用动态创建类对象的原因。简化,但未涉及某些要点。
新文章 制作仪表板以显示指标和EA中的数据已发布:
在本文中,我们将创建一个用于指标和EA的仪表板类。这是一个小系列文章中的介绍性文章,其中包含模板以在EA交易中包含和使用标准指标。我将首先创建一个类似于MetaTrader 5数据窗口的面板。
在本文中,我将创建一个可以显示开发人员指定的数据的仪表板。这样的面板将便于在图表上直观地显示数据和进行可视化调试,因为在面板上查看必要的值比在调试器中跟踪它们更方便。我指的是根据某些数据值调试策略的情况。
我将以终端数据窗口原型的形式制作面板,并用相同的数据填充:
图1数据窗口和仪表板
我们的自定义面板将允许我们向其添加任何所需数量的必要数据,对其进行签名,以及显示和更新程序代码的读数。
应该可以用鼠标在图表周围移动面板,将其固定在所需的图表位置,以及折叠/展开它。为了方便在面板上放置数据,可以显示具有指定行数和列数的表格。该表中的数据可以显示在日志中(每个表单元格的X和Y坐标),并通过编程获得,以指示该数据应位于的行和列的索引,或者只需打印坐标并在显示文本和数据时将所需坐标输入到代码中。第一种方法由于其完全自动化而更加方便。面板也将有一个活动的关闭按钮,但我们将其处理委托给控制程序,因为只有程序开发人员才能决定如何对按下关闭按钮做出反应。单击按钮时,将向程序事件处理程序发送一个自定义事件。开发人员可以自行处理。
作者:Artyom Trishkin