Visual C++程式設計技巧之一
1.如何擷取應用程式的執行個體句柄?
應用程式的 執行個體句柄儲存在CWinAppIm_hInstance 中,可以這麼調用
AfxGetInstancdHandle獲得句柄.
Example: HANDLE hInstance=AfxGetInstanceHandle();
2.如何通過代碼獲得應用程式主視窗的指針?
主視窗的 指針儲存在CWinThread::m_pMainWnd中,調用AfxGetMainWnd實作。
AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //使程式最大化.
3.如何在程式中獲得其他程式的圖示?
兩種方法:
(1) SDK函數SHGetFileInfo或使用ExtractIcon獲得圖示資源的 handle,
(2) SDK函數SHGetFileInfo獲得有關檔案的 很多資訊,如大小圖示,屬性,類型等.
Example(1):在程式視窗左上角顯示 NotePad圖示.
void CSampleView: OnDraw(CDC * pDC)
{
if( :: SHGetFileInfo(_T("c://pwin95//notepad.exe"),0,
&stFileInfo,sizeof(stFileInfo),SHGFI_ICON))
{
pDC ->DrawIcon(10,10,stFileInfo.hIcon);
}
}
Example(2):同樣功能,Use ExtractIcon Function
void CSampleView:: OnDraw(CDC *pDC)
{
HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T
("NotePad.exe"),0);
if (hIcon &&hIcon!=(HICON)-1)
pDC->DrawIcon(10,10,hIcon);
}
說明:獲得notepad.exe的路徑正規上來說用GetWindowsDirectory函數得到,如果是調用 win95下的畫筆,應該用通路系統資料庫的方法獲得其路徑,要作成一個比較考究的程式,考慮應該全面點.
4.如何程式設計結束應用程式?如何程式設計控制windows的重新開機?
這是個很簡單又是程式設計中經常要遇到的問題.
第一問,向視窗發送WM_CLOSE消息,調用CWnd::OnClose成員函數.允許對使用者提示
是否儲存修改過的資料.
Example: AfxGetMainWindow()->SendMessage(WM_CLOSE);
還可以建立一個自定義的函數Terminate Window
void Terminate Window(LPCSTR pCaption)
{
CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption);
if (pWnd)
pWnd ->SendMessage(WM_CLOSE);
}
說明: FindWindow函數不是提倡的做法,因為它無法處理标題欄自動改變,比如我們要檢測 Notepad是不是已運作而事先不知道Notepad的标題欄,這時 FindWindow就無能為力了,可以通過枚舉windows任務清單的辦法來實作。 在 機械出版社"Windows 95 API開發人員指南"一書有比較詳細的介紹,這裡就不再多說樂。
第二問,Use ExitWindowsEx Function函數控制系統是重新開機,還是重新開機 windows.前面已經有人講過樂,就不再提了。
5.怎樣加栽其他的應用程式?
我記得這好象是出場頻度很高的問題。
三個SDK函數winexec, shellexecute,createprocess可以使用。
WinExec最簡單,兩個參數,前一個指定路徑,後一個指定顯示方式.後一個參數值得說一下,比如泥用SW_SHOWMAXMIZED方式去加栽一個無最大化按鈕的 程式,呵呵就是Neterm,calc等等,就不會出現正常的 窗體,但是已經被加到任務清單裡了。ShellExecute較 WinExex靈活一點,可以指定工作目錄,下面的Example就是直接打開 c:/temp/1.txt,而不用加栽與txt檔案關聯的應用程式,很多安裝程式完成後都會打開一個視窗,來顯示Readme or Faq,偶猜就是這麼作的啦.
ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c://temp"),SW_SHOWMAXMIZED);
CreateProcess最複雜,一共有十個參數,不過大部分都可以用NULL代替,它可以指定程序的安全屬性,繼承資訊,類的優先級等等.來看個很簡單的Example:
STARTUPINFO stinfo; //啟動視窗的資訊
PROCESSINFO procinfo; //程序的資訊
CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE, NORMAL_PRIORITY_
CLASS,NULL,NULL, &stinfo,&procinfo);
6.确定應用程式的路徑
前些天好象有人問過這個問題.
Use GetModuleFileName獲得應用程式的路徑,然後去掉可執行檔案名。
Example:
TCHAR exeFullPath[MAX_PATH]; // MAX_PATH在API中定義了吧,好象是128
GetModuleFileName(NULL,exeFullPath,MAX_PATH)
7.獲得各種目錄資訊
Windows目錄: Use "GetWindowsDirectory“
Windows下的system目錄: Use "GetSystemDirectory"
temp目錄: Use "GetTempPath "
目前目錄: Use "GetCurrentDirectory"
請注意前兩個函數的第一個參數為 目錄變量名,後一個為緩沖區;後兩個相反.
8.如何自定義消息
也有人問過的,其實不難。
(1)手工定義消息,可以這麼寫 #define WM_MY_MESSAGE(WM_USER+100),
MS推薦的至少是WM_USER+100;
(2)寫消息處理函數,用WPARAM,LPARAM傳回LRESULT.
LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam)
{
//加入你的處理函數
}
(3)在類的AFX_MSG處進行聲明,也就是常說的"宏映射"
---------------------------------------
9.如何改變視窗的圖示?
向視窗發送WM_SECTION消息。
Example:
HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON);
ASSERT(hIcon);
AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM) hIcon);
10.如何改變視窗的預設風格?
重栽CWnd:: PreCreateWindow并修改CREATESTRUCT結構來指定視窗風格和其他
建立資訊.
Example: Delete "Max" Button and Set Original Window's Position and Size
BOOL CMainFrame:: PreCreateWindow (CREATESTRUCT &cs)
{
cs.style &=~WS_MAXINIZEMOX;
cs.x=cs.y=0;
cs.cx=GetSystemMetrics(SM_CXSCREEN/2);
cs.cy=GetSystemMetrics(SM_CYSCREEN/2);
return CMDIFramewnd ::PreCreateWindow(cs);
}
11.如何将視窗居中顯示?
Easy, Call Function CWnd:: Center Windows
Example(1): Center Window( ); //Relative to it's parent
// Relative to Screen
Example(2): Center Window(CWnd:: GetDesktopWindow( ));
//Relative to Application's MainWindow
AfxGetMainWnd( ) -> Center Window( );
12.如何讓視窗和MDI視窗一啟動就最大化和最小化?
先說視窗。
在InitStance函數中設定m_nCmdShow的 取值.
m_nCmdShow=SW_SHOWMAXMIZED ; //最大化
m_nCmdShow=SW_SHOWMINMIZED ; //最小化
m_nCmdShow=SW_SHOWNORMAL ; //正常方式
MDI視窗:
如果是建立新的應用程式,可以用 MFC AppWizard的Advanced 按鈕并在
MDI子視窗風格組中檢測最大化或最小化;還可以重載MDI Window的
PreCreateWindow函數,設定WS_MAXMIZE or WS_MINMIZE;
如果從CMDIChildWnd派生,調用OnInitialUpdate函數中的 CWnd::Show
Window來指定MDI Child Window的 風格。
13.如何使程式保持極小狀态?
很有意思的 問題
這麼辦:在恢複程式窗體大小時, Windows會發送WM_QUERY-OPEN消息,
用ClassWizard設定成員函數OnQueryOpen() ,add following code:
Bool CMainFrame:: OnQueryOpen( )
{
Return false;
}
14.如何限制視窗的大小?
也就是FixedDialog形式。Windows發送WM_GETMAXMININFO消息來跟蹤,
響應它,在OnGetMAXMININFO中寫代碼:
15.如何使視窗不可見?
很簡單,用SW_HIDE隐藏視窗,可以結合FindWindow,ShowWindow控制.
16.如何使視窗始終在最前方?
兩種途徑.
BringWindowToTop(Handle);
SetWindowPos函數,指定視窗的 最頂風格,用WS_EX_TOPMOST擴充視窗的 風格
Example:
void ToggleTopMost( CWnd *pWnd)
{
ASSERT_VALID(pWnd);
pWnd ->SetWindowPos(pWnd-> GetStyle( ) &WS_EX_TOPMOST)?
&wndNoTopMOST: &wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE);
}
=======================================
17、如何建立一個字回繞的CEditView
重載CWnd : : PreCreateWindow和修改CREATESTRUCT結構,關閉CEditView對象的ES_AUTOHSCROLL和WS_HSCROLL風格位, 由于CEditView : : PreCreateWindow顯示設定cs. style,調用基類函數後要修改cs . style。
BOOL CSampleEDitView : : PreCreateWindow (CREATESTRUCT&cs)
{
//First call basse class function .
BOOL bResutl =CEditView : : PreCreateWindow (cs) ;
// Now specify the new window style .
cs.style &= ~ (ES_AUTOHSCROLL |WS_HSCROLL);
return bResult ;
}
18、通用控件的顯示視窗
MFC提供了幾個CView派生的視窗類, 封裝了通用控件的功能,但仍然使用工
作框文檔顯示視窗體系結構:CEditView封裝了編輯控件,CTreeView保持了樹清單
控件,CListView封裝了清單顯示視窗控件,CRichEditView可以處理多種編輯控件。
19、移動視窗
調用CWnd : : SetWindowPos并指定SWP_NOSIZE标志。目的位置與父視窗
有關(頂層視窗與螢幕有關)。調用CWnd : : MoveWindow時必須要指定視窗
的大小。
//Move window to positoin 100 , 100 of its parent window .
SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE |SWP_NOAORDER);
20、重置視窗的大小
調用CWnd: : SetWindowPos并指定SWP_NOMOVE标志, 也可調用
CWnd : : MoveWindow 但必須指定視窗的位置。
// Get the size of the window .
Crect reWindow ;
GetWindowRect (reWindow );
//Make the window twice as wide and twice as tall .
SetWindowPos (NULL , 0 , 0 , reWindow . Width ( ) *2,
reWindow . Height () * 2,
SWP_NOMOVE |SWP_NOZORDER );
21、如何單擊除了視窗标題欄以外的區域使視窗移動
當視窗需要确定滑鼠位置時Windows向視窗發送WM_NCHITTEST資訊,可以處理
該資訊使Windows認為滑鼠在視窗标題上。對于對話框和基于對話的應用程式,可
以使用ClassWizard處理該資訊并調用基類函數, 如果函數傳回HTCLIENT 則表明
滑鼠在客房區域,傳回HTCAPTION表明滑鼠在Windows的标題欄中。
UINT CSampleDialog : : OnNcHitTest (Cpoint point )
{
UINT nHitTest =Cdialog: : OnNcHitTest (point );
return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest ;
}
上述技術有兩點不利之處, 其一是在視窗的客戶區域輕按兩下時, 視窗将極大;
其二, 它不适合包含幾個視窗的主框視窗。還有一種方法,當使用者按下滑鼠左鍵
使主框視窗認為滑鼠在其視窗标題上,使用ClassWizard在視窗中處理WM_LBUTTODOWN
資訊并向主框視窗發送一個WM_NCLBUTTONDOWN資訊和一個單擊測試HTCAPTION。
void CSampleView : : OnLButtonDown (UINT nFlags , Cpoint point )
{
CView : : OnLButtonDow (nFlags , pont );
//Fool frame window into thinking somene clicked on
its caption bar .
GetParentFrame ( ) —> PostMessage (
WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (poitn .x , point .y) );
}
該技術也适用于對話框和基于對的應用程式,隻是不必調用CWnd : : GetParentFrame 。
void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point )
{
Cdialog : : OnLButtonDow (nFlags, goint );
//Fool dialog into thinking simeone clicked on its caption bar .
PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x , point. y ) )
}
22、如何改變視窗的背景顔色
Windows向視窗發送一個WM_ERASEBKGND消息通知該視窗擦除背景,可以使用
ClassWizard重載該消息的預設處理程式來擦除背景(實際是畫),并傳回TRUE以
防止Windows擦除視窗。
//Paint area that needs to be erased.
BOOL CSampleView : : OnEraseBkgnd (CDC* pDC)
{
// Create a pruple brush.
CBrush Brush (RGB (128 , 0 , 128) );
// Select the brush into the device context .
CBrush* pOldBrush = pDC—>SelcetObject (&brush);
// Get the area that needs to be erased .
CRect reClip ;
pDC—>GetCilpBox (&rcClip);
//Paint the area.
pDC—> PatBlt (rcClip.left , rcClip.top ,
rcClip.Width ( ) , rcClip.Height ( ) , PATCOPY );
//Unselect brush out of device context .
pDC—>SelectObject (pOldBrush );
// Return nonzero to half fruther processing .
return TRUE;
}
23、如何改變視窗标題
調用CWnd : : SetWindowText可以改變任何視窗(包括控件)的标題。
//Set title for application's main frame window .
AfxGetMainWnd ( ) —> SetWindowText (_T("Application title") );
//Set title for View's MDI child frame window .
GetParentFrame ( ) —> SetWindowText ("_T ("MDI Child Frame new title") );
//Set title for dialog's push button control.
GetDigitem (IDC_BUTTON) —> SetWindowText (_T ("Button new title ") );
如果需要經常修改視窗的标題(注:控件也是視窗),應該考慮使用半文檔化
的函數AfxSetWindowText。該函數在AFXPRIV.H中說明,在WINUTIL.CPP中實作,在
聯機幫助中找不到它,它在AFXPRIV.H中半文檔化, 在以後發行的MFC中将文檔化。
AfxSetWindowText的實作如下:
voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew )
{
itn nNewLen= Istrlen (Ipaznew);
TCHAR szOld [256];
//fast check to see if text really changes (reduces flash in the controls )
if (nNewLen >_contof (szOld) ||
: : GetWindowText (hWndCrtl , szOld , _countof (szOld) =nNewLen ||
Istrcmp (szOld , IpszNew ) = 0
{
//change it
: : SetWindowText (hWndCtrl , IpszNew );
}
}
24、如何防止主框視窗在其說明中顯示活動的文檔名
建立主框視窗和MDI子視窗進通常具有FWS_ADDTOTITLE風格位, 如果不希望在
說明中自動添加文檔名, 必須禁止該風格位, 可以使用ClassWizard重置
CWnd: : PreCreateWindow并關閉FWS_ADDTOTITLE風格。
BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs)
{
//Turn off FWS_ADDTOTITLE in main frame .
cs.styel & = ~FWS_ADDTOTITLE ;
return CMDIFrameWnd : : PreCreateWindow (cs );
}
關閉MDI子視窗的FWS _ADDTOTITLE風格将建立一個具有空标題的視窗,可以調
用CWnd: : SetWindowText來設定标題。記住自己設定标題時要遵循接口風格指南。
====================================
Visual C++程式設計技巧之四
25、如何擷取有關視窗正在處理的目前消息的資訊
調用CWnd: : GetCurrentMessage可以擷取一個MSG指針。例如,可以使用
ClassWizard将幾個菜單項處理程式映射到一個函數中,然後調用GetCurrentMessage
來确定所選中的菜單項。
viod CMainFrame : : OnCommmonMenuHandler ( )
{
//Display selected menu item in debug window .
TRACE ("Menu item %u was selected . /n" ,
GetCruuentMessage ( )—> wParam );
}
26、如何建立一個不規則形狀的視窗
可以使用新的SDK函數SetWindowRgn。該函數将繪畫和滑鼠消息限定在視窗的一
個指定的區域,實際上使視窗成為指定的不規則形狀。
使用AppWizard建立一個基于對的應用程式并使用資源編輯器從主對話資源中删
除所在的預設控件、标題以及邊界。
給對話類增加一個CRgn資料成員,以後要使用該資料成員建立視窗區域。
Class CRoundDlg : public CDialog
{
…
private :
Crgn m_rgn : // window region
…
} ;
修改OnInitDialog函數建立一個橢圓區域并調用SetWindowRgn将該區域配置設定給
視窗:
BOOL CRoundDlg : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( ) ;
//Get size of dialog .
CRect rcDialog ;
GetClientRect (rcDialog );
// Create region and assign to window .
m_rgn . CreateEllipticRgn (0 , 0 , rcDialog.Width ( ) , rcDialog .Height ( ) );
SetWindowRgn (GetSafeHwnd ( ) , (HRGN) m_ rgn , TRUE );
return TRUE ;
}
通過建立區域和調用SetWindowRgn,已經建立一個不規則形狀的視窗,下面的例
子程式是修改OnPaint函數使視窗形狀看起來象一個球形體。
voik CRoundDlg : : OnPaint ( )
{
CPaintDC de (this) ; // device context for painting .
//draw ellipse with out any border
dc. SelecStockObject (NULL_PEN);
//get the RGB colour components of the sphere color
COLORREF color= RGB( 0 , 0 , 255);
BYTE byRed =GetRValue (color);
BYTE byGreen = GetGValue (color);
BYTE byBlue = GetBValue (color);
// get the size of the view window
Crect rect ;
GetClientRect (rect);
// get minimun number of units
int nUnits =min (rect.right , rect.bottom );
//calculate he horiaontal and vertical step size
float fltStepHorz = (float) rect.right /nUnits ;
float fltStepVert = (float) rect.bottom /nUnits ;
int nEllipse = nUnits/3; // calculate how many to draw
int nIndex ; // current ellipse that is being draw
CBrush brush ; // bursh used for ellipse fill color
CBrush *pBrushOld; // previous brush that was selected into dc
//draw ellipse , gradually moving towards upper-right corner
for (nIndex = 0 ; nIndes < + nEllipse ; nIndes ++)
{
//creat solid brush
brush . CreatSolidBrush (RGB ( ( (nIndex *byRed ) /nEllipse ).
( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue) /nEllipse ) ) );
//select brush into dc
pBrushOld= dc .SelectObject (&brhsh);
//draw ellipse
dc .Ellipse ( (int) fltStepHorz * 2, (int) fltStepVert * nIndex ,
rect. right -( (int) fltStepHorz * nIndex )+ 1,
rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1) ;
//delete the brush
brush.DelecteObject ( );
}
}
最後,處理WM_NCHITTEST消息,使當擊打視窗的任何位置時能移動視窗。
UINT CRoundDlg : : OnNchitTest (Cpoint point )
{
//Let user move window by clickign anywhere on the window .
UINT nHitTest = CDialog : : OnNcHitTest (point) ;
rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest ;
}
27、如何在代碼中擷取工具條和狀态條的指針
預設時, 工作框建立狀态條和工具條時将它們作為主框視窗的子視窗,狀态條
有一個AFX_IDW_STATUS_BAR辨別符,工具條有一個AFX_IDW_TOOLBAR辨別符,下例說
明了如何通過一起調用CWnd: : GetDescendantWindow和AfxGetMainWnd來擷取這些
子視窗的指針:
//Get pointer to status bar .
CStatusBar * pStatusBar =
(CStatusBar *) AfxGetMainWnd ( )—> GetDescendantWindow
(AFX_IDW_STUTUS_BAR);
//Get pointer to toolbar .
CToolBar * pToolBar =
(CToolBar * ) AfxGetMainWnd ( )—> GetDescendantWindow (AFX_IDW_TOOLBAR);
28、如何使能和禁止工具條的工具提示
如果設定了CBRS_TOOLTIPS風格位,工具條将顯示工具提示,要使能或者禁止
工具提示,需要設定或者清除該風格位。下例通過調用CControlBar : : GetBarStyle
和CControlBar : : SetBarStyle建立一個完成此功能的成員函數:
void CMainFrame : : EnableToolTips ( BOOL bDisplayTips )
{
ASSERT_VALID (m_wndToolBar);
DWORD dwStyle = m _wndToolBar.GetBarStyle ( ) ;
if (bDisplayTips)
dwStyle|=CBRS_TOOLTIPS ;
else
dwStyle & = ~ CBRS_TOOLTIPS ;
m_wndToolBar.SetBarStyle (dwStyle );
}
29、如何設定工具條标題
工具條是一個視窗,是以可以在調用CWnd : : SetWindowText來設定标題,例子如下:
int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct )
{
…
// Set the caption of the toolbar .
m_wndToolBar.SetWindowText (_T "Standdard");
30、如何建立和使用無模式對話框
MFC将模式和無模式對話封裝在同一個類中,但是使用無模式對話需要幾
個對話需要幾個額處的步驟。首先,使用資源編輯器建立對話資源并使用
ClassWizard建立一個CDialog的派生類。模式和無模式對話的中止是不一樣的:
模式對話通過調用CDialog : : EndDialog來中止,無模式對話則是調用
CWnd: : DestroyWindow來中止的,函數CDialog : : OnOK和CDialog : : OnCancel
調用EndDialog ,是以需要調用DestroyWindow并重置無模式對話的函數。
void CSampleDialog : : OnOK ( )
{
// Retrieve and validate dialog data .
if (! UpdateData (TRUE) )
{
// the UpdateData rountine will set focus to correct item
TRACEO (" UpdateData failed during dialog termination ./n") ;
return ;
}
//Call DestroyWindow instead of EndDialog .
DestroyWindow ( ) ;
}
void CSampleDialog : : OnCancel ( )
{
//Call DestroyWindow instead of EndDialog .
DestroyWindow ( ) ;
}
其次,需要正确删除表示對話的C++對象。對于模式對來說,這很容易,需要建立函數傳回後即可删除C++對象;無模式對話不是同步的,建立函數調用後立即傳回,因而使用者不知道何時删除C++對象。撤銷視窗時工作框調用CWnd : : PostNcDestroy,可以重置該函數并執行清除操作,諸如删除this指針。
void CSampleDialog : : PostNcDestroy ( )
{
// Declete the C++ object that represents this dialog .
delete this ;
}
最後,要建立無模式對話。可以調用CDialog : : DoModal建立一個模式對放, 要建立一個無模式對話則要調用CDialog: : Create。下面的例子說明了應用程式是如何建立無模式對話的:
void CMainFrame : : OnSampleDialog ( )
{
//Allocate a modeless dialog object .
CSampleDilog * pDialog =new CSampleDialog ;
ASSERT_VALID (pDialog) ;
//Create the modeless dialog .
BOOL bResult = pDialog—> Creste (IDD_IDALOG) ;
ASSERT (bResult ) ;
}
31、如何在對話框中顯示一個位圖
這要歸功于Win 32先進的靜态控件和Microsoft的資源編輯器, 在對話框中顯示位圖是很容易的, 隻需将圖形控件拖到對話中并選擇适當屬性即可,使用者也可以顯示圖示、位圖以及增強型元檔案。
32、如何改變對話或窗體視窗的背景顔色
調用CWinApp : : SetDialogBkColor可以改變所有應用程式的背景顔色。第一個參數指定了背景顔色,第二個參數指定了文本顔色。下例将應用程式對話設定為藍色背景和黃色文本。
BOOL CSampleApp : : InitInstance ( )
{
…
//use blue dialog with yellow text .
SetDialogBkColor (RGB (0, 0, 255 ), RGB ( 255 , 255 , 0 ) ) ;
…
}
需要重畫對話(或對話的子控件)時,Windows向對話發送消息WM_CTLCOLOR,通常使用者可以讓Windows選擇繪畫背景的刷子,也可重置該消息指定刷子。下例說明了建立一個紅色背景對話的步驟。
首先,給對話基類增加一人成員變量CBursh :
class CMyFormView : public CFormView
{
…
private :
CBrush m_ brush ; // background brush
…
} ;
其次, 在類的構造函數中将刷子初始化為所需要的背景顔色。
CMyFormView : : CMyFormView ( )
{
// Initialize background brush .
m_brush .CreateSolidBrush (RGB ( 0, 0, 255 ) )
}
最後,使用ClassWizard處理WM_CTLCOLOR消息并傳回一個用來繪畫對話背景的刷子句柄。注意:由于當重畫對話控件時也要調用該函數,是以要檢測nCtlColor參量。
HBRUSH CMyFormView : : OnCtlColor (CDC* pDC , CWnd*pWnd , UINT nCtlColor )
{
// Determine if drawing a dialog box . If we are , return +handle to
//our own background brush . Otherwise let windows handle it .
if (nCtlColor = = CTLCOLOR _ DLG )
return (HBRUSH) m_brush .GetSafeHandle ( ) ;
return CFormView : : OnCtlColor (pDC, pWnd , nCtlColor );
}
33、如何擷取一個對話控件的指針
有兩種方法。其一,調用CWnd: : GetDlgItem,擷取一個CWnd*指針調用成員函數。下例調用GetDlgItem,将傳回值傳給一個CSpinButtonCtrl*以便調用CSpinButtonCtrl : : SetPos函數:
BOOL CSampleDialog : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( ) ;
//Get pointer to spin button .
CSpinButtonCtrl * pSpin - ( CSpinButtonCtrl *) GetDlgItem (IDC_SPIN) ;
ASSERT _ VALID (pSpin) ;
//Set spin button's default position .
pSpin—> SetPos (10) ;
return TRUE ;
}
其二, 可以使用ClassWizard将控件和成員變量聯系起來。在ClassWizard中簡單地選擇Member Variables标簽,然後選擇Add Variable…按鈕。如果在對話資源編輯器中,按下Ctrl鍵并輕按兩下控件即可轉到Add Member Variable對話。
34、如何禁止和使能控件
控件也是視窗,是以可以調用CWnd : : EnableWindow使能和禁止控件。
//Disable button controls .
m_wndOK.EnableWindow (FALSE ) ;
m_wndApply.EnableWindow (FALSE ) ;
35、如何改變控件的字型
由于控件是也是視窗,使用者可以調用CWnd: : SetFont指定新字型。該函數用一個Cfont指針,要保證在控件撤消之前不能撤消字型對象。下例将下壓按鈕的字型改為8點Arial字型:
//Declare font object in class declaration (.H file ).
private :
Cfont m_font ;
// Set font in class implementation (.Cpp file ). Note m_wndButton is a
//member variable added by ClassWizard.DDX routines hook the member
//variable to a dialog button contrlo.
BOOL CSampleDialog : : OnInitDialog ( )
{
…
//Create an 8-point Arial font
m_font . CreateFont (MulDiv (8 , -pDC—> GetDeviceCaps (LOGPIXELSY) , 72).
0 , 0 , 0 , FW_NORMAL , 0 , 0, 0, ANSI_CHARSER, OUT_STROKE_PRECIS ,
CLIP_STROKE _PRECIS , DRAFT _QUALITY
VARIABLE_PITCH|FF_SWISS, _T ("Arial") );
//Set font for push button .
m_wndButton . SetFont (&m _font );
…
}
36、如何在OLE控件中使用OLE_COLOR資料類型
諸如COleControl : : GetFortColor和COleControl : : GetBackColor等函數傳回OLE _COLOR資料類型的顔色,而GDI對象諸如筆和刷子使用的是COLORREF資料類型,調用COleControl : : TranslateColor可以很容易地将OLE_COLOR類型改為COLORREF類型。下例建立了一個目前背景顔色的刷子:
void CSampleControl : : OnDraw (CDC* pdc
const Crect& rcBounds , const Crect& rcInvalid )
{
//Create a brush of the cuttent background color .
CBrush brushBack (TranslateColor (GetBackColor ( ) ) );
//Paint the background using the current background color .
pdc—> FilllRect (rcBounds , &brushBack) ;
//other drawign commands
…
}
37、在不使用通用檔案打開對話的情況下如何顯示一個檔案清單
調用CWnd: : DlgDirList或者CWnd: : DlgDirListComboBox,Windows 将自動地向清單框或組合框填充可用的驅動器名或者指定目錄中的檔案,下例将Windows目錄中的檔案填充在組合框中:
BOOL CSampleDig : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( )
TCHAR szPath [MAX_PATH] = {"c://windows"} ;
int nReslt = DlgDirListComboBox (szPath , IDC_COMBO , IDC_CURIDIR,
DDL_READWRITE|DDL_READONLY|DDL_HIDDEN|
DDL_SYSTEM|DDL_ARCHIVE ) ;
return TRUE ;
}
38、為什麼旋轉按鈕控件看起來倒轉
需要調用CSpinCtrl : : SetRange設定旋轉按鈕控件的範圍,旋轉按鈕控件的預設上限為0,預設下限為100,這意味着增加時旋轉按控件的值由100變為0。下例将旋轉按鈕控件的範圍設定為0到100:
BOOL CAboutDlg : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( )
//set the lower and upper limit of the spin button
m_wndSpin . SetRange ( 0 ,100 ) ;
return TRUE ;
}
Visual C++ 4.0 Print對話中的Copise旋轉按鈕控件也有同樣的問題:按下Up按鈕時拷貝的數目減少,而按下Down按鈕時拷貝的數目增加。
39為什麼旋轉按鈕控件不能自動地更新它下面的編輯控件
如果使用旋轉按鈕的autu buddy特性, 則必須保證在對話的标記順序中buddy視窗優先于旋轉按鈕控件。從Layout菜單中選擇Tab Order菜單項(或者按下Crtl+D)可以設定對話的标簽順序。
40、如何用位圖顯示下壓按鈕
Windows 95按鈕有幾處新的建立風格,尤其是BS_BITMAP和BS_ICON,要想具有位圖按鈕,建立按鈕和調用CButton : : SetBitmap或CButton : : SetIcon時要指定BS_BITMAP或BS_ICON風格。
首先,設定按鈕的圖示屬性。
然後,當對話初始化時調用CButton: : SetIcon。注意:下例用圖示代替位圖,使用位圖時要小心,因為不知道背景所有的顔色——并非每個人都使用淺灰色。
BOOL CSampleDlg : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( ) ;
//set the images for the push buttons .
m_wndButton1.SetIcon (AfxGetApp ( )—> LoadIcon (IDI _ IPTION1) )
m_wndButton2.SetIcon (AfxGetApp ( )—> LoadIcon (IDI _ IPTION2) )
m_wndButton3.SetIcon (AfxGetApp ( )—> LoadIcon (IDI _ IPTION3) )
return TRUE ;
}
=================
41、如何一個建立三态下壓按鈕
可以使用新的BS_PUSHBUTTON風格位和檢測框以及按鈕來建立一個三态下壓按鈕。這很容易,隻需将檢測框和按鈕拖拉到對話中并指定屬性Push—like即可。不用任何附加程式就可以成為三态下壓按鈕。
42、如何動态建立控件
配置設定一個控件對象的執行個體并調用其Create成員函數。開發者最容易忽略兩件事:忘記指定WS_VISBLE标簽和在棧中配置設定控件對象。下例動态地建立一個下壓按鈕控件:
//In class declaration (.H file ).
private :
CButton* m _pButton ;
//In class implementation (.cpp file ) .
m_pButton =new CButton ;
ASSERT_VALID (m_pButton);
m_pButton—>Create (_T ("Button Title ") , WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON.
Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON )
43、如何限制編輯框中的準許字元
如果使用者在編輯控件中隻允許接收數字,可以使用一個标準的編輯控件并指定新的建立标志ES_NUMBERS,它是Windows 95新增加的标志,該标志限制 編輯控件隻按收數字字元。如果使用者需要複雜的編輯控件,可以使用Microsoft的屏蔽編輯控件,它是一個很有用的OLE定制控件。
如果希望不使用OLE定制控件自己處理字元,可以派生一個CEdit類并處理WM_CHAR消息,然後從編輯控件中過濾出特定的字元。首先,使用ClassWizard建立一個CEdit的派生類,其次,在對話類中指定一個成員變量将編輯控件分類在OnInitdialog中調用CWnd: : SubclassDlgItem .
//In your dialog class declaration (.H file )
private :
CMyEdit m_wndEdit ; // Instance of your new edit control .
//In you dialog class implementation (.CPP file )
BOOL CSampleDialog : : OnInitDialog ( )
{
…
//Subclass the edit lontrod .
m_wndEdit .SubclassDlgItem (IDC_EDIT,this );
…
}
使用ClassWizard處理WM_CHAR消息,計算nChar參量并決定所執行的操作,使用者可以确定是否修改、傳送字元。下例說明了如何顯示字母字元,如果字元是字母字元,則調用CWnd ; OnChar,否則不調用OnChar.
//Only display alphabetic dharacters .
void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags )
{
//Determine if nChar is an alphabetic character .
if (: : IsCharAlpha ( ( TCHAR) nChar ) )
CEdit : : OnChar (nChar, nRepCnt , nFlags );
}
如果要修改字元,則不能僅僅簡單地用修改過的nChar調用CEdit : : OnChar,然後CEdit: : OnChar調用CWnd: : Default擷取原來的wParam和lParam的值 ,這樣是不行的。要修改一個字元,需要首先修改nChar,然後用修改過的nChar調用CWnd: : DefWindowProc。下例說明了如何将字元轉變為大寫:
//Make all characters uppercase
void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags )
{
//Make sure character is uppercase .
if (: : IsCharAlpha ( .( TCHAR) nChar)
nChar=: : CharUpper (nChar ) ;
//Bypass default OnChar processing and directly call
//default window proc.
DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt , nFlags )) ;
}
44、如何改變控件的顔色
有兩種方法。其一,可以在父類中指定控件的顔色,或者利用MFC4.0新的消息反射在控件類中指定顔色。當控件需要重新着色時,工作框調用父視窗(通常是對話框)的CWnd: : OnCrtlColor,可以在父視窗類中重置該函數并指定控件的新的繪畫屬性。例如,下述代碼将對話中的所有編輯控件文本顔色改為紅色:
HBRUSH CAboutDig : : OnCtlColor (CDC * pDCM , CWnd * pWnd , UINT nCtlColor)
{
HBRUSH hbr = CDialog : : OnCtlColor (pDC, pWnd , nCtlColor );
//Draw red text for all edit controls .
if (nCtlColor= = CTLCOLOR_EDIT )
pDC—> SetTextColor (RGB (255 , 0 , 0 , ) ) ;
return hbr ;
}
然而,由于每個父視窗必須處理通知消息并指定每個控件的繪畫屬性,是以,這種方法不是完全的面向對象的方法。控件處理該消息并指定繪畫屬性更合情合理。消息反射允許使用者這樣做。通知消息首先發送給父視窗,如果父視窗沒有處理則發送給控件。建立一個定制彩色清單框控件必須遵循下述步驟。
首先,使用ClassWizard建立一個CListBox的派生類并為該類添加下述資料成員。
class CMyListBox ; publilc CListBox
{
…
private;
COLORREF m_clrFor ; // foreground color
COLORREF m_clrBack ; //background color
Cbrush m_brush ; //background brush
…
} ;
其次,在類的構造函數中,初始化資料中。
CMyListBox : : CMyListBox ()
{
//Initialize data members .
m_clrFore =RGB (255 , 255 , 0) ; // yellow text
m_clrBack=RGB (0 , 0 , 255) ; // blue background
m_brush . CreateSolidBrush (m _clrBack );
}
最後,使用ClassWizard處理反射的WM_CTLCOLOR(=WM_CTLCOLOR)消息并指定新的繪畫屬性。
HBRUSH CMyListBox : : CtlColor (CDC* pDC, UINT nCtlColor )
{
pDC—>SetTextColor (m_clrFore);
pDC—>SetBkColor (m_clrBack);
return (HBRUSH) m_brush.GetSafeHandle ()
}
現在,控件可以自己決定如何繪畫,與父視窗無關。
45、當向清單框中添加多個項時如何防止閃爍
調用CWnd::SetRedraw清除重畫标志可以禁止CListBox(或者視窗)重畫。當向清單框添加幾個項時,使用者可以清除重畫标志,然後添加項,最後恢複重畫标志。為確定重畫清單框的新項,調用SetRedraw (TRUE)之後調用CWnd::Invalidate。
//Disable redrawing.
pListBox->SetRedraw (FALSE);
//Fill in the list box gere
//Enable drwing and make sure list box is redrawn.
pListBox->SetRedraw (TRUE);
pListBox->Invalidate ();
46、如何向編輯控件中添加文本
由于沒有CEdit:: AppendText函數,使用者隻好自己做此項工作。調用CEdit:: SetSel移動到編輯控件末尾,然後調用CEdit:: ReplaceSel添加文本。下例是AppendText的一種實作方法:
void CMyEdit:: AppendText (LPCSTR pText)
{
int nLen=GetWindowTextLength ();
SetFocus ();
SetSel (nLen, nLen);
ReplaceSel (pText);
}
47、如何通路預定義的GDI對象
可以通過調用CDC:: SlectStockObject使用Windows的幾個預定義的對象,諸如刷子、筆以及字型。下例使用了Windows預定義的筆和刷子GDI對象在視窗中畫一個橢圓。
//Draw ellipse using stock black pen and gray brush.
void CSampleView:: OnDraw (CDC* pDC)
{
//Determine size of view.
CRect rcView;
GetClientRect (rcView);
//Use stock black pen and stock gray brush to draw ellipse.
pDC->SelectStockObject (BLACK_PEN);
pDC->SelectStockObject (GRAY_BRUSH)
//Draw the ellipse.
pDC->Ellipse (reView);
}
也可以調用新的SDK函數GetSysColorBrush擷取一個系統顔色刷子,下例用背景色在視窗中畫一個橢圓:
void CsampleView:: OnDraw (CDC* pDC)
{
//Determine size of view.
CRect rcView;
GetClientRect (rcView);
//Use background color for tooltips brush.
CBrush * pOrgBrush=pDC->SelectObject (
CBrush::FromHandle (::GetSysColorBrush (COLOR_INFOBK)));
//Draw the ellipse.
pDC->Ellipse (rcView);
//Restore original brush.
pDC->SelectObject (pOrgBrush);
}
48、如何擷取GDI對象的屬性資訊
可以調用GDIObject:: GetObject。這個函數将指定圖表裝置的消息寫入到緩沖區。下例建立了幾個有用的輔助函數。
//Determine if font is bold.
BOOL IsFontBold (const CFont&font)
{
LOGFONT stFont;
font.GetObject (sizeof (LOGFONT), &stFont);
return (stFont.lfBold)? TRUE: FALSE;
}
//Return the size of a bitmap.
CSize GetBitmapSize (const CBitmap&bitmap)
{
BITMAP stBitmap;
bitmap.GetObject (sizeof (BITMAP), &stBitmap);
return CSize (stBitmap.bmWidth, stBitmap. bmHeight);
}
//Create a pen with the same color as a brush.
BOOL CreatePenFromBrush (Cpen&pen, cost Cbrush&brush)
{
LOGBRUSH stBrush;
brush.Getobject (sizeof (LOGBRUSH), &stBrush);
return pen. Createpen (PS_SOLID, 0, stBrush.ibColor);
}
=========================
49、如何實作一個橡皮區矩形
CRectTracker是一個很有用的類,可以通過調用CRectTracker:: TrackRubberBand響應WM_LBUTTONDOWN消息來建立一個橡皮區矩形。下例表明使用CRectTracker移動和重置視窗中的藍色橢圓的大小是很容易的事情。
首先,在檔案檔中聲明一個CRectTracker資料成員:
class CSampleView : Public CView
{
…
public :
CrectTracker m_tracker;
…
};
其次,在文檔類的構造函數中初始化CRectTracker對象:
CSampleDoc:: CSampleDOC ()
{
//Initialize tracker position, size and style.
m_tracker.m_rect.SetRect (0, 0, 10, 10);
m_tracker.m_nStyle=CRectTracker:: resizeInside |
CRectTracker:: dottedLine;
}
然後,在OnDraw函數中畫橢圓和蹤迹矩形:
void CSampleView:: OnDraw (CDC* pDC)
{
CSampleDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoc);
//Select blue brush into device context.
CBrush brush (RGB (0, 0, 255));
CBrush* pOldBrush=pDC->SelectObject (&brush);
//draw ellipse in tracking rectangle.
Crect rcEllipse;
pDoc->m_tracker.GetTrueRect (rcEllipse);
pDC->Ellipse (rcEllipse);
//Draw tracking rectangle.
pDoc->m_tracker.Draw (pDC);
//Select blue brush out of device context.
pDC->Selectobject (pOldBrush);
}
最後,使用ClassWizard處理WM_LBUTTONDOWN消息,并增加下述代碼。該段代碼根據滑鼠擊鍵情況可以拖放、移動或者重置橢圓的大小。
void CSampleView::OnLButtonDown (UINT nFlags, CPoint point)
{
//Get pointer to document.
CSampleDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoc);
//If clicked on ellipse, drag or resize it. Otherwise create a
//rubber-band rectangle nd create a new ellipse.
BOOL bResult=pDoc->m_tracker.HitTest (point)!=
CRectTracker::hitNothing;
//Tracker rectangle changed so update views.
if (bResult)
{
pDoc->m_tracker.Track (this,point,TRue);
pDoc->SetModifiedFlag ();
pDoc->UpdateAllViews (NULL);
}
else
pDoc->m-tracker.TrackRubberBand (this,point,TRUE);
CView:: onLButtonDown (nFlags,point);
}
50、如何更新翻轉背景顔色的文本
調用CDC:: SetBkmode并傳送OPAQUE用目前的背景顔色填充背景,或者調用CDC::SetBkMode并傳送TRANSPAARENT使背景保持不變,這兩種方法都可以設定背景模式。下例設定背景模式為TRANSPARENT,可以兩次更新串,用花色帶黑陰影更新文本。黑色串在紅色串之後,但由于設定了背景模式仍然可見。
void CSampleView:: OnDraw (CDC* pDC)
{
//Determint size of view.
CRect rcView;
GetClientRect (rcVieew);
//Create sample string to display.
CString str (_T ("Awesome Shadow Text..."));
//Set the background mode to transparent.
pDC->SetBKMode (TRANSPARENT);
//Draw black shadow text.
rcView.OffsetRect (1, 1);
pDc->SetTextColor (RGB (0, 0, 0));
pDC->DrawText (str, str.GetLength (), rcView,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
//Draw red text.
rcView.OffsetRect (-1,-1);
pDc->SetTextColor (RGB (255, 0, 0));
pDC->DrawText (str, str.GetLength (), rcView,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
51、如何建立一個具有特定點大小的字型
可以指定字型邏輯機關的大小,但有時指定字型的點的大小可能會更友善一些。可以如下将字型的點轉換為字型的高度:
int nHeigth=mulDiv (nPointSize, -dc.GetDeviceCaps (LOGPIXELSY), 72);
下例建立了一個8點的Apial字型:
CClientDC dc (AqfxGetMainWnd ());
m_font. CreateFont (MulDiv (8, -dc.GetDeviceCaps (LOGPIXELSY),
72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,
OUT_STROKE_PRECIS,CLIP_STROKE_PRECIS,DRAFT_QUALITY,
VARIABLE_PITCH | FF-SWISS,_T ("Arial"));
52、如何計算一個串的大小
函數CDC:: Det text Extent根據目前選擇的字型計算一個串的高度和寬度。如果使用的不是系統字型而是其他字型,則在調用GetTextExtent之前将字型選進裝置上下文中是很重要的,否則計算高度和寬度時将依據系統字型,由此得出的結果當然是不正确的。下述樣闆程式當改變下壓按鈕的标題時動态調整按鈕的大小,按鈕的大小由按鈕的字型和标題的大小而定。響應消息WM_SETTEXT時調用OnSetText,該消息使用ON_MESSAE宏指令定義的使用者自定義消息。
LRESULT CMyButton:: OnSettext (WPARAM wParam, LPARAM lParam)
{
//Pass message to window procedure.
LRESULT bResult=CallWindowProc (*GetSuperWndProcAddr (),
m_hWnd, GetCurrentMessage () ->message,wParam,lParam);
//Get title of push button.
CString strTitle;
GetWindowText (strTitle);
//Select current font into device context.
CDC* pDC=GetDc ();
CFont*pFont=GetFont ();
CFont*pOldFont=pDC->SelectObject (pFont);
//Calculate size of title.
CSize size=pDC->GetTextExent (strTitle,strTitle.GetLength ());
//Adjust the button's size based on its title.
//Add a 5-pixel border around the button.
SetWindowPos (NULL, 0, 0, size.cx+10, size.cy+10,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
//Clean up.
pDC->SelectFont (pOldFont);
ReleaseDC (pDC);
return bResult;
}
53、如何顯示旋轉文本
隻要使用者使用TrueType或者GDI筆或字型就可以顯示旋轉文本(有些硬體裝置也支援旋轉光栅字型)。LOGFONT結構中的ifEscapement成員指定了文本行和x軸的角度,角度的機關是十分之一度而不是度,例如,ifEscapement為450表示字型旋轉45度。為確定所有的字型沿坐标系統的同一方向旋轉,一定要設定ifEscapement成員的CLIP_LH_ANGLES位,否則,有些字型可能反向旋轉。下例使用了14點Arial字型每間隔15度畫一個串。
void CSampleView:: OnDraw (CDC* pDC)
{
//Determine the size of the window.
CRect rcClient;
GetClientRect (rcClient);
//Create sample string.
CString str (_T ("Wheeee...I am rotating!"));
//Draw transparent, red text.
pDC->SetBkMode (TRANSPARENT);
pDC->SetTextColor (RGB (255,0,0));
CFont font; //font object
LOGFONT stFont; //font definition
//Set font attributes that will not change.
memset (&stFont, 0, sizeof (LOGFONT));
stFont.ifheight=MulDiv (14, -pDC->GetDeviceCaps (LOGPIXELSY), 72);
stFont.ifWeight=FW_NORMAL;
stFont.ifClipPrecision=LCIP_LH_ANGLES;
strcpy (stFont.lfFaceName, "Arial");
//Draw text at 15degree intervals.
for (int nAngle=0; nAngle<3600; nAngle+=150)
{
//Specify new angle.
stFont.lfEscapement=nAngle;
//Create and select font into dc.
font.CreateFontIndirect (&stfont);
CFont* pOldFont=pDC->SelectObject (&font);
//Draw the text.
pDC->SelectObject (pOldFont);
font.DelectObjext ();
}
}
54、如何正确顯示包含标簽字元的串
調用GDI文本繪畫函數時需要展開标簽字元,這可以通過調用CDC:: TabbedTextOut或者CDC:: DrawText并指定DT_EXPANDTABS标志來完成。TabbedTextOut函數允許指定标簽位的數組,下例指定每20裝置機關展開一個标簽:
void CSampleView:: OnDraw (CDC* pDC)
{
CTestDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoC);
CString str;
str.Format (_T ("Cathy/tNorman/tOliver"));
int nTabStop=20; //tabs are every 20 pixels
pDC->TabbedtextOut (10, 10, str, 1, &nTabStop, 10);
}
55、串太長時如何在其末尾顯示一個省略号
調用CDC:: DrawText并指定DT_END_ELLIPSIS标志,這樣就可以用小略号取代串末尾的字元使其适合于指定的邊界矩形。如果要顯示路徑資訊,指定DT_END_ELLIPSIS标志并省略号取代串中間的字元。
void CSampleView:: OnDraw (CDC* pDC)
{
CTestDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoc);
//Add ellpsis to end of string if it does not fit
pDC->Drawtext (CString ("This is a long string"),
CRect (10, 10, 80, 30), DT_LEFT | DT_END_ELLIPSIS);
//Add ellpsis to middle of string if it does not fit
pDC->DrawText (AfxgetApp () ->m_pszhelpfilePath,
CRect (10, 40, 200, 60), DT_LEFT | DT_PATH_ELLIPSIS);
}
56、如何快速地格式化一個CString對象
調用CString:: Format,該函數和printf函數具有相同的參數,下例說明了如何使用Format函數:
//Get size of window.
CRect rcWindow;
GetWindowRect (rcWindow);
//Format message string.
CString strMessage;
strMessage.Format (_T ("Window Size (%d, %d)"),
rcWindow.Width (), rcWindow.Height ());
//Display the message.
MessageBox (strmessage);
為什麼即使調用EnableMenuItem菜單項後,菜單項還處于禁止狀态
需要将CFrameWnd:: m_bAutomenuEnable設定為FALSE,如果該資料成員為TRUE(預設值),工作框将自動地禁止沒有ON_UPDATE_COMMAND_UI或者ON_COMMAND的菜單項。
//Disable MFC from automatically disabling menu items.
m_bAuoMenuEnable=FALSE;
//Now enable the menu item.
CMenu* pMenu=GetMenu ();
ASSERT_VALID (pMenu);
pMenu->EnableMenuItem (ID_MENU_ITEM,MF_BYCOMMAND | MF_ENABLED);
58、如何給系統菜單添加一個菜單項
給系統菜單添加一個菜單項需要進行下述三個步驟:
首先,使用Resource Symbols對話(在View菜單中選擇Resource Symbols...
可以顯示該對話)定義菜單項ID,該ID應大于0x0F而小于0xF000;
其次,調用CWnd::GetSystemMenu擷取系統菜單的指針并調用CWnd:: Appendmenu将菜單項添加到菜單中。下例給系統菜單添加兩個新的菜單項:
int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct)
{
…
//Make sure system menu item is in the right range.
ASSERT (IDM_MYSYSITEM &0xFFF0)==IDM_MYSYSITEM);
ASSERT (IDM-MYSYSITEM<0xF000);
//Get pointer to system menu.
CMenu* pSysmenu=GetSystemmenu (FALSE);
ASSERT_VALID (pSysMenu);
//Add a separator and our menu item to system menu.
CString StrMenuItem (_T ("New menu item"));
pSysMenu->Appendmenu (MF_SEPARATOR);
pSysMenu->AppendMenu (MF_STRING, IDM_MYSYSITEM, strMenuitem);
…
}
現在,選擇系統菜單項時使用者應進行檢測。使用ClassWizard處理
WM_SYSCOMMAND消息并檢測使用者菜單的nID參數:
void CMainFrame:: OnSysCommand (UINT nID,LPARAM lParam)
{
//Determine if our system menu item was selected.
if ( (nID & 0xFFF0)==IDM_MYSYSITEM)
{
//TODO-process system menu item
}
else
CMDIFrameWnd:: OnSysCommand (nID, lParam);
}
最後,一個設計良好的UI應用程式應當在系統菜單項加亮時在狀态條顯示一個幫助資訊,這可以通過增加一個包含系統菜單基ID的串表的入口來實作。
59、如何确定頂層菜單所占據的菜單行數
這可以通過簡單的減法和除法來實作。首先,使用者需要計算主框視窗的高度和客戶區;其次,從主框視窗的高度中減去客戶區、框邊界以及标題的高度;最後,除以菜單欄的高度。下例成員函數是一個計算主框菜單所占據的行數的代碼實作。
int CMainFrame:: GetMenuRows ()
{
CRect rcFrame,rcClient;
GetWindowRect (rcFrame);
GetClientRect (rcClient);
return (rcFrame.Height () -rcClient.Height ()-
:: GetSystemMetrics (SM_CYCAPTION) -
(:: getSystemMetrics (SM_CYFRAME) *2)) /
:: GetSystemMetrics (SM_CYMENU);
}
60、在使用者環境中如何确定系統顯示元素的顔色
調用SDK函數GetSysColor可以擷取一個特定顯示元素的顔色。下例說明了如何在MFC函數CMainFrameWnd:: OnNcPaint中調用該函數設定視窗标題顔色。
void CMiniFrameWnd:: OnNcPaint ()
{
…
dc.SetTextColor (:: GetSysColor (m_bActive ?
COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
…
}
61、如何查詢和設定系統參數
在Windows 3.1 SDK中介紹過SDK函數SystemParametersInfo,調用該函數可以查詢和設定系統參數,諸如按鍵的重複速率設定、滑鼠輕按兩下延遲時間、圖示字型以及桌面覆寫位圖等等。
//Create a font that is used for icon titles.
LOGFONT stFont;
:: SystemParametersInfo (SPIF_GETICONTITLELOGFONT,
sizeof (LOGFONT), &stFont, SPIF_SENDWININICHANGE);
m_font.CreateFontIndirect (&stFont);
//Change the wallpaper to leaves.bmp.
:: SystemParametersInfo (SPI_SETDESKWALLPAPER, 0,
_T (" forest.bmp"), SPIF_UPDATEINIFILE);
62、如何使用一個預定義的Windows光标
調用CWinApp:: LoadStandardCursor并傳送光标辨別符。
BOOL CSampleDialog:: OnSetCursor (CWnd* pWnd, UINT nHitTest, UINT message)
{
//Display wait cursor if busy.
if (m_bBusy)
{
SetCursor (AfxGetApp () ->LoadStandardCursor (IDC_WAIT));
return TRUE;
}
return CDialog:: OnSetCursor (pWnd. nHitTest,message);
}
63、如何确定目前螢幕分辨率
調用SDK函數GetSystemMetrics,該函數可以檢索有關windows顯示資訊,諸如标題大小、邊界大小以及滾動條大小等等。
//Initialize CSize object with screen size.
CSize sizeScreen (GetSystemMetrics (SM_CXSCREEN),
GetSystemMetrics (SM_CYSCREEN));
64、如何檢索原先的Task Manager應用程式使用的任務清單
原先的Task Manager應用程式顯示頂層視窗的清單。為了顯示該清單,視窗
必須可見、包含一個标題以及不能被其他視窗擁有。調用CWnd:: GetWindow可以
檢索頂層視窗的清單,調用IsWindowVisible、GetWindowTextLength以及GetOwner
可以确定視窗是否應該在清單中。下例将把TaskManager視窗的标題填充到清單中。
void GetTadkList (CListBox&list)
{
CString strCaption; //Caption of window.
list.ResetContent (); //Clear list box.
//Get first Window in window list.
ASSERT_VALID (AfxGetMainWnd ());
CWnd* pWnd=AfxGetMainWnd () ->GetWindow (GW_HWNDFIRST);
//Walk window list.
while (pWnd)
{
// I window visible, has a caption, and does not have an owner?
if (pWnd ->IsWindowVisible () &&
pWnd ->GetWindowTextLength () &&! pWnd ->GetOwner ())
{
//Add caption o window to list box.
pWnd ->GetWindowText (strCaption);
list.AddString (strCaption);
}
//Get next window in window list.
pWnd=pWnd->GetWindow (GW_HWNDNEXT);
}
}
65、如何确定Windows和Windows系統目錄
有兩個SDK函數可以完成該功能。GetWindowsDirectory和GetSystemDirectory,下例說明了如何使用這兩個函數:
TCHAR szDir [MAX_PATH];
//Get the full path of the windows directory.
:: GetWindowsDirectory (szDir, MAX_PATH);
TRACE ("Windows directory %s/n", szDir);
//Get the full path of the windows system directory.
:: GetSystemDirectory (szDir, MAX_PATH);
TRACE ("Windows system directory %s/n", szDir);
66、在哪兒建立臨檔案
調用SDK函數GetTemPath可以确定臨時檔案的目錄,該函數首先為臨時路徑檢測TMP環境變量:如果沒有指定TMP,檢測TMP環境變量,然後傳回到目前目錄。下例說明了如何建立一個臨時檔案。
…
//get unique temporary file.
CString strFile;
GetUniqueTempName (strFile);
TRY
{
//Create file and write data.Note that file is closed
//in the destructor of the CFile object.
CFile file (strFile,CFile:: modeCreate | CFile:: modeWrite);
//write data
}
CATCH (CFileException, e)
{
//error opening file
}
END_CATCH
…
Void GetuniqueTempName (CString& strTempName)
{
//Get the temporary files directory.
TCHAR szTempPath [MAX_PATH];
DWORD dwResult=:: GetTempPath (MAX_PATH, szTempPath);
ASSERT (dwResult);
//Create a unique temporary file.
TCHAR szTempFile [MAX_PATH];
UINT nResult=GetTempFileName (szTempPath, _T ("~ex"),0,szTempfile);
ASSERT (nResult);
strTempName=szTempFile;
}
67、如何通路桌面視窗
靜态函數CWnd:: GetDesktopWindow傳回桌面視窗的指針。下例說明了MFC函數CFrameWnd::BeginModalStae是如何使用該函數進入内部視窗清單的。
void CFrameWnd::BeginModalState ()
{
…
//first count all windows that need to be disabled
UINT nCount=0;
HWND hWnd=:: GetWindow (:: GetDesktopWindow (), GW_CHILD);
while (hWnd!=NULL)
{
if (:: IsWindowEnabled (hwnd) &&
CWnd::FromHandlePermanent (hWnd)!=NULL &&
AfxIsDescendant (pParent->m_hWnd, hWnd) &&
:: SendMessage (hWnd, WM_DISABLEMODAL, 0, 0)==0)
{
++nCount;
}
hWnd=:: GetWindow (hWnd, GW_HWNDNEXT);
}
…
}