这样的一个问题:界面上一组(一堆)静态控件,比如模拟控制器上许多按钮,当某个信号来时,一些设置为红色(故障),当另一个信号来时,一些设置为绿色(正常),使用了CLabel类,在http://www.codeproject.com/KB/static/clabel.aspx上下载,因为它可以直观设置【背景色】。
因为是“一组按钮”(不是一个),程序应该用循环的方式来遍历“每一个按钮”,而不是直接去直观的“按钮2设置颜色、按钮2设置颜色,。。。。按钮N设置颜色”。第一次我选用了循环遍历控件ID下标方式,以下程序是选择了两个静态控件做例子:
使用VC创建一个基于对话框的程序,上面添加两个静态文本框(IDC_STATIC01、IDC_STATIC02)和一个按钮,两个静态文本框分别关联CLabel类:
在头文件中:
CLabel m1;
CLabel m2;
在实现cpp文件初始化函数OnInitDialog中:
m1.SubclassDlgItem(IDC_STATIC01,this);
m2.SubclassDlgItem(IDC_STATIC02,this);
在cpp实现文件中,写一个让它闪烁的函数:
//
// 奇数时为红色,偶数时为绿色
//
void CTest2Dlg::SetColors(int x)
{
int i;
for (i=IDC_STATIC01; i<=IDC_STATIC02;i++)
{
if(x%2)
{
CLabel *p = ((CLabel *)GetDlgItem(i));
p->SetBkColor(RGB(0, 255, 0));
}
else
{
CLabel *p = ((CLabel *)GetDlgItem(i));
p->SetBkColor(RGB(255, 0, 0));
}
}
}
这个成员函数,大家可以使用按钮事件来调用它,一切都是正常(闪烁)的:
void CTest2Dlg::OnOK()
{
static y=0;
SetColors(y++);
}
也可以使用SetTimer调用,也是正常闪烁的:
void CTest2Dlg::OnOK()
{
SetTimer(1, 100, 0);
}
void CTest2Dlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
static int x=0;
SetColors(x++);
CDialog::OnTimer(nIDEvent);
}
但是这样就不正常了:在按钮事件中创建一个线程MyControllingFunction,在线程函数中调用SetColors:
void CTest2Dlg::OnOK()
{
AfxBeginThread(MyControllingFunction, this);
}
UINT MyControllingFunction( LPVOID pParam )
{
CTest2Dlg *p = (CTest2Dlg *)pParam;
int x = 0;
while(1)
{
Sleep(100);
p->SetColors(x++);
}
return 1L;
}
报错:MFC42D!CFrameWnd::'RTTI Base Class Descriptor at .........,分别将线程函数设置为静态类成员函数和友元函数,问题依旧,百思不得其解!
好像是
CLabel *p = ((CLabel *)GetDlgItem(i));
转换类型时失败,但是为何在按钮事件(或者时钟触发事件)中直接调用,又不失败呢?
最后的解决办法:不使用控件ID下标循环:
定义时:
CLabel m[2];
关联时:
for (int i=0; i<2; i++)
{
m[i].SubclassDlgItem(IDC_STATIC01+i,this);
}
设置闪烁颜色时:
void CTest2Dlg::SetColors(int x)
{
int i;
for (i=0; i<=2;i++)
{
if(x%2)
{
m[i].SetBkColor(RGB(0, 255, 0));
}
else
{
m[i].SetBkColor(RGB(255, 0, 0));
}
}
}
因为起到了同样的遍历静态控件的效果,只好暂时到此为止。
观察CLabel的源码,没看出什么问题,并且自己也尝试写过一个CColorStatic类(只是实现设置背景颜色),在http://blog.youkuaiyun.com/dijkstar/article/details/7184752,用第一方式调用(线程函数循环ID下标),是正常的!更加百思不得其解,先到此。