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

/* 你可以通過如下代碼來獲得文本的大小:
(A)獲得被使用的字體 */

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);
/*
(B) 獲得菜單項的文本: */
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);
}
/*此時,size.cy即爲高度,size.cx爲寬度,你可以給菜單加上自定義的高度和寬度,通過比較,我發現寬度爲4

比較合適。*/


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


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章