监视多币种的交易信号(第三部分):引入搜索算法·进阶篇
(2/3)· 当品种和信号堆到几十个,手工翻看就是漏单之源,这篇把保存集与搜索逻辑一次讲透
「信号集存盘与读取的结构细节」
保存信号集时,边框颜色仅在第二个参数按钮被按下时才写入当前色板第三号颜色,否则直接置为 clrNONE;背景色则始终清空为 clrNONE。这种写法意味着界面状态与配置文件严格一一对应,手动改面板不点按就不会落盘。 时间段写入用了一个 0 到 20 的 21 次循环,遍历全部周期按钮。若按钮未锁定且处于按下态,就把对应 timeframes[i] 标 true 并拷贝按钮标签文本,同时 tf 计数加一;否则写 false。 若循环结束 tf 仍小于 1,弹窗“No timeframes selected”并关闭文件返回 false,说明至少选一个周期才能存成功。该检查直接拦在 FileWriteStruct 之前。 读取侧用 FileOpen 以 FILE_READ|FILE_BIN 打开 Signal Monitor\signal_*.bin,句柄无效就报“Configuration not found”。随后 ZeroMemory 清空结构体再 FileReadStruct 载入,接着把 ind_type、ind_period、app_price、rule_type 依次推回界面控件并 Update(true),实现面板复原。
m_signal_set[index].back_color=clrNONE; class=class="str">"cmt">//--- Border class="type">color if(m_set_param[class="num">1].IsPressed()) m_signal_set[index].border_color=m_color_button[class="num">2].CurrentColor(); else m_signal_set[index].border_color=clrNONE; class=class="str">"cmt">//--- Tooltip value m_signal_set[index].tooltip=m_set_param[class="num">2].IsPressed(); if(m_signal_set[index].tooltip) StringToCharArray(m_tooltip_text.GetValue(),m_signal_set[index].tooltip_text); class=class="str">"cmt">//--- Selected image m_signal_set[index].image=m_set_param[class="num">3].IsPressed(); if(m_signal_set[index].image) m_signal_set[index].img_index=m_pictures_slider.GetRadioButtonsPointer().SelectedButtonIndex(); class=class="str">"cmt">//--- Selected timegrames class="type">int tf=class="num">0; for(class="type">int i=class="num">0; i<class="num">21; i++) { if(!m_tf_button[i].IsLocked() && m_tf_button[i].IsPressed()) { m_signal_set[index].timeframes[i]=true; StringToCharArray(m_tf_button[i].LabelText(),m_signal_set[index].tf_name[i].tf); tf++; } else m_signal_set[index].timeframes[i]=false; } class=class="str">"cmt">//--- if(tf<class="num">1) { MessageBox("No timeframes selected","Signal Monitor"); FileClose(h); class="kw">return(false); } class=class="str">"cmt">//--- FileWriteStruct(h,m_signal_set[index]); FileClose(h); Print("Configuration signal_"+class="type">class="kw">string(index)+" has been successfully saved"); class=class="str">"cmt">//--- class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CProgram::LoadSignalSet(class="type">int index) { class="type">int h=FileOpen("Signal Monitor\\signal_"+class="type">class="kw">string(index)+".bin",FILE_READ|FILE_BIN); if(h==INVALID_HANDLE) { MessageBox("Configuration not found","Signal Monitor"); class="kw">return(false); } ZeroMemory(m_signal_set[index]); FileReadStruct(h,m_signal_set[index]); class=class="str">"cmt">//--- Loading indicator type m_indicator_type.SelectItem(m_signal_set[index].ind_type); RebuildParameters(m_signal_set[index].ind_type); m_indicator_type.GetButtonPointer().Update(true); class=class="str">"cmt">//--- Loading indicator period m_period_edit.SetValue((class="type">class="kw">string)m_signal_set[index].ind_period); m_period_edit.GetTextBoxPointer().Update(true); class=class="str">"cmt">//--- Loading applied price if(!m_applied_price.IsLocked()) { m_applied_price.SelectItem(m_signal_set[index].app_price); m_applied_price.GetButtonPointer().Update(true); } class=class="str">"cmt">//--- Loading signal rule m_rule_type.SelectItem(m_signal_set[index].rule_type);
信号集回填界面控件的判定分支
这段逻辑干的是把已保存的 signal_set 某一条记录,原样灌回面板控件。rule_type 和 rule_value 先刷新,文本用 (string) 强转,保证枚举或数值都能落进文本框。 label_type==0 走预设标签分支:button[0] 按下、button[1] 弹起,文本框锁死不可编辑;非 0 则反过来,文本框解锁并清空后用 CharArrayToString 把 label_value 字符数组转成可见文字,注意这里用的是索引 0 的 AddText,多行缓冲若没清干净可能叠字。 颜色与开关是三套平行判断:文字色直接赋值;背景色和边框色若等于 clrNONE,对应 set_param 不按、颜色按钮锁住,否则解锁并 CurrentColor 写入。tooltip 为假时锁定提示框,为真才放开——这套 0/非0 与 clrNONE 双基准,决定了面板“只读”还是“可改”的状态机。 开 MT5 把这段塞进你的 CAppDialog 派生类,断点看 m_signal_set[index] 各字段,能直接验证 label_type 切到 1 时文本框是否如约解锁。外汇与贵金属 GUI 回测无收益含义,界面状态错乱只会影响人工判单效率,实盘前务必手点一遍三种颜色开关。
m_rule_type.GetButtonPointer().Update(true); m_rule_value.SetValue((class="type">class="kw">string)m_signal_set[index].rule_value); m_rule_value.GetTextBoxPointer().Update(true); class=class="str">"cmt">//--- Loading a text label if(m_signal_set[index].label_type==class="num">0) { m_label_button[class="num">0].IsPressed(true); m_label_button[class="num">0].Update(true); m_label_button[class="num">1].IsPressed(false); m_label_button[class="num">1].Update(true); m_text_box.IsLocked(true); } else { m_label_button[class="num">0].IsPressed(false); m_label_button[class="num">0].Update(true); m_label_button[class="num">1].IsPressed(true); m_label_button[class="num">1].Update(true); m_text_box.IsLocked(false); m_text_box.ClearTextBox(); m_text_box.AddText(class="num">0,CharArrayToString(m_signal_set[index].label_value)); m_text_box.Update(true); } class=class="str">"cmt">//--- Loading the class="type">color of the text label m_color_button[class="num">0].CurrentColor(m_signal_set[index].label_color); m_color_button[class="num">0].Update(true); class=class="str">"cmt">//--- Loading the background class="type">color if(m_signal_set[index].back_color==clrNONE) { m_set_param[class="num">0].IsPressed(false); m_set_param[class="num">0].Update(true); m_color_button[class="num">1].IsLocked(true); m_color_button[class="num">1].GetButtonPointer().Update(true); } else { m_set_param[class="num">0].IsPressed(true); m_set_param[class="num">0].Update(true); m_color_button[class="num">1].IsLocked(false); m_color_button[class="num">1].CurrentColor(m_signal_set[index].back_color); m_color_button[class="num">1].GetButtonPointer().Update(true); } class=class="str">"cmt">//--- Loading the border class="type">color if(m_signal_set[index].border_color==clrNONE) { m_set_param[class="num">1].IsPressed(false); m_set_param[class="num">1].Update(true); m_color_button[class="num">2].IsLocked(true); m_color_button[class="num">2].GetButtonPointer().Update(true); } else { m_set_param[class="num">1].IsPressed(true); m_set_param[class="num">1].Update(true); m_color_button[class="num">2].IsLocked(false); m_color_button[class="num">2].CurrentColor(m_signal_set[index].border_color); m_color_button[class="num">2].GetButtonPointer().Update(true); } class=class="str">"cmt">//--- Loading the tooltip value if(!m_signal_set[index].tooltip) { m_set_param[class="num">2].IsPressed(false); m_set_param[class="num">2].Update(true); m_tooltip_text.IsLocked(true); m_tooltip_text.Update(true); } else { m_set_param[class="num">2].IsPressed(true);
◍ 信号编辑器面板的回灌与按钮构造
从文件载入信号配置时,代码先把第 2 号参数控件的选中态刷新为 true,并解锁提示文本框、清空后写入对应信号的 tooltip 字符串。若当前信号不带图像(m_signal_set[index].image 为假),第 3 号参数按钮置为非按下、图片滑块锁定;反之则按下该按钮、解锁滑块并按 img_index 选中对应单选钮。 时间框架的回灌用了一个 0 到 20 的循环,共 21 个周期按钮——只要某按钮未被锁定,就按其 timeframes[i] 布尔值设按下态并刷新。注意循环上限写死 21,若你后期扩到 28 个周期(含 Year),不改为 i<28 就会漏载后 7 个。 文件句柄在尾部统一 FileClose(h) 并返回 true,说明载入流程无论界面元素多少都走一次性批刷新,而非增量重绘。 下方 CreateSignalEditor 负责生成带图标的编辑器按钮:尺寸固定 110×30,图标左距 3、上距 7,底色 C'70,180,70'、按下态 C'70,170,70',文字白色居中。它依赖 #resource 预编译指令把 settings_light.bmp 打进 ex5,路径为 Images\EasyAndFastGUI\Icons\bmp16\。改按钮宽度时记得同步 XSize 与图标间隙,否则 MT5 上可能文字被图标挤掉。 外汇与贵金属信号面板涉及高频参数切换,界面逻辑错误可能引发行情误读,实盘前务必在策略测试器里跑一遍载入回灌。
m_set_param[class="num">2].Update(true); m_tooltip_text.IsLocked(false); m_tooltip_text.ClearTextBox(); m_tooltip_text.AddText(class="num">0,CharArrayToString(m_signal_set[index].tooltip_text)); m_tooltip_text.Update(true); } class=class="str">"cmt">//--- Loading the image if(!m_signal_set[index].image) { m_set_param[class="num">3].IsPressed(false); m_set_param[class="num">3].Update(true); m_pictures_slider.IsLocked(true); m_pictures_slider.GetRadioButtonsPointer().Update(true); } else { m_set_param[class="num">3].IsPressed(true); m_set_param[class="num">3].Update(true); m_pictures_slider.IsLocked(false); m_pictures_slider.GetRadioButtonsPointer().SelectButton(m_signal_set[index].img_index); m_pictures_slider.GetRadioButtonsPointer().Update(true); } class=class="str">"cmt">//--- Loading selected timeframes for(class="type">int i=class="num">0; i<class="num">21; i++) { if(!m_tf_button[i].IsLocked()) { m_tf_button[i].IsPressed(m_signal_set[index].timeframes[i]); m_tf_button[i].Update(true); } } class=class="str">"cmt">//--- FileClose(h); class="kw">return(true); } CButton m_signal_editor[class="num">5]; class="type">bool CreateSignalEditor(CButton &button,class="type">class="kw">string text,class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap); class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Creates a button with an image | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\settings_light.bmp" class="type">bool CProgram::CreateSignalEditor(CButton &button,class="type">class="kw">string text,class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap) { class=class="str">"cmt">//--- class="type">color baseclr=C&class="macro">#x27;class="num">70,class="num">180,class="num">70&class="macro">#x27;; class="type">color pressed=C&class="macro">#x27;class="num">70,class="num">170,class="num">70&class="macro">#x27;; class=class="str">"cmt">//--- Save the window pointer button.MainPointer(m_step_window); class=class="str">"cmt">//--- Set up properties before creation button.XSize(class="num">110); button.YSize(class="num">30); button.Font(m_base_font); button.FontSize(m_base_font_size); button.IconXGap(class="num">3); button.IconYGap(class="num">7); button.IconFile("Images\\EasyAndFastGUI\\Icons\\bmp16\\settings_light.bmp"); button.BackColor(baseclr); button.BackColorHover(baseclr); button.BackColorPressed(pressed); button.BorderColor(baseclr); button.BorderColorHover(baseclr); button.BorderColorPressed(pressed); button.LabelColor(clrWhite); button.LabelColorPressed(clrWhite); button.LabelColorHover(clrWhite); button.IsCenterText(true); class=class="str">"cmt">//--- Create the control if(!button.CreateButton(text,x_gap,y_gap)) class="kw">return(false); class=class="str">"cmt">//--- Add the element pointer to the base CWndContainer::AddToElementsArray(class="num">0,button); class="kw">return(true); } class=class="str">"cmt">//---
「信号编辑器与 GUI 初始化的循环写法」
这段逻辑里,信号编辑器数组按固定上限 5 个做批量处理。循环从 i=0 到 i<5,每次尝试创建名为 Signal_0 到 Signal_4 的编辑器,纵向坐标用 40*i+90 算,也就是 90、130、170、210、250 像素——改这个步进值就能调编辑器间距。 CreateGUI 里先建三步窗口(选品种、编辑信号、拾色器),最后把 m_back_button、m_add_signal、m_signal_header 全隐藏,并默认按下 m_label_button[1]。末尾那段高亮循环把 5 个 m_signal_editor 一次性 Hide,说明初始状态不暴露编辑器界面。 ClearSaves 走的是文件级清理:对 i=0..4 调 FileDelete 删掉 Signal Monitor\\signal_i.bin,再把 m_total_signals 归零。想验证就开 MT5 把循环上限从 5 改成 3,看编辑器实例和 bin 文件是否同步减少。 事件分支里,点 m_add_signal 会开设置窗并标“Add”;点某个 m_signal_editor[i] 则 LoadSignalSet(i) 后标“Save”并把 m_number_signal 记成 i——这就是后面存读配置的索引来源。
for(class="type">int i=class="num">0; i<class="num">5; i++) { if(!CreateSignalEditor(m_signal_editor[i],"Signal_"+class="type">class="kw">string(i),class="num">10,class="num">40*i+class="num">90)) class="kw">return(false); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Creates the graphical interface of the program | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CProgram::CreateGUI(class="type">void) { class=class="str">"cmt">//--- Step class="num">1-class="num">3. Symbol selection window. if(!CreateStepWindow("Signal Monitor Step class="num">1: Choose Symbols")) class="kw">return(false); class=class="str">"cmt">//--- if(!CreateSetWindow("Signal Monitor Edit Signal")) class="kw">return(false); class=class="str">"cmt">//--- Creating form class="num">2 for the class="type">color picker if(!CreateColorWindow("Color Picker")) class="kw">return(false); class=class="str">"cmt">//--- Finishing the creation of GUI CWndEvents::CompletedGUI(); m_back_button.Hide(); m_add_signal.Hide(); m_signal_header.Hide(); m_label_button[class="num">1].IsPressed(true); m_label_button[class="num">1].Update(true); for(class="type">int i=class="num">0; i<class="num">5; i++) m_signal_editor[i].Hide(); class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CProgram::ClearSaves(class="type">void) { for(class="type">int i=class="num">0; i<class="num">5; i++) FileDelete("Signal Monitor\\signal_"+class="type">class="kw">string(i)+".bin"); m_total_signals=class="num">0; class="kw">return(true); } class=class="str">"cmt">//--- Add Signal button click event if(lparam==m_add_signal.Id()) { m_set_window.OpenWindow(); m_number_signal=-class="num">1; RebuildTimeframes(); m_new_signal.LabelText("Add"); m_new_signal.Update(true); } class=class="str">"cmt">//--- for(class="type">int i=class="num">0; i<class="num">5; i++) { if(lparam==m_signal_editor[i].Id()) { LoadSignalSet(i); m_new_signal.LabelText("Save"); m_new_signal.Update(true); m_set_window.OpenWindow(); m_number_signal=i; } }
把信号搜索接进监视器
表格视图已经铺好:行是第一步挑的品种,列是第二步挑的时间帧。点 Create 之后 ToMonitor() 被调用,这一步要把编辑信号的按钮全隐藏掉,和第三步那些控件一样处理,否则跳到监视窗口时界面会叠层。 隐藏动作直接复用按钮对象的状态切换。下面这段是 StepWindow 里收尾隐藏的典型写法,循环里把 5 个编辑槽位逐个 Hide: 标示模块(indication block)用 CButton 数组承载,CreateSignalButton() 负责按坐标生成单个模块。尺寸固定为 40×20,双线边框,底色 C'220,225,235',标签左偏 19 像素——这些硬参数决定了监视器里信号格的视觉密度,想加密行列就得回来改 XSize / YSize。 SearchSignal() 是核心:先读连接信号设置的文件,拿到已配置信号总数,再按表格索引判断每个标示模块对应哪个品种+时间帧。CheckTimeframe() 做过滤器,不在选定时间帧内的直接跳过。命中后按信号配置给模块染色。 要让它自己跑,得在 SignalMonitor.mq5 开头加一个刷新间隔枚举,初始化里算好下次更新时间,OnTick() 里做时间差判断。编译后建一组品种挂个信号就能看到监视器活起来。外汇和贵金属波动剧烈,这类自动标信号只是辅助提示,信号出现不代表方向确定性,实盘仍需自担高风险。
<span class="comment">class=class="str">"cmt">//--- Hide Step class="num">3</span> m_add_signal.Hide(); m_signal_header.Hide(); m_back_button.Hide(); m_next_button.Hide(); <span style="background-class="type">color:rgb(class="num">255, class="num">235, class="num">85);"><span class="keyword">for</span>(<span class="keyword">class="type">int</span> i=<span class="number">class="num">0</span>; i<<span class="number">class="num">5</span>; i++) m_signal_editor[i].Hide();</span> <span class="keyword">class="type">bool</span> CreateSignalButton(CButton &button,<span class="keyword">class="kw">const</span> <span class="keyword">class="type">int</span> x_gap,<span class="keyword">class="kw">const</span> <span class="keyword">class="type">int</span> y_gap); CButton m_signal_button[]; <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="comment">class=class="str">"cmt">//| Creates an indication block |</span> <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="keyword">class="type">bool</span> CProgram::CreateSignalButton(CButton &button,<span class="keyword">class="kw">const</span> <span class="keyword">class="type">int</span> x_gap,<span class="keyword">class="kw">const</span> <span class="keyword">class="type">int</span> y_gap) { <span class="comment">class=class="str">"cmt">//---</span> <span class="keyword">class="type">color</span> baseclr=<span class="class="type">class="kw">string">C&class="macro">#x27;class="num">220,class="num">225,class="num">235&class="macro">#x27;</span>; <span class="comment">class=class="str">"cmt">//--- Save the window pointer</span> button.MainPointer(m_step_window); <span class="comment">class=class="str">"cmt">//--- Set up properties before creation</span> button.TwoState(<span class="macro">false</span>); button.XSize(<span class="number">class="num">40</span>); button.YSize(<span class="number">class="num">20</span>); button.IconXGap(<span class="number">class="num">2</span>); button.IconYGap(button.YSize()/<span class="number">class="num">2</span>-<span class="number">class="num">8</span>); button.LabelXGap(<span class="number">class="num">19</span>); button.LabelYGap(<span class="number">class="num">2</span>); button.FontSize(m_base_font_size); button.BackColor(baseclr); button.BackColorHover(baseclr); button.BackColorPressed(baseclr); button.BorderColor(baseclr); button.BorderColorHover(baseclr); button.BorderColorPressed(baseclr); button.LabelColor(<span class="macro">clrBlack</span>); button.LabelColorPressed(<span class="macro">clrSlateGray</span>); button.IconFile(<span class="class="type">class="kw">string">""</span>); button.IconFileLocked(<span class="class="type">class="kw">string">""</span>); button.IsDoubleBorder(<span class="macro">true</span>); <span class="comment">class=class="str">"cmt">//--- Create the control</span> <span class="keyword">if</span>(!button.CreateButton(<span class="class="type">class="kw">string">""</span>,x_gap-button.XSize()/<span class="number">class="num">2</span>,y_gap)) <span class="keyword">class="kw">return</span>(<span class="macro">false</span>); <span class="comment">class=class="str">"cmt">//--- Add the element pointer to the base</span> CWndContainer::AddToElementsArray(<span class="number">class="num">0</span>,button); <span class="keyword">class="kw">return</span>(<span class="macro">true</span>); } <span class="comment">class=class="str">"cmt">//--- Timeframes</span> <span class="keyword">class="type">int</span> tf=<span class="functions">ArraySize</span>(m_timeframes); <span class="functions">ArrayResize</span>(m_timeframe_label,tf); <span class="comment">class=class="str">"cmt">//---</span> <span class="keyword">for</span>(<span class="keyword">class="type">int</span> i=<span class="number">class="num">0</span>; i<tf; i++) {
◍ 信号面板的按钮布局与配色接口
信号区块的绘制用两层循环铺开:外层按交易品种行数 sy 走,内层按周期数 tf 走,每个格子生成一个信号按钮。按钮横坐标取对应周期标签的中心点(XGap 加 XSize 的一半),纵坐标从窗口标题栏下 25 像素起,每行再叠 25 像素,因此总行高固定为 25*j,布局密度直接由 sy 和 tf 的乘积决定。 数组 m_signal_button 先用 ArrayResize(m_signal_button, sy*tf) 一次性扩到 sy*tf 个,k 从 0 累加穿透两层循环,保证不越界。窗口尺寸最后靠 AutoResize 收口,右边界取最后一个周期标签的右沿加 5,下边界取最后一个品种标签的下沿加 5,这套算法在 4 周期 × 8 品种下会生成 32 个按钮对象。 SetBorderColor、SetLabel、SetBackground 三个方法都针对 m_signal_button[index] 同时改常态、悬停、按下三态属性然后 Update(true)。比如 SetBackground 只动 BackColor 和 BackColorHover,没有 Pressed 态——意味着按钮被按住时背景不会变,如果你要做按压反馈得自己补一行 BorderColorPressed 之外的 BackColorPressed。 外汇与贵金属市场杠杆高、滑点随机,这类面板只是信号可视化辅助,任何颜色标记都不构成方向建议,实盘前请在 MT5 策略测试器里把 sy、tf 改小先验证对象数是否爆栈。
if(!CreateTimeframeLabel(m_timeframe_label[i],class="num">110+class="num">50*i,m_step_window.CaptionHeight()+class="num">3,m_timeframes[i])) class="kw">return; m_timeframe_label[i].Update(true); } class=class="str">"cmt">//-- Signal blocks class="type">int k=class="num">0; ArrayResize(m_signal_button,sy*tf); for(class="type">int j=class="num">0; j<sy; j++) { for(class="type">int i=class="num">0; i<tf; i++) { if(!CreateSignalButton(m_signal_button[k],m_timeframe_label[i].XGap()+m_timeframe_label[i].XSize()/class="num">2,m_step_window.CaptionHeight()+class="num">25+j*class="num">25)) class="kw">return; m_signal_button[k].Update(true); k++; } } class=class="str">"cmt">//--- Resize window AutoResize(m_timeframe_label[tf-class="num">1].XGap()+m_timeframe_label[tf-class="num">1].XSize()+class="num">5,m_symbol_label[sy-class="num">1].YGap()+m_symbol_label[sy-class="num">1].YSize()+class="num">5); class="type">void SetBorderColor(class="type">int index, class="type">color clr); class="type">void SetLabel(class="type">int index, class="type">class="kw">string text,class="type">color clr=clrBlack); class="type">void SetIcon(class="type">int index,class="type">int number); class="type">void SetBackground(class="type">int index,class="type">color clr); class="type">void SetTooltip(class="type">int index,class="type">class="kw">string text="\n"); class="type">void CProgram::SetBorderColor(class="type">int index, class="type">color clr) { m_signal_button[index].BorderColor(clr); m_signal_button[index].BorderColorHover(clr); m_signal_button[index].BorderColorPressed(clr); m_signal_button[index].Update(true); } class="type">void CProgram::SetLabel(class="type">int index, class="type">class="kw">string text,class="type">color clr=clrBlack) { m_signal_button[index].LabelColor(clr); m_signal_button[index].LabelColorHover(clr); m_signal_button[index].LabelColorPressed(clr); m_signal_button[index].LabelText(text); m_signal_button[index].Update(true); } class="type">void CProgram::SetBackground(class="type">int index,class="type">color clr) { m_signal_button[index].BackColor(clr); m_signal_button[index].BackColorHover(clr); m_signal_button[index].Update(true); }