天天看點

vc常用技巧總結

http://www.vczx.com/forum/showthread.php?s=&threadid=7197

vc常用技巧總結

(1) 如何通過代碼獲得應用程式主視窗的 指針

主視窗的 指針儲存在CWinThreadm_pMainWnd中,調用AfxGetMainWnd實作。

AfxGetMainWnd() -ShowWindow(SW_SHOWMAXMIZED)

使程式最大化.

(2) 确定應用程式的路徑

Use GetModuleFileName 獲得應用程式的路徑,然後去掉可執行檔案名。

Example

TCHAR

exeFullPath[MAX_PATH]  MAX_PATH在API中定義了吧,好象是

128

GetModuleFileName(NULL,exeFullPath,MAX_PATH)

(3) 如何在程式中獲得其他程式的 圖示

兩種方法

(1) SDK函數 SHGetFileInfo 或使用 ExtractIcon獲得圖示資源的 handle,

(2) SDK函數 SHGetFileInfo 獲得有關檔案的很多資訊,如大小圖示,屬性, 類型等.

Example(1)

在程式視窗左上角顯示 NotePad圖示.

void CSampleView

OnDraw(CDC  pDC)

{

if(  SHGetFileInfo(_T(cpwin95notepad.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目錄 Use GetWindowsDirectory

Windows下的system目錄 Use GetSystemDirectory

temp目錄 Use GetTempPath

目前目錄 Use GetCurrentDirectory

請注意前兩個函數的第一個參數為目錄變量名,後一個為緩沖區後兩個相反.

(5) 如何自定義消息

1) 手工定義消息,可以這麼寫

#define WM_MY_MESSAGE(WM_USER+100),

MS 推薦的至少是 WM_USER+100

(2)寫消息處理函數,用

WPARAM,LPARAM傳回LRESULT.

LRESULT CMainFrameOnMyMessage(WPARAM wparam,LPARAM lParam)

{

temp目錄 Use GetTempPath

加入你的處理函數 irectory

}

(6) 如何改變視窗的圖示

向視窗發送 WM_SECTION消息。

Example

HICON hIcon=AfxGetApp() -LoadIcon(IDI_ICON)

ASSERT(hIcon)

AfxGetMainWnd() -SendMessage(WM_SECTION,TRUE,(LPARAM)hIcon)

(7) 如何改變視窗的預設風格

重載 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_CXSCREEN2)

cs.cy=GetSystemMetrics(SM_CYSCREEN2)

return CMDIFramewnd PreCreateWindow(cs)

}

(8) 如何将視窗居中顯示

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( )

(9) 如何讓視窗和 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函數中的 CWndShow Window來指定 MDI Child Window的風格。

(10) 如何限制視窗的大小

也就是 FixedDialog形式。 Windows發送 WM_GETMAXMININFO消息來跟蹤, 響應它,在 OnGetMAXMININFO 中寫代碼

(11) 如何使視窗不可見?

很簡單,用SW_HIDE 隐藏視窗,可以結合 FindWindow,ShowWindow控制.

(12) 如何建立一個字回繞的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

}

(13) 如何使程式保持極小狀态

這麼辦 在恢複程式窗體大小時,Windows會發送WM_QUERY-OPEN消息,用 ClassWizard設定成員函數

OnQueryOpen() ,add following code

Bool CMainFrame OnQueryOpen( )

{

Return false

}

(14) 移動視窗

調用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)

(15) 通用控件的顯示視窗

MFC提供了幾個CView派生的視窗類, 封裝了通用控件的功能,但仍然使用工作框文檔顯示視窗體系結構:CEditView封裝了編輯控件,CTreeView保持了樹清單控件,CListView封裝了清單顯示視窗控件,CRichEditView可以處理多種編輯控件。

(16) 重置視窗的大小

調用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 )

(17) 如何單擊除了視窗标題欄以外的區域使視窗移動

當視窗需要确定滑鼠位置時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

) )

}

(18) 如何改變視窗的背景顔色

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

}

(19) 如何改變視窗标題

調用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 )

}

}

(20) 如何防止主框視窗在其說明中顯示活動的文檔名

建立主框視窗和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來設定标題。記住自己設定标題時要遵循接口風格指南

(21) 如何擷取有關視窗正在處理的目前消息的資訊

調用CWnd  GetCurrentMessage可以擷取一個MSG指針。例如,可以使用ClassWizard将幾個菜單項處理程式映射到一個函數中,然後調用GetCurrentMessage來确定所選中的菜單項。

viod CMainFrame   OnCommmonMenuHandler ( )

{

Display selected menu item in debug window .

TRACE (Menu item %u was selected . n ,

(22) 如何在代碼中擷取工具條和狀态條的指針

預設時, 工作框建立狀态條和工具條時将它們作為主框視窗的子視窗,狀态條有一個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)

(23) 如何使能和禁止工具條的工具提示

如果設定了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 )

}

(24) 如何建立一個不規則形狀的視窗

可以使用新的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 = nUnits3  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 ( ( (nIndexbyRed ) 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 thewindow .

UINT nHitTest = CDialog   OnNcHitTest (point)

rerurn (nHitTest = = HTCLIENT) HTCAPTION nHitTest

}

(25) 如何擷取應用程式的 執行個體句柄

應用程式的執行個體句柄儲存在CWinApp m_hInstance 中,可以這麼調用AfxGetInstancdHandle獲得句柄.

Example HANDLE hInstance=AfxGetInstanceHandle()

(26) 如何程式設計結束應用程式

這是個很簡單又是程式設計中經常要遇到的問題.

向視窗發送 WM_CLOSE消息,調用 CWndOnClose成員函數.允許對使用者提示是否儲存修改過的資料.

Example AfxGetMainWindow()-SendMessage(WM_CLOSE)

還可以建立一個自定義的函數 Terminate Window

void Terminate Window(LPCSTR pCaption)

{

CWnd pWnd=CwndFindWindow(NULL,pCaption)

if (pWnd)

pWnd -SendMessage(WM_CLOSE)

}

說明 FindWindow函數不是提倡的做法,因為它無法處理标題欄自動改變,比如我們要檢測 Notepad是不是已運作而事先不知道Notepad的标題欄,這時FindWindow就無能為力了,可以通過枚舉 windows任務清單的辦法來實作。在機械出版社Windows 95 API開發人員指南一書有比較詳細的介紹,這裡就不再多說樂。

(27) 如何建立和使用無模式對話框

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) Destroy ( )

Create the modeless dialog . represents this dialog.

BOOL bResult = pDialog — Creste (IDD_IDALOG)

ASSERT (bResult )

}

(28) 如何防止主框視窗在其說明中顯示活動的文檔名

建立主框視窗和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來設定标題。記住自己設定标題時要遵循接口風格指南。

(29) 如何在代碼中擷取工具條和狀态條的指針

預設時, 工作框建立狀态條和工具條時将它們作為主框視窗的子視窗,狀态條有一個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)

(30) 怎樣加載其他的應用程式

三個SDK函數 winexec, shellexecute,createprocess可以使用。

WinExec最簡單,兩個參數,前一個指定路徑,後一個指定顯示方式.後一個參數值得說一下,比如泥用 SW_SHOWMAXMIZED方式去加載一個無最大化按鈕的程式,就是Neterm,calc等等,就不會出現正常的窗體,但是已經被加到任務清單裡了。

ShellExecute較 WinExex靈活一點,可以指定工作目錄,下面的Example就是直接打開 ctemp1.txt,而不用加載與 txt檔案關聯的應用程式,很多安裝程式完成後都會打開一個視窗,來顯示Readme or Faq,我猜就是這麼作的啦.

ShellExecute(NULL,NULL,_T(1.txt),NULL,_T(ctemp),SW_SHOWMAXMIZED)

CreateProcess最複雜,一共有十個參數,不過大部分都可以用NULL代替,它可以指定程序的安全屬性,繼承資訊,類的優先級等等.來看個很簡單的Example

STARTUPINFO stinfo

啟動視窗的資訊

PROCESSINFO procinfo 程序的資訊

CreateProcess(NULL,_T(notepad.exe),NULL,NULL.FALSE,

NORMAL_PRIORITY_

CLASS,NULL,NULL, &stinfo,&procinfo)

(31) 如何在代碼中擷取工具條和狀态條的指針

預設時, 工作框建立狀态條和工具條時将它們作為主框視窗的子視窗,狀态條有一個AFX_IDW_STATUS_BAR辨別符,工具條有一個AFX_IDW_TOOLBAR辨別符,下例說明了如何通過一起調用CWnd  GetDescendantWindow和AfxGetMainWnd來擷取這些子視窗的指針:

Get pointer to status bar .

CStatusBar  pStatusBar = (CStatusBar ) AfxGetMainWnd ( )

— GetDescendantWindow(AFX_IDW_STUTUS_BAR)

(32) 如何使能和禁止工具條的工具提示

如果設定了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 )

}

Get pointer to toolbar .

CToolBar  pToolBar = (CToolBar  ) AfxGetMainWnd ( )

— GetDescendantWindow(AFX_IDW_TOOLBAR)

(33) 如何設定工具條标題

工具條是一個視窗,是以可以在調用CWnd   SetWindowText來設定标題,例子如下:

int CMainFrame   OnCreate (LPCREATESTRUCT lpCreateStruct )

{

 Set the caption of the toolbar .

m_wndToolBar.SetWindowText (_T Standdard)

(34) 如何使視窗始終在最前方

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_NOSIZEWSP_NOMOVE)

}

(35) 如何在對話框中顯示一個位圖

這要歸功于Win 32先進的靜态控件和Microsoft的資源編輯器,在對話框中顯示位圖是很容易的, 隻需将圖形控件拖到對話中并選擇适當屬性即可,使用者也可以顯示圖示、位圖以及增強型元檔案。

(36) 如何改變對話或窗體視窗的背景顔色

調用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 , CWndpWnd , 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

)

}

(37) 如何擷取一個對話控件的指針

有兩種方法。其一,調用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對話。

(38) 如何禁止和使能控件

控件也是視窗,是以可以調用CWnd   EnableWindow使能和禁止控件。

Disable button controls .

m_wndOK.EnableWindow (FALSE )

m_wndApply.EnableWindow (FALSE )

(39) 如何改變控件的字型

由于控件是也是視窗,使用者可以調用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 )

}

(40) 如何在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 backgroundcolor .

pdc— FilllRect (rcBounds , &brushBack)

other drawign commands

}

(41) 在不使用通用檔案打開對話的情況下如何顯示一個檔案清單

調用CWnd  DlgDirList或者CWnd  DlgDirListComboBox,Windows 将自動地向清單框或組合框填充可用的驅動器名或者指定目錄中的檔案,下例将Windows目錄中的檔案填充在組合框中:

BOOL CSampleDig   OnInitDialog ( )

{

CDialog   OnInitDialog ( )

TCHAR szPath [MAX_PATH] = {cwindows}

int nReslt = DlgDirListComboBox (szPath, IDC_COMBO , IDC_CURIDIR, DDL_READWRITE |DDL_READONLY|DDL_HIDDEN| DDL_SYSTEM|DDL_ARCHIVE)

return TRUE

}

(42) 為什麼旋轉按鈕控件看起來倒轉

需要調用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 按鈕時拷貝的數目增加。

(43) 為什麼旋轉按鈕控件不能自動地更新它下面的編輯控件

如果使用旋轉按鈕的autu buddy特性, 則必須保證在對話的标記順序中buddy視窗優先于旋轉按鈕控件。從Layout菜單中選擇Tab Order菜單項(或者按下Crtl+D)可以設定對話的标簽順序。

(44) 如何用位圖顯示下壓按鈕

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 .

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

}

(45) 如何一個建立三态下壓按鈕

可以使用新的BS_PUSHBUTTON 風格位和檢測框以及按鈕來建立一個三态下壓按鈕。這很容易,隻需将檢測框和按鈕拖拉到對話中并指定屬性Push—like即可。不用任何附加程式就可以成為三态下壓按鈕。

(46) 如何動态建立控件

配置設定一個控件對象的執行個體并調用其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 )

(47) 如何限制編輯框中的準許字元

如果使用者在編輯控件中隻允許接收數字,可以使用一個标準的編輯控件并指定新的建立标志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 ))

}

(48) 如何改變控件的顔色

有兩種方法。其一,可以在父類中指定控件的顔色,或者利用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 ()

}

現在,控件可以自己決定如何繪畫,與父視窗無關。

(49) 當向清單框中添加多個項時如何防止閃爍

調用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 ()

(50) 如何向編輯控件中添加文本

由于沒有CEdit:: AppendText函數,使用者隻好自己做此項工作。調用CEdit:: SetSel移動到編輯控件末尾,然後調用CEdit:: ReplaceSel添加文本。下例是AppendText 的一種實作方法:

void CMyEdit:: AppendText (LPCSTR pText)

{

int nLen=GetWindowTextLength ()

SetFocus ()

SetSel (nLen, nLen)

ReplaceSel (pText)

}

(51) 如何通路預定義的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)

}

(52) 如何擷取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)

}

(53) 如何實作一個橡皮區矩形

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)

}

(54) 如何更新翻轉背景顔色的文本

調用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)

}

(55) 如何建立一個具有特定點大小的字型

可以指定字型邏輯機關的大小,但有時指定字型的點的大小可能會更友善一些。可以如下将字型的點轉換為字型的高度:

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"))

(56) 如何計算一個串的大小

函數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

}

(57) 如何顯示旋轉文本

隻要使用者使用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()

}

}

(58) 如何正确顯示包含标簽字元的串

調用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)

}

(59) 如何快速地格式化一個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)

(60) 串太長時如何在其末尾顯示一個省略号

調用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)

}

(61) 為什麼即使調用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)

(62) 如何給系統菜單添加一個菜單項

給系統菜單添加一個菜單項需要進行下述三個步驟:

首先,使用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的串表的入口來實作。

(63) 如何确定頂層菜單所占據的菜單行數

這可以通過簡單的減法和除法來實作。首先,使用者需要計算主框視窗的高度和客戶區;其次,從主框視窗的高度中減去客戶區、框邊界以及标題的高度;最後,除以菜單欄的高度。下例成員函數是一個計算主框菜單所占據的行數的代碼實作。

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)

}

(64) 在使用者環境中如何确定系統顯示元素的顔色

調用SDK函數GetSysColor可以擷取一個特定顯示元素的顔色。下例說明了如何在MFC函數CMainFrameWnd:: OnNcPaint中調用該函數設定視窗标題顔色。

void CMiniFrameWnd:: OnNcPaint ()

{

dc.SetTextColor (:: GetSysColor (m_bActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT))

(65) 如何查詢和設定系統參數

在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)

(66) 如何确定目前螢幕分辨率

調用SDK函數GetSystemMetrics,該函數可以檢索有關windows顯示資訊,諸如标題大小、邊界大小以及滾動條大小等等。

//Initialize CSize object with screen size.

CSize sizeScreen (GetSystemMetrics (SM_CXSCREEN),

GetSystemMetrics (SM_CYSCREEN))

(67) 如何使用一個預定義的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)

}

(68) 如何檢索原先的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)

}

}

(69) 如何确定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)

(70) 在哪兒建立臨檔案

調用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

}

(71) 我怎樣才能建立一個等待光标?

調 用 BeginWaitCursor 函 數 來 啟 動 等 待 光 标,調 用 EndWaitCursor 函 數 來 結 束 等 待 光 标。要 注 意,二 者 都 要 調 用 app 的 成 員 函 數,如 下 所 示:

AfxGetApp()->BeginWaitCursor();

// 要做的事

AfxGetApp()->EndWaitCursor();

(72) 我在MDI架構中有個 form 視窗。它有個取消按鈕,我需要當使用者按取消按鈕時可關閉form視窗。我應該如何關閉該文檔?

調 用 OnCloseDocument 函 數。

(73) 如何通路桌面視窗

靜态函數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)

}

(74) 什麼是COLORREF? 我該怎樣用它?

COLORREF 是 一 個 32-bit 整 型 數 值,它 代 表 了 一 種 顔 色。你 可 以 使 用 RGB 函 數 來 初 始 化 COLORREF。例 如:

COLORREF color = RGB(0, 255, 0);

RGB 函 數 接 收 三 個 0-255 數 值,一 個 代 表 紅 色, 一 個 代 表 綠 色, 一 個 代 表 藍 色。在 上 面的 例 子 中, 紅 色 和 藍 色 值 都 為 0,所 以 在 該 顔 色 中 沒 有 紅 色 和 藍 色。綠 色 為 最 大 值 255。所 以 該 顔 色 為 綠 色。0,0,0 為 黑 色,255,255,255 為 白 色。

另 一 種 初 始 化 COLORREF 的 方 法 如 下 所 示:

CColorDialog colorDialog;

COLORREF color;

if( colorDialog.DoModal() == IDOK )

{

color = colorDialog.GetColor();

}

這 段 代 碼 使 用 了 MFC 中 的 顔 色 對 話 框,它 需 要 文 件。

(75) AppWizard所産生的STDAFX檔案是幹什麼用的?

它 主 要 是 協 助 産 生 預 編 譯 頭 文 件 的。通 常 你 是 不 需 要 修 改 它 的。

(76) 我在我的程式中是了CDWordArray。我向它添加了約10,000個整數,這使得它變得非常非常慢。為什麼會這麼糟?

CDWordArray 是 很 好 用 的,隻 是 因 為 你 沒 有 指 定 數 組 的最大尺寸。因 此,當 你 添 加 新 元 素 時,該 類 會 從 堆 中 重 新 分 配 空 間。不 幸 的 是,該 類 會 在 每 次 插 入 新 元 素 時 都 為 數 組 重 新 分 配 空 間。如 果 你 向 它 添 加 了 很 多 新 元 素,所 有 這 些 分 配 和 複 制 數 組 的 操 作 會 就 會 使 它 變 慢。解 決 該 問 題 的 方 法 是,你 可 以 使 用 SetSize 函 數 的 第 二 個 參 數 來 改 變 這 種 重 新 分 配 的 頻 率。例 如,如 果 你 把 該 參 數 設 置 為 500,則 每 次 數 組 空 間 超 出 時 它 才 重 新 分 配 并 添 加 500 個 新 空 間,而 不 是 1 個。這 樣 一 來,你 就 可 以 不 用 重 新 分 配 而 添 加 了 另 外 499 個 元 素 空 間,這 也 會 大 大 提 高 程 序 的 運 行 速 度。

(77) 我該如何改變MDI架構視窗的子視窗的大小以使在視窗以一定的大小打開?

在 視 中 的 OnInitialUpdate 函 數 中 調 用 GetParentFrame 函 數。GetParentFrame 會 返 回 一 指 向 一 保 存 有 該 視 的 框 架 窗 口 的 指 針。然 後 調 用 在 框 架 窗 口 上 調 用 MoveWindow。

(78) 在我的程式的某些部分,我可以調用 MessageBox 函數來建立一個資訊對話框,例如在視類中。但是,在其它部分我卻不能,如文檔類中。為什麼?我怎樣才能在我的應用程式類中建立一個資訊對話框?

MessageBox 函 數 來 自 CWnd 類,所 以 你 隻 能 在 從 CWnd 繼 承 的 類 ( 如 CView ) 中 調 用 它。但 是,MFC 也 提 供 了 AfxMessageBox 函 數,你 可 以 在 任 何 地 方 調 用 它。

(79) 我需要在我的程式中設定全局變量,以使文檔中的所有類都能通路。我應該吧它放到哪兒?

把 該 變 量 放 到 該 應 用 程 序 類 的 頭 文 件 中 的 attribute 處。然 後,在 程 序 的 任 何 地 方,你 都 可 以 用 下 面 的 方 法 來 訪 問 該 變 量:

CMyApp *app = (CMyApp *)AfxGetApp();

app->MyGlobalVariable = ...

(80) 我聽說MFC可以發現記憶體漏洞,我怎樣使用該特性?

如 果 你 在 Debug 菜 單 中 的 Go 選 項 ( 不 是 Project 菜 單 中 的 Execute 選 項 ) 來 運 行 你 的 應 用 程 序,MFC 應 該 在 程 序 終 止 時 報 告 内 存 漏 洞。如 果 沒 有,那 麼 試 試 運 行 MFC Tracer 工 具 程 序 ( 在 VC++ 程 序 組 中 ),并 啟 動 跟 蹤。然 後 返 回 應 用 程 序。

(81) 我怎樣才能在我的應用程式中循環浏覽已經打開的文檔?

使用CDocTemplate中未公開的GetFirstDocPosition()和GetNextDoc()函數。

(82)才能在我的應用程式中循環浏覽已經打開的視?

使 用 CDocument 中 未 公 開 的 GetFirstViewPosition() 和 GetNextView() 函 數。

(83)數PreCreateWindow是幹什麼用的?

PreCreateWindow 允 許 你 在 調 用 CreateWindow 之 前 來 改 變 窗 口 屬 性。

(84)該怎樣防止MFC在視窗标題欄上把文檔名預置成應用程式名?

在 PreCreateWindow 函 數 中 删 除 FWS_PREFIXTITLE 标 志 的 窗 口 樣 式:

cs.style &= ~FWS_PREFIXTITLE;

(85) 我應該怎樣防止MFC在視窗标題欄上添加文檔名?

在 PreCreateWindow 函 數 中 删 除 FWS_ADDTOTITLE 标 志 的 窗 口 樣 式:

cs.style &= ~FWS_ADDTOTITLE ;

(86) 我應該如何改變視視窗的大小?

因 為 視 窗 口 實 際 上 是 框 架 窗 口 的 子 窗 口,所 以 你 必 須 改 變 框 架 窗 口 的 大 小,而 不 是 改 變 視 窗 口。使 用 CView 類 中 的 GetParentFrame() 函 數 獲 得 指 向 框 架 窗 口 的 指 針,然 後 調 用 MoveWindow() 函 數 來 改 變 框 架 的 大 小。這 會 使 變 尺 寸 的 視 充 滿 框 架 窗 口。

(87) 我有一無模式對話框。我怎樣才能在視窗退出時删除CDialog對象?

把“delete this”加 到 PostNcDestroy 中。這 主 要 用 在 需 要 自 動 删 除 對 象 的 場 合。

(88) 為什麼把“delete this”放在PostNcDestroy中而不是OnNcDestroy?

OnNcDestroy 隻 被 已 建 立 的 窗 口 調 用。如 果 建 立 窗 口 失 敗 ( 如 PreCreateWindow ),則 沒 有 窗 口 處 來 發 送 WM_NCDESTROY 消 息。PostNcDestroy 是 在 對 象 窗 口 被 完 全 删 除,在 OnNcDestroy 後,甚 至 在 窗 口 建 立 失 敗 之 後 調 用 的。

(89) File菜單中的MRU清單是從哪兒來的?清單中的名字放在哪兒了?我怎樣才能改變清單中項目的最大值?

在 應 用 程 序 類 的 InitInstance 函 數 中 對 LoadStdProfileSettings 的 調 用 中。該 調 用 接 受 一 個 參 數 ( 在 缺 省 情 況 下 如 果 沒 有 傳 遞 值 則 為 4 )。MRU 文 件 名 是 從 INI 文 件 中 調 用 的。如 果 你 有 帶 有 ID_FILE_MRU_FILE1 的 ID 的 菜 單 選 項,它 會 為 調 入 的 MRU 列 表 所 替 換。如 果 你 改 變 傳 遞 給 LoadStdProfileSettings 的 數 值 ( 最 大 為 16 ),則 你 就 改 變 了 所 裝 如 文 件 名 的 最 大 值。

(90) 我在菜單中添加了新的項。但是,當我選該項時,在狀态欄上沒有出現任何提示資訊。為什麼?

打 開 資 源 文 件 中 的 菜 單 模 闆。打 開 新 菜 單 選 項 的 屬 性 對 話 框。在 對 話 框 的 底 部 的 Prompt 編 輯 框 中 ,你 可 以 如 下 指 定 狀 态 欄 上 的 提 示 信 息 和 工 具 欄 上 的 提 示 信 息 ( 如 果 你 已 經 建 立 的 工 具 欄 按 鈕 ):

Status bar string/nFlying tag

(91) 我怎樣才能在應用程式的預設系統菜單中加上一些東西?

系 統 菜 單 與 其 它 菜 單 類 似,你 可 以 添 加 或 删 除 項 目,這 需 要 使 用 CMenu 類 的 成 員 函 數。下 面 的 代 碼 在 你 的 系 統 菜 單 後 面 添 加 一 個 新 菜 單 項:

CMenu *sysmenu;

sysmenu = m_pMainWnd->GetSystemMenu(FALSE);

sysmenu->AppendMenu(MF_STRING, 1000, "xxx");

參 見 MFC 幫 助 文 件 中 的 CMenu 類。

(92) 我建立了一個對話框。但是當我顯示該對話框時,第一個編輯框總是不能獲得焦點,我必須單擊它來使它獲得焦點。我怎樣才能使第一個編輯框在對話框打開時就獲得焦點?

打 開 資 源 編 輯 器 中 的 對 話 框 模 闆。在 Layout 菜單 中 選 擇 Tab Order 選 項。按 你 的 需 求 單 擊 對 話 框 中 的 控 制 來 重 新 排 列 這 些 控 制 的 tab 順 序。

(93) 我怎樣才能使一個視窗具有“always on top”特性?

在 調 用 OnFileNew 後,在 你 的 InitInstance 函 數 中 加 上 下 面 的 代 碼:

m_pMainWnd->SetWindowPos(&CWnd::wndTopMost,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);

(94) 我要為我的form view添加文檔模闆。我先建立了對話框模闆,然後使用ClassWizard建立了基于CFormView的新類,它也是從CDocument繼承來的。我還建立了相應的資源并在InitInstance中添加了新的文檔模闆。但是,當我試圖運作該程式時,出現了Assertion資訊。為什麼?

form 的 對 話 框 模 闆 需 要 些 特 殊 設 置 以 便 可 用 于 CFromView。确 保 這 些 設 置 的 最 簡 單 方 法 是 使 用 AppWizard 來 建 立 CFormView 應 用 程 序,并 查 看 AppWizard 所 建 立 的 對 話 框 模 闆 所 選 擇 的Styles Properties。你 會 發 現 該 對 話 框 模 闆 具 有 下 列 樣 式:沒 有 标 題 欄、不 可 見 和“Child”。把 你 的 form view 的 對 話 框 屬 性 變 成 這 樣 就 可 以 了。

(95) 我在一對話框中有一清單框,我需要tabbed清單框中的項目。但是,當我處理含有tab字元(用AddString添加的)的清單項時,tab被顯示成小黑塊而沒有展開。哪兒出錯了?

在 對 話 框 模 版 中,打 開 列 表 框 的 屬 性。确 保 選 擇 了“Use Tabstops” 樣 式。然 後,确 保 在 對 話 框 類 中 OnInitDialog 函 數 中 調 用 SetTabStops。

(96) 我建立了一個應用程式,并使用了CRecordset類。但是,當我運作該程式時,它試圖要通路資料庫,并給出“Internal Application Error”對話框。我應該怎樣做?

通 常 情 況 下,當 你 的 程 序 中 向 數 據 庫 發 送 信 息 的 SQL 語 句 出 現 問 題 時 才 出 現 該 對 話 框。例 如,參 見 下 面 的 例 子:

set.m_strFilter = "(ZipCode = '27111')";

如 果 ZipCode 列 被 定 義 為 字 符 串 時 不 會 出 現 問 題,如 果 定 義 為 long,則 會 出 現“Internal Application Error”對 話 框,這 是 由 于 類 型 不 匹 配 的 緣 故。如 果 你 删 除 27111 的 單 引 号,則 不 會 出 現 問 題。當 你 看 到“Internal Application Error”時,最 好 檢 查 一 下 試 圖 要 發 送 給 數 據 庫 的 SQL 語 句。

(97) 我用ClassWizard建立了一個類。但是,我把名字取錯了,我想把它從項目中删除,應該如何做?

在 ClassWizard 對 話 框 關 閉 後,用 文 件 管 理 器 删 除 新 類 的 H 和 CPP 文 件。然 後 打 開 ClassWizard,它 會 提 示 丢 失 了 兩 個 文 件,并 詢 問 你 該 如 何 做。你 可 以 選 擇 從 項 目 中 删 除 這 兩 個 問 的 按 鈕。

(98) 當我打開應用程式中的視窗時,我要傳遞該視窗的矩形尺寸。該矩形指定了視窗的外圍大小,但是當我調用GetClientRect時,所得到的尺寸要比所希望的值要小(因為工具欄和視窗邊框的緣故)。有其它方法來計算視窗的尺寸嗎?

參 見 CWnd::CalcWindowRect。

(99) 我在文檔類中設定了一個整型變量。但是,當我試圖把該變量寫入Serialize函數中的archive檔案中時,出現了類型錯誤。而文檔中的其它變量沒有問題。為什麼?

archive 類 隻 重 載 某 些 類 型 的 >> 和 << 操 作 符。“int”類 型 沒 有 在 其 中,也 許 是 因 為 int 變 量 在 Windows 3.1 與 Windows NT/95 有 所 不 同 的 緣 故 吧。“long”類 型 得 到 了 支 持,所 以 你 可 以 把 int 類 型 改 成 long 型。參 見 MFC 幫 助 文 件 中 CArchive 類。

(100) 如何控制菜單的大小?

我用MFC的CMenu生成了一個動态菜單(例如File,Edit,View...Help), 我想控制這個菜單的大小(長+高).

方法一:查找 WM_MEASUREITEM 和 MEASUREITEMSTRUCT.

方法二:查詢系統::GetSystemMetric(SM_CXMENUSIZE).

NONCLIENTMETRICS ncm;

HFONT hFontMenu;

SIZE size;

size.cy = size.cy = 0;

memset(&ncm, 0, sizeof(NONCLIENTMETRICS));

ncm.cbSize = sizeof(NONCLIENTMETRICS);

if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0))

{

hFontMenu = CreateFontIndirect(&ncm.lfMenuFont);

char szText[_MAX_PATH];

pMenu->GetMenuString(0, szText, _MAX_PATH, MF_BYPOSITION);

HFONT hFontOld;

HDC hDC;

hDC = ::GetDC(NULL);

hFontOld = (HFONT) ::SelectObject(hDC, hFontMenu);

GetTextExtentPoint32(hDC, szText, lstrlen(szText), &size);

SelectObject(hDC, hFontOld);

::ReleaseDC(NULL, hDC);

}

(101) 改變LVIS_SELECTED的狀态顔色?

我想将CListCtrl項和CTreeCtrl項在LVIS_SELECTED狀态時的顔色變灰.

方法一:查找函數CustomDraw,它是IE4提供的公共控制,允許有你自己的代碼.

方法二:生成一個draw控件,然後在DrawItem中處理文本顔色.

(102) 如何隻存儲文檔的某一部分?

我隻想存儲文檔的某一部分,能否象使用檔案一樣使用文檔?(也就是有定位函數).将每個CArchive類設定為CFile類的派生類,這樣你就能使用Seek等成員函數.

(103) 儲存工具條菜單有bug嗎?

使用浮動菜單條時,SaveBarState和LoadBarState出現了問題.如果菜單是浮動的,重起應用程式時它會出現在左上角,而它固定在螢幕其它位置時,下一次啟動就會出現在該位置,這是什麼原因?你試試這個PToolBar->Create(this,...,ID_MYTOOLBAR);

你的工具條需要包括id,而不是象預設的工具條那樣.

(104) Tip of the day的bug

我建立了一個簡單的mdi應用程式,使用.BSF(自定義的文檔擴充名)作為它的文檔我儲存一個foo.bsf文檔後,可以在資料總管中輕按兩下該檔案打開mdi應用程式同時打開foo.bsf文檔.但當我給mdi應用程式加上a tip of the day元件之後,從資料總管中輕按兩下foo.bsf後,就會給我一個警告:ASSERT(::IsWindow(m_hWnd)),然後mdi應用程式就死那了.

當從dde啟動應用程式(例如:輕按兩下相關文檔)時,"Tip of the Day"是有bug的.你可以看看函數"ShowTipAtStartup",它在"InitInstance"中調用,可以看到tip of the day作為一個模式對話框顯示,在處理其它消息時它一直進行消息循環你可心修改ShowTipAtStartup使其從dde啟動時不出現tip of the day.

void CTipOfApp::ShowTipAtStartup(void)

{

// CG: This function added by 'Tip of the Day' component.

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

if (

cmdInfo.m_bShowSplash &&

cmdInfo.m_nShellCommand != CCommandLineInf:FileDDE

)

{

CTipDlg dlg;

if (dlg.m_bStartup)

dlg.DoModal();

}

}

如果還有其它bug,你可以設定cmdInfo.m_nShellCommand的過濾.

(105) 如何可以讓我的程式可以顯示在其它的視窗上面?

讓使用者選擇"總是在最上面"最好是在系統菜單裡加入一個選項.可以通過修改WM_SYSCOMMAND消息來發送使用者的選擇.菜單的指令辨別(id)會作為一個參數傳給OnSysCommand().要定義辨別(id),将如下代碼加入到CMainFrame.CPP中:

#define WM_ALWAYSONTOP WM_USER + 1

将"總在最上面"的菜單項加入到系統菜單中,将如下代碼加入到函數CMainFrame::OnCreate()中:

CMenu* pSysMenu = GetSystemMenu(FALSE);

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, WM_ALWAYSONTOP,

"&Always On Top");

使用ClassWizard,加入對WM_SYSCOMMAND消息的處理,你應該改變消息過濾器,使用系統可以處理這個消息.

void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam)

{

switch ( nID )

{

case WM_ALWAYSONTOP:

if ( GetExStyle() & WS_EX_TOPMOST )

{

SetWindowPos(&wndNoTopMost, 0, 0, 0, 0,

SWP_NOSIZE | SWP_NOMOVE);

GetSystemMenu(FALSE)->CheckMenuItem(WM_ALWAYSONTOP,

MF_UNCHECKED);

}

else

{

SetWindowPos(&wndTopMost, 0, 0, 0, 0,

SWP_NOSIZE | SWP_NOMOVE);

GetSystemMenu(FALSE)->CheckMenuItem(WM_ALWAYSONTOP,MF_CHECKED);

}

break;

default:

CFrameWnd::OnSysCommand(nID, lParam);

}

}

(106) 如何控制視窗架構的最大最小尺寸?

要控制一個架構的的最大最小尺寸,你需要做兩件事情.在CFrameWnd的繼承類中處理消息WM_GETMINMAXINFO,結構MINMAXINFO設定了整個視窗類的限制,是以記住要考慮工具條,卷動條等等的大小.

// 最大最小尺寸的象素點 - 示例

#define MINX 200

#define MINY 300

#define MAXX 300

#define MAXY 400

void CMyFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)

{

CRect rectWindow;

GetWindowRect(&rectWindow);

CRect rectClient;

GetClientRect(&rectClient);

// get offset of toolbars, scrollbars, etc.

int nWidthOffset = rectWindow.Width() - rectClient.Width();

int nHeightOffset = rectWindow.Height() - rectClient.Height();

lpMMI->ptMinTrackSize.x = MINX + nWidthOffset;

lpMMI->ptMinTrackSize.y = MINY + nHeightOffset;

lpMMI->ptMaxTrackSize.x = MAXX + nWidthOffset;

lpMMI->ptMaxTrackSize.y = MAXY + nHeightOffset;

}

第二步,在CFrameWnd的繼承類的PreCreateWindow函數中去掉WS_MAXIMIZEBOX消息,否則在最大化時你将得不到預料的結果.

BOOL CMyFrameWnd::PreCreateWindow(CREATESTRUCT& cs)

{

cs.style &= ~WS_MAXIMIZEBOX;

return CFrameWnd::PreCreateWindow(cs);

}

(107) 如何改變視窗架構的顔色?

MDI架構的客戶區被另一個視窗的架構所覆寫.為了改變客戶區的背景色,你需要重畫這個客戶視窗.為了做到這點,你要處理消息WM_ERASEBKND産生一個新類,從CWnd繼承,姑且稱之為CMDIClient.給它加上一個成員變量,

#include "MDIClient.h"

class CMainFrame : public CMDIFrameWnd

{

...

protected:

CMDIClient m_wndMDIClient;

}

在CMainFrame中重載CMDIFrameWnd::OnCreateClient

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)

{

if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) )

{

m_wndMDIClient.SubclassWindow(m_hWndMDIClient);

return TRUE;

}

else

return FALSE;

}

然後就可以加入對消息WM_ERASEBKGND的處理了.

(108) 如何将應用程式視窗置于螢幕正中?

要将你的應用程式視窗放置在螢幕正中央,隻須在MainFrame的OnCreate函數中加入:

CenterWindow( GetDesktopWindow() );

繼續閱讀