在写一个算法的时候,希望能够看到计算过程中数据的实时变化,本以为很简单,就拖了一个文本框用来显示循环次数,没想到事与愿违,文本框中的数据并不是动态的变化,而是在计算完成后才一次冒出来,如下例如示,这个小小的问题难了我一整天,现在终于解决,并总结了数据实时显示的一些方法。
一个示例:
for (int i=0;i<10000000;i++)
{
m_curPos=i;
itoa(m_curPos,temp,10);
m_edit.SetWindowText(temp);
}
在上例中,整个循环结束后,程序才将控制权交给窗口,窗口控件才能刷新。解决方法有以下几种:
1.使用定时器:
先设定定时器:this->SetTimer ( 1, 0.1, NULL ) ;然后在对话框中添加OnTimer消息,这样文本框中的数据就可以动态变化了。
void CTestDlg::OnButton1()
{
this->SetTimer ( 1, 0.1, NULL ) ;
}
void CTestDlg::OnTimer(UINT nIDEvent)
{
m_curPos++;
char temp[20];
itoa(m_curPos,temp,10);
m_edit.SetWindowText(temp);
UpdateData(false);
CDialog::OnTimer(nIDEvent);
}
2.使用多线程
void CTestDlg::OnButton3() //¶àÏ̷߳½Ê½
{
CWinThread* pThread;
pThread=AfxBeginThread(ThreadProc,this);//¸Ã²ÎÊý¿ÉÓÃÀ´ÏòÉÏÃ溯Êý´«µÝ
}
static UINT ThreadProc(LPVOID lpParam)//²ÎÊýlpParamÓÃÀ´´«µÝ£¬¿ÉÁé»îÔËÓÃ
{
CTestDlg *dlg=(CTestDlg *)lpParam;
char temp[30];
while (dlg->m_curPos<100000)
{
dlg->m_curPos=dlg->m_curPos+1;
itoa(dlg->m_curPos,temp,10);
dlg->m_edit.SetWindowText(temp);
}
return 0;
}
但是,有时候这两种方法并不能达到我们的要求,方法1必须将计算过程写在OnTimer函数中,若将m_curPos写在OnTimer函数外部变化,仍不能动态更新,而有时候计算过程不能写在OnTimer函数中,而且文本框中数据的变化时间间隔是事先设定好的,与计算并不是同步的,有违实时性。方法2类似,必须将变量的计算过程写在ThreadProc中,与法1的区别是可与计算过程同步更新。
3.用设备管理器DC来更新文本
这次不用文本框来显示数据,而是直接在对话框界面上绘制,可达到目的。
void CTestDlg::OnButton2() //DC·½Ê½
{
char temp[20];
CDC* dc=this->GetDC();
for (int i=0;i<1000000;i++)
{
m_curPos=i;
itoa(m_curPos,temp,10);
dc->TextOut(20,20,CString(temp));
UpdateData(false);
}
}
4.用Static控件来显示
void CTestDlg::OnButton4()
{
// TODO: Add your control notification handler code here
char temp[20];
CDC* dc=this->GetDC();
for (int i=0;i<10000000;i++)
{
m_curPos=i;
itoa(m_curPos,temp,10);
m_staticValue=CString(temp);
m_staticControl.SetWindowText(temp);
UpdateData(false);
}
}
不知为什么Edit控件如此不能实时更新,而Static控件却可以。但此法与法3也是有缺陷的:计算过程中,如果程序焦点变化,如处理其它事情,数据将停止变化,甚至整个程序出现假死状态,一片空白,但实际仍在运行,就是不能动态刷新了。
5.使用DoEvent()或者使用SendMessage强制向窗口发送刷新消息
void CTestDlg::OnButton4()
{
// TODO: Add your control notification handler code here
char temp[20];
CDC* dc=this->GetDC();
for (int i=0;i<10000000;i++)
{
m_curPos=i;
itoa(m_curPos,temp,10);
m_edit.SetWindowText(temp);m_editValue=m_curPos;
UpdateData(false);
GetDlgItem(IDC_EDIT2)->SendMessage(WM_PAINT);
// DoEvent(); //暂时转出去处理一下系统消息
}
}
void DoEvent()
{
MSG msg;
while (PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE) )//ÅжÏÊÇ·ñÓÐÏûÏ¢
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
使用SendMessage方法和法3.4存在相同的问题,即焦点变化时,出现假死状态,经检验,使用DoEvent方法是最完美的办法。
总结:
此问题实际上是实时绘制和刷新的问题,在做实时数据采集显示,科学计算过程显示时会遇到,有时还需要绘制实时的图形,这时,就要求计算过程与显示同步更新,以上方法可在小程序中使用,若在大型实时系统中,可能最终还是会用多线程技术,虽然法2也用了多线程,但解决并不完美,望高手指正。