控件内容更新 之 DrawText UpdateData SetWindowText

以一个显示用户通话时长的界面为例,要在一个static控件上绘制“通话时长:XX:XX:XX”

关于绘制,可以使用获得到控件的句柄和CDC,通过 DrawText 绘制,也可以通过API函数UpdateData 或 SetWindowText 进行更新。

关于计时,可以通过线程来计时也可以通过利用计时器来计时。

下面,按照绘制方式的不同来进行比较,看哪个最方便啦~

 

方法一: DrawText + 线程计时

这无疑是最笨的一种方法啦...

代码:

//变量

CDC* pDCStatic;//static控件的CDC

BOOL bIintState;//是否初始化完毕(对WM_SIZE的处理必须是在初始化完毕后,否则出错)

BOOL bOnLine;//线程运行控制符

DWORD dwStartTime;//用来记录通话起始时间  在需要开始计时的地方通过 GetTickCount()获得

HANDLE hUpdateEvent;//用于线程同步的Event
CWinThread* pThreadUpdate;//计时线程句柄


static UINT CALLBACK PaintWindow(LPVOID lParam);//计时线程

void GetTimeSpace(DWORD dwStartTime,CString & szTime);//用来得到时长的CString形态

 

//对话框初始化函数 

BOOL C****Dlg::OnInitDialog()
{
 CDialog::OnInitDialog();
 
 // TODO: Add extra initialization here
 this->pDCStatic = NULL;

 this->bOnLine = TRUE;

//创建线程同步事件
 this->hUpdateEvent = CreateEvent(NULL, TRUE, FALSE, "UpdateEvent") ;
//创建计时线程
 this->pThreadUpdate=new CWinThread;
 this->pThreadUpdate->m_bAutoDelete=true;
 this->pThreadUpdate=AfxBeginThread(AFX_THREADPROC(PaintWindow),this,THREAD_PRIORITY_NORMAL,0,0,NULL);

//初始化结束置位

 this->bIintState = FALSE;

 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}

//窗口WM_SIZE响应函数
void C****Dlg::OnSize(UINT nType, int cx, int cy)
{
 CDialog::OnSize(nType, cx, cy);
 
 // TODO: Add your message handler code here
 if(!this->bIintState)
 {  

  CRect rcOnLine;

//获取当前窗口的客户区大小
  GetClientRect(&rcOnLine);

  CWnd*  hStatic = GetDlgItem(IDC_TIME);
  this->pDCStatic = hStatic->GetDC();

//得到在static上绘字的大小,以便于决定static控件位置和大小

  CSize font = this->pDCStatic->GetTextExtent("你");

//和客户区同宽,起点在客户区的1/4处,高位字高的3倍
  this->rcAllText = this->rcOnLine;
  this->rcAllText.top += this->rcOnLine.Height()/4;
  this->rcAllText.bottom = this->rcAllText.top+(font.cy*3);

//挪动static控件

  hStatic->MoveWindow( &this->rcAllText, TRUE ); 
 }
}

//计时线程 

UINT C****Dlg::PaintWindow(LPVOID lParam)
{
 C****Dlg * vnol = (C****Dlg*)lParam;

 while(vnol->bOnLine)
 { 
  WaitForSingleObject(vnol->hUpdateEvent,INFINITE);//等待事件被置位,此线程暂停于此
  ::SendMessage(vnol->m_hWnd,WM_PAINT,0,0);//给窗口发送刷新消息
  Sleep(100);//时间间隔为100ms
 }

 return 1;
}

//刷新函数

void C****Dlg::OnPaint()
{
 CPaintDC dc(this); // device context for painting
 
 // TODO: Add your message handler code here
 // Do not call CDialog::OnPaint() for painting messages

//得到当前时长

 CString strStaticText;

 CString strTimeSpace;

//自定义的函数,用来得到时长的CString形态

//dwStartTime在需要开始计时的地方获得

 this->GetTimeSpace(this->dwStartTime,strTimeSpace);

 strStaticText = "通话时长:" + strTimeSpace;
 CBrush brush(RGB(255,255,255)); 

//将控件区绘制白色背景
 this->pDCStatic->FillRect(CRect(0,0,this->rcAllText.Width(),this->rcAllText.Height()),&brush);
//在控件上通过DrawText将字显示到屏幕上

 this->pDCStatic->DrawText(szText,CRect(0,0,this->rcAllText.Width(),this->rcAllText.Height()),DT_CENTER|DT_VCENTER|DT_SINGLELINE);

}

//这三种方法共用函数,用来得到时差的CString形态 

void C****Dlg::GetTimeSpace(DWORD dwStartTime,CString & szTime)
{
 DWORD dwNowTime=0;
 DWORD dwSpace=0;
 char time[10]={0,};

 //获取当前时间
 dwNowTime = GetTickCount();

 //开始计算时差
 dwSpace = dwNowTime-dwStartTime;

 dwSpace = dwSpace/1000;//转化为以秒为单位
 int sec = dwSpace` ;
 int min = ((dwSpace - sec)/60)`;
 int hour = ((dwSpace - sec)/60)/60;

 sprintf(time,"-:-:-",hour,min,sec);
 szTime.Format("%s",(char*)time);

 return;
}

 

 

方法二:setwindowText + 计时器

这个方法还好吧。思路就是:启动定时器,每隔一段时间就对控件setwindowText。

在这个方法里,我们用两个控件来进行,一个是staticText控件,一个是Edit控件。

setwindowText:设置控件的显示信息,是针对单个控件而言滴!

CWnd::SetWindowText

void SetWindowText( LPCTSTR lpszString );

Parameters

lpszString

Points to a CString object or null-terminated string to be used as the new title or control text.

与setwindowText相对应的是 GetwindowText。

GetwindowText:获取控件的当前内容(对于Edit控件,可以在它的EN_CHANGE处理中得到当前的显示)。

CWnd::GetWindowText

int GetWindowText( LPTSTR lpszStringBuf, int nMaxCount ) const;

void GetWindowText( CString& rString ) const;

代码如下:

 //变量

 CString m_staticText;//要显示在static控件上的字符串

 CString m_EditText;//要显示在Edit控件上的字符串

 BOOL m_bInitState;//是否处于初始化状态 (若要重载OnSize 则必须是在初始化结束后,否则报错)

 DWORD m_dwStartTime;//起始时间 在需要开始计时的地方通过 GetTickCount()获得

 void GetTimeSpace(DWORD dwStartTime,CString & szTime);//用来的到当前时间差字符串的函数

//窗口的初始化函数 

BOOL C****Dlg::OnInitDialog()
{
 CDialog::OnInitDialog();

 // Set the icon for this dialog.  The framework does this automatically
 //  when the application's main window is not a dialog
 SetIcon(m_hIcon, TRUE);   // Set big icon
 SetIcon(m_hIcon, FALSE);  // Set small icon
 
 // TODO: Add extra initialization here
 //设置定时器
 SetTimer(1,500,NULL);

 this->m_bInitState = FALSE;

 return TRUE;  // return TRUE  unless you set the focus to a control
}


//计时器响应函数

void CUpdateDateDlg::OnTimer(UINT nIDEvent)
{
 // TODO: Add your message handler code here and/or call default
 switch(nIDEvent)
 {
 case 1:
  //定时器时间到
  {
   //计算出时差str

   CString strTemp;
   this->GetTimeSpace(this->m_dwStartTime,strTemp);
   this->m_staticText = "通话时长:"+strTemp;

   //edit和static显示的是一样的

   this->m_EditText = this->m_staticText;
   //得到控件的句柄
   CWnd* hStatic = GetDlgItem(IDC_MYSTATIC);

   CWnd* hEdit = GetDlgItem(IDC_MYEDIT);

   //把语句显示到两个控件上
   hStatic->SetWindowText(this->m_staticText);
   hEdit->SetWindowText(this->m_editText);
  }
  break;
 default:
  CDialog::OnTimer(nIDEvent);
 }
}

//Edit控件显示发生改变时EN_CHANGE的响应函数 

void C****Dlg::OnChangeMyedit()
{

  CString szNowText;
  CWnd* hEdit = GetDlgItem(IDC_MYEDIT);
  hEdit->GetWindowText(szNowText); 
}

方法三:UpdateData + 定时器

这个方法跟方法二思路是一样滴,不过区别在于UpdateData的用法啦~

UpdateData刷新的是整个对话框,而不是像SetWindowText那样是针对控件进行处理。

UpdateData是MFC的API,所以这个方法要基于MFC使用。

使用这个方法,首先要通过ClassWizard建立控件和变量之间的联系。当你修改了变量的值,而希望对话框控件更新显示,就应该在修改变量后调用 UpdateData(FALSE);如果你希望知道用户在对话框中到底输入了什么,就应该在访问变量前调用UpdateData(TRUE)。

// ClassWizard建立控件和变量之间的联系

控件内容更新 <wbr>之 <wbr>DrawText <wbr>UpdateData <wbr>SetWindowText

代码:

//通过ClassWizard建立控件和变量之间联系的代码反映

.h

 //{{AFX_DATA(CUpdateDateDlg)
 enum { IDD = IDD_UPDATEDATE_DIALOG };
 CString m_staticText;
 CString m_editText;
 //}}AFX_DATA

.cpp

void CUpdateDateDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CUpdateDateDlg)
 DDX_Text(pDX, IDC_MYSTATIC, m_staticText);
 DDX_Text(pDX, IDC_MYEDIT, m_editText);
 //}}AFX_DATA_MAP
}

//变量 

 BOOL m_bInitState;//是否处于初始化状态 (若要重载OnSize 则必须是在初始化结束后,否则报错)

 DWORD m_dwStartTime;//起始时间
 void GetTimeSpace(DWORD dwStartTime,CString & szTime);//用来的到当前时间差字符串的函数

//窗口的初始化函数 

BOOL C****Dlg::OnInitDialog()
{
 CDialog::OnInitDialog();

 // Set the icon for this dialog.  The framework does this automatically
 //  when the application's main window is not a dialog
 SetIcon(m_hIcon, TRUE);   // Set big icon
 SetIcon(m_hIcon, FALSE);  // Set small icon
 
 // TODO: Add extra initialization here
 //设置定时器
 SetTimer(1,500,NULL);

 this->m_bInitState = FALSE;

 return TRUE;  // return TRUE  unless you set the focus to a control
}


//计时器的响应函数

void CUpdateDateDlg::OnTimer(UINT nIDEvent)
{
 // TODO: Add your message handler code here and/or call default
 switch(nIDEvent)
 {
 case 1:
  //定时器时间到
  {
   //计算出时差
   this->GetTimeSpace(this->m_dwStartTime,this->m_editText);
   this->m_staticText = this->m_editText;


   this->UpdateData(false);

  }
  break;
 default:
  CDialog::OnTimer(nIDEvent);
 }
}

//edit控件显示内容发生变化时EN_CHANGE的响应函数 

void C****Dlg::OnChangeMyedit()
{

    this->UpdateData(true); 
}

 


UpdateData详解

UpdateData(TRUE):

是将控件的状态传给其关联的变量,当然你要为控件关联上变量才行。

用于将屏幕上控件中的数据交换到变量中。
UpdateData(FALSE):

是将控件的关联变量的值传给控件并改变控件状态。

用于将数据在屏幕中对应控件中显示出来。

注意:

UpdateData刷新的是当前对话框

使用UpdateData()函数时,当前界面上所有绑定了的变量(即通过MFC ClassWizard给控件添加了对应的变量)都会被UpdateData(TRUE)更新成对应控件中的内容;同样所有绑定了变量的控件中的内容也会 UpdateData(FALSE)更新成对应变量中的内容。

重要补充

GetWindowText()是获取控件当前内容,是对单个控件而言;
UpdateData()是作用于整个CWnd的DDX数据交换机制之中的,是控件和数据的双向通道。

原文地址:https://www.cnblogs.com/jack-jia-moonew/p/4299764.html