以一個顯示用戶通話時長的界面爲例,要在一個static控件上繪製「通話時長:XX:XX:XX」html
關於繪製,可使用得到到控件的句柄和CDC,經過 DrawText 繪製,也能夠經過API函數UpdateData 或 SetWindowText 進行更新。app
關於計時,能夠經過線程來計時也能夠經過利用計時器來計時。less
下面,按照繪製方式的不一樣來進行比較,看哪一個最方便啦~函數
方法一: DrawText + 線程計時this
這無疑是最笨的一種方法啦...url
代碼:spa
//變量線程
CDC* pDCStatic;//static控件的CDCcode
BOOL bIintState;//是否初始化完畢(對WM_SIZE的處理必須是在初始化完畢後,不然出錯)orm
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創建控件和變量之間的聯繫
//經過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數據交換機制之中的,是控件和數據的雙向通道。