(一)List Control控件的使用
新近开发了一个摄像机标定的MFC程序,标定完成后期望将求得的摄像机参数直观地显示到应用程序的界面上来。起初的方案是为每一个参数都建立一个Edit控件,并对每一个控件设定一个控制变量,将该变量与相应参数对应起来。这样做是可行的,但当参数众多时比较繁琐。鉴于此,决定在程序中使用List Control控件,将参数以List的形式呈现在界面上。以下是我在基于对话框的MFC程序中添加List Control控件的步骤。
1.新加ListControl 控件,属性中的style属性页下的View选择Report。并设置其对应的控制变量如:m_ListCtrl。
2.初始化,即设置列。
m_ListCtrl.InsertColumn(0,"参数名"); //插入列
m_ListCtrl.InsertColumn(1,"参数值");
m_ListCtrl.InsertColumn(2,"备注");
CRect rect3;
m_ListCtrl.GetClientRect(rect3); //获得当前客户区信息
m_ListCtrl.SetColumnWidth(0,rect3.Width()/4); //设置列的宽度。
m_ListCtrl.SetColumnWidth(1,rect3.Width()*2/4);
m_ListCtrl.SetColumnWidth(2,rect3.Width()/4);
这部分初始化操作,最好放在对话框类的OnInitDialog()函数里,自动初始化。
3.插入数据
m_ListCtrl.InsertItem(0,"参数1"); //插入第一个数据,即第0条数据。先插入,然后在修改其他的信息。
m_ListCtrl.SetItemText(0,1,"参数1值"); //修改第0条数据的其他信息。
m_ListCtrl.SetItemText(0,2,"无");
SetItemText()函数负责向列表里添加字符串。当需要添加的是非字符串的数据类型时,需要先转换为字符串类型再用SetItemText()完成添加。假设所需要添加的是double类型的浮点数。
double dbl=1.2345678;
char str[16]={0};
sprintf(str, "%lf", dbl);
m_ListCtrl.InsertItem(0,"参数1");
m_ListCtrl.SetItemText(0,1,str); //等价于m_ListCtrl.SetItemText(0,1,“1.2345678”);
需要注意的是用sprintf族函数时,char数组一定要足够大,否则程序运行时会出现错误提示“ Stack around the variable 'str' was corrupted ”,解决方法是把数组改大一些。
4.删除所有数据。有些程序中需要刷新显示数据,如果直接利用上述方法,则会将当前显示数据追加在前一次数据行的后面,造成随着刷新次数的增加数据行线性增加的问题。解决方法是每次在插入数据之前删除已有数据,使用下面语句:
m_ListCtrl.DeleteAllItems();
5.如何设置ListView控件的完全行(Full Row)选项。 这个控件有个地方常常很恼人,那就是在报告视图中选中一行时,它只加亮最左边的一个栏目。解决方法:向ListView控件发送一个VM_SETEXTENDEDLISTVIEWSTYLE消息。
::SendMessage(m_ListCtrl.m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
这条语句可以加在OnInitDialog()函数,也可以加在负责插入数据的代码部分。
(二)MFC中实时显示系统时间
下面给出在基于对话框的MFC应用程序的Edit控件中实时显示系统时间的方法。首先来了解一下几个主要的与定时器有关的函数。
SetTimer()函数表示定义一个定时器。根据定义指定的窗口,在指定的窗口(CWnd)中实现OnTimer事件,这样,就可以响应事件了。
SetTimer有两个函数。一个是全局的函数::SetTimer()
UINT SetTimer( HWND hWnd, // handle of window for timer messages
UINT nIDEvent, // timer identifier
UINT uElapse, // time-out value
TIMERPROC lpTimerFunc // address of timer procedure
);
其中hWnd 是指向CWnd的指针,即处理Timer事件的窗口类。说道窗口类(CWnd),我们有必要来看一下CWnd的继承情况:CWnd有以下子类:CFrameWnd,CDialog,CView,CControlBar等类。这也意味这些类中都可以定义SetTimer事件。
SetTimer()的另外一种定义为:
UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );
nIDEvent:是指设置这个定时器的iD,即身份标志,这样在OnTimer()事件中,才能根据不同的定时器,来做不同的事件响应。这个ID是一个无符号的整型。
nElapse:是指时间延迟。单位是毫秒。这意味着,每隔nElapse毫秒系统调用一次Ontimer()。
void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD): Specifies the address of the application-supplied TimerProc callback function that processes the WM_TIMER messages. If this parameter is NULL, the WM_TIMER messages are placed in the application’s message queue and handled by the CWnd object。意思指:指定应用程序提供的TimerProc回调函数的地址,来处里这个WM_TIMER 事件。如果是NULL,则由定义这个Timer事件的CWnd对象来处理该Timer事件。它将WM_TIMER消息传递给这个对象,通过实现这个对象的OnTimer()事件来处理这个Timer事件。所以,一般情况下,我们将这个值设为NULL,由设置该定时器的对象中的OnTimer()函数来处理这个事件。对于SetTimer()可以在初始化当中添加!
OnTimer()函数是响应用SetTimer()函数设定的时钟发送的时钟消息的,你没设定时钟,就不会有时钟消息,OnTimer()里的语句当然也不会被调用。为类添加WM_TIMER消息响应,会看到类中出现OnTimer(UINT nIDEvent)函数。
KillTimer()同SetTimer()一样,它也有两个,一个是全局的::KillTimer(),另一个是CWnd的一个函数。声明如下:
//全局函数
BOOL KillTimer( HWND hWnd, // handle of window that installed timer
UINT uIDEvent // timer identifier
);
//CWnd函数
BOOL KillTimer( int nIDEvent );
这两个函数表示的意思是将ID为nIDEVENT的定时器移走,使其不再作用。其用法如同SetTimer()一样。一般将KillTimer()语句放在需要移去定时器的地方或程序退出是的窗口销毁过程中。
在基于对话框的MFC应用程序中,添加一个Edit控件,ID标号为IDC_EDIT_TIME。
在OnInitDialog()函数中添加下面语句:
SetTimer(1,1000,NULL);//1000毫秒发生一次定时器事件
为类添加WM_TIMER消息响应函数OnTimer(UINT_PTR nIDEvent):
void CTestDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CDialog::OnTimer(nIDEvent);
CString str;
CTime theTime = CTime::GetCurrentTime();
str.Format("%02d:%02d:%02d",theTime.GetHour(),theTime.GetMinute(),theTime.GetSecond());
SetDlgItemText(IDC_EDIT_TIME,str);
}
为类添加WM_DESTROY消息响应函数OnDestroy():
void CTestDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
KillTimer(1);
}