VC中常見的108個問題

1 如何通過代碼獲得應用程序主窗口的指針?
主窗口的指針保存在CWinThread::m_pMainWnd,調用AfxGetMainWnd實現。
AfxGetMainWnd()->ShowWindow(SW_SHOWMAXMIZED)
//
使程序最大化.

2 確定應用程序的路徑
Use GetModuleFileName 獲得應用程序的路徑,然後去掉可執行文件名。
Example:
TCHAR exeFullPath[MAX_PATH] // MAX_PATH
MFC中定義爲260
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("c:\\pwin95\\notepad.exe"),0,
&stFileInfo,sizeof(stFileInfo),SHGFI_ICON))
{
  pDC ->DrawIcon(10,10,stFileInfo.hIcon);
}
}
Example(2):
同樣功能,Use ExtractIcon Function
void CSampleView::OnDraw(CDC *pDC)
{
  HICON hIcon=::ExtractIcon(AfxGetInstanceHandle(),_T("NotePad.exe"),0)

  if (hIcon && hIcon!=(HICON)-1))
    pDC->DrawIcon(10,10,hIcon);
}
說明獲得notepad.exe的路徑正規上來說用GetWindowsDirectory函數得到如果是調用win95下的畫筆,應該用訪問註冊表的方法獲得其路徑,要作成一個比較考究的程序,考慮應該全面點

4 獲得各種目錄信息
Windows目錄: 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 CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam)
{
  //
加入你的處理函數 
}

6 如何改變窗口的圖標?
向窗口發送 WM_SETICON消息。
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_CXSCREEN/2)
  cs.cy=GetSystemMetrics(SM_CYSCREEN/2)

  return CMDIFramewnd ::PreCreateWindow(cs)
}

8 如何將窗口居中顯示?
Call Function CWnd::CenterWindow

Example(1):
CenterWindow() //Relative to it's parent
Example(2):
CenterWindow(CWnd:: GetDesktopWindow( )) // Relative to Screen
AfxGetMainWnd()->CenterWindow()          //Relative to Application's MainWindow

9 如何讓窗口和 MDI窗口一啓動就最大化和最小化?
先說窗口。
 InitStance 函數中設定 m_nCmdShow的取值.
m_nCmdShow=SW_SHOWMAXMIZED //
最大化
m_nCmdShow=SW_SHOWMINMIZED //最小化
m_nCmdShow=SW_SHOWNORMAL //正常方式

MDI窗口:
如果是創建新的應用程序,可以用MFC AppWizardAdvanced按鈕並在MDI子窗口風格組中檢測最大化或最小化還可以重載MDI WindowPreCreateWindow函數,設置WS_MAXMIZE or WS_MINMIZE

如果從 CMDIChildWnd派生,調用 OnInitialUpdate函數中的CWnd::Show Window來指定MDI Child Window的風格。

10 如何限制窗口的大小?
也就是FixedDialog形式。Windows發送WM_GETMAXMININFO消息來跟蹤響應它, OnGetMAXMININFO中寫代碼.

11 如何使窗口不可見?
很簡單,SW_HIDE隱藏窗口,可以結合FindWindow,ShowWindow控制.

12 如何創建一個字迴繞的CEditView
重載CWnd::PreCreateWindow和修改CREATESTRUCT結構,關閉CEditView對象的ES_AUTOHSCROLLWS_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_QUERYOPEN消息,用ClassWizard設置成員函數OnQueryOpen(),添加如下代碼:
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, point);
  //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.
GetDlgItem(IDC_BUTTON)->SetWindowText(_T("Button new title "))
如果需要經常修改窗口的標題(注:控件也是窗口),應該考慮使用半文檔化的函數AfxSetWindowText。該函數在AFXPRIV.H中說明,在WINUTIL.CPP中實現,在聯機幫助中找不到它,它在AFXPRIV.H中半文檔化, 在以後發行的MFC中將文檔化。
AfxSetWindowText的實現如下:
voik AFXAPI AfxSetWindowText(HWND hWndCtrl, LPCTSTR IpszNew)
{
int nNewLen = strlen(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
    || strcmp(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::GetDescendantWindowAfxGetMainWnd來獲取這些子窗口的指針:
//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::GetBarStyleCControlBar::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 dc(this); // device context for painting.
//draw ellipse with out any border
dc.SelecStockObject(NULL_PEN);
//get the RGB colour components of the sphere color
COLORREF color= RGB( 0 , 0 , 255);
BYTE byRed =GetRValue (color);
BYTE byGreen = GetGValue(color);
BYTE byBlue = GetBValue (color);

// get the size of the view window
CRect rect;
GetClientRect(rect);

// get minimun number of units
int nUnits = min(rect.right, rect.bottom );

//calculate he horiaontal and vertical step size
float fltStepHorz = (float) rect.right /nUnits;
float fltStepVert = (float) rect.bottom /nUnits;


int nEllipse = nUnits/3 // calculate how many to draw
int nIndex;             // current ellipse that is being draw

CBrush brush;           // bursh used for ellipse fill color
CBrush *pBrushOld;      // previous brush that was selected into dc

//draw ellipse , gradually moving towards upper-right corner
for (nIndex = 0 nIndes < + nEllipse nIndes++)
{
//creat solid brush
brush.CreatSolidBrush(RGB(((nIndex*byRed)/nEllipse).((nIndex * byGreen)/nEllipse ), 
    ((nIndex * byBlue)/nEllipse)));

//select brush into dc
pBrushOld = dc.SelectObject(&brush);

//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消息,調用 CWnd::OnClose成員函數.允許對用戶提示是否保存修改過的數據.
Example: AfxGetMainWindow()->SendMessage(WM_CLOSE)

還可以創建一個自定義的函數 Terminate Window
void Terminate Window(LPCSTR pCaption)
{
CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption);

if (pWnd)

pWnd ->SendMessage(WM_CLOSE);
}

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

27 如何創建和使用無模式對話框
MFC將模式和無模式對話封裝在同一個類中,但是使用無模式對話需要幾個對話需要幾個額處的步驟。首先,使用資源編輯器建立對話資源並使用ClassWizard創建一個CDialog的派生類。模式和無模式對話的中止是不一樣的:模式對話通過調用CDialog::EndDialog 來中止,無模式對話則是調用CWnd::DestroyWindow來中止的,函數CDialog::OnOKCDialog::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->Create(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: : GetDescendantWindowAfxGetMainWnd來獲取這些子窗口的指針:
//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就是直接打開 c:\temp\1.txt,而不用加載與 txt文件關聯的應用程序,很多安裝程序完成後都會打開一個窗口,來顯示Readme or Faq,我猜就是這麼作的啦.

ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c:\\temp"),SW_SHOWMAXMIZED);

CreateProcess最複雜,一共有十個參數,不過大部分都可以用NULL代替,它可以指定進程的安全屬性,繼承信息,類的優先級等等.來看個很簡單的Example:
STARTUPINFO stinfo;   //
啓動窗口的信息
PROCESSINFO procinfo; //進程的信息

CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE,
NORMAL_PRIORITY_CLASS,NULL,NULL, &stinfo,&procinfo);

31 如何在代碼中獲取工具條和狀態條的指針
缺省時,工作框創建狀態條和工具條時將它們作爲主框窗口的子窗口,狀態條有一個AFX_IDW_STATUS_BAR標識符,工具條有一個AFX_IDW_TOOLBAR標識符,下例說明了如何通過一起調用CWnd: : GetDescendantWindowAfxGetMainWnd來獲取這些子窗口的指針:
//Get pointer to status bar .
CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STUTUS_BAR);

32 如何使能和禁止工具條的工具提示
如果設置了CBRS_TOOLTIPS風格位,工具條將顯示工具提示,要使能或者禁止工具提示,需要設置或者清除該風格位。下例通過調用CControlBar::GetBarStyleCControlBar::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_NOSIZE|WSP_NOMOVE);
}

35 如何在對話框中顯示一個位圖
這要歸功於Win32先進的靜態控件和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 , CWnd*pWnd , UINT nCtlColor)
{
// Determine if drawing a dialog box . If we are, return +handle to
//our own background brush . Otherwise let windows handle it .
if (nCtlColor = = CTLCOLOR _ DLG )
return (HBRUSH) m_brush.GetSafeHandle();
return CFormView::OnCtlColor(pDC, pWnd, nCtlColor);
}

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指針,要保證在控件撤消之前不能撤消字體對象。下例將下壓按鈕的字體改爲8Arial字體:
//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::GetFortColorCOleControl::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::DlgDirListComboBoxWindows 將自動地向列表框或組合框填充可用的驅動器名或者指定目錄中的文件,下例將Windows目錄中的文件填充在組合框中:
BOOL CSampleDig::OnInitDialog()
{
CDialog::OnInitDialog();
TCHAR szPath [MAX_PATH] = {"c:\\windows"};
int nReslt = DlgDirListComboBox(szPath, IDC_COMBO, IDC_CURIDIR, DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | DDL_ARCHIVE);
return TRUE;
}

42)爲什麼旋轉按鈕控件看起來倒轉
需要調用CSpinCtrl::SetRange 設置旋轉按鈕控件的範圍,旋轉按鈕控件的缺省上限爲0,缺省下限爲100,這意味着增加時旋轉按控件的值由100變爲0。下例將旋轉按鈕控件的範圍設置爲0100
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_BITMAPBS_ICON,要想具有位圖按鈕,創建按鈕和調用CButton::SetBitmapCButton::SetIcon時要指定BS_BITMAPBS_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::GetTextExtent 根據當前選擇的字體計算一個串的高度和寬度。如果使用的不是系統字體而是其他字體,則在調用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軸的角度,角度的單位是十分之一度而不是度,例如,ifEscapement450表示字體旋轉45度。爲確保所有的字體沿座標系統的同一方向旋轉,一定要設置ifEscapement成員的CLIP_LH_ANGLES位,否則,有些字體可能反向旋轉。下例使用了14Arial字體每間隔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可以檢索頂層窗口的列表,調用IsWindowVisibleGetWindowTextLength以及GetOwner可以確定窗口是否應該在列表中。下例將把TaskManager窗口的標題填充到列表中。

void GetTaskList(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)如何確定WindowsWindows系統目錄
有兩個SDK函數可以完成該功能。GetWindowsDirectoryGetSystemDirectory,下例說明了如何使用這兩個函數:

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_FILE1ID的菜單選項,它會爲調入的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對話框關閉後,用文件管理器刪除新類的HCPP文件。然後打開ClassWizard,它會提示丟失了兩個文件,並詢問你該如何做。你可以選擇從項目中刪除這兩個文件的按鈕。


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

參見 CWnd::CalcWindowRect

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

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

(100)     如何控制菜單的大小?
我用MFCCMenu生成了一個動態菜單(例如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?
使用浮動菜單條時,SaveBarStateLoadBarState出現了問題.如果菜單是浮動的,重起應用程序時它會出現在左上角,而它固定在屏幕其它位置時,下一次啓動就會出現在該位置,這是什麼原因?

你試試這個PToolBar->Create(this,...,ID_MYTOOLBAR);
你的工具條需要包括id,而不是象默認的工具條那樣.

(104)      Tip of the daybug

我創建了一個簡單的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)       如何將應用程序窗口置於屏幕正中?

要將你的應用程序窗口放置在屏幕正中央,只須在MainFrameOnCreate函數中加入:
CenterWindow(GetDesktopWindow());

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