Visual C++程式設計技巧中的這些問題可能經常被人問到,現在列出來供大家參考,歡迎大家一起來完善之。 1. 如何擷取應用程式的執行個體句柄? 應 用程式的 執行個體句柄儲存在CWin AppIm_hInstance 中,可以這麼調用AfxGetInstancdHandle獲得句柄Example: HANDLE hInstance=AfxGetInstanceHandle(); 2. 如何通過代碼獲得應用程式主視窗的指針? 主視窗的 指針儲存在CWinThread::m_pMainWnd中,調用 AfxGetMainWnd實作。
AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //使程式最大化。 3. 如何在程式中獲得其他程式的圖示? 兩種方法:
(1) SDK函數 SHGetFileInfo 或使用 ExtractIcon獲得圖示資源的 handle,
(2) SDK函數 SHGetFileInfo獲得有關檔案的 很多資訊,如大小圖示,屬性,類型等。
Example(1): 在程式視窗左上角顯示 NotePad圖示。
void CSampleV iew: 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 的路徑正規上來說用Get WindowsDirectory 函數得到,如果是調用 win95下的畫筆,應該用通路系統資料庫的方法獲得其路徑,要作成一個比較考究的程式,考慮應該全面點。 4. 如何程式設計結束應用程式?如何程式設計控制windows 的重新開機? 這是個很簡單又是程式設計中經常要遇到的問題。 第一問,向視窗發送 WM_CLOSE消息,調用 CWnd::OnClose成員函數。允許對使用者提示是否儲存修改過的資料。
Example: AfxGetMainWindow()->SendMessage(WM_CLOSE);
還可以建立一個自定義的函數 Terminate Window
void Terminate Window(L PCSTR p Caption)
{
CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption);
if (pWnd)
pWnd ->SendMessage(WM_CLOSE);
}
說明: FindWindow 函數不是提倡的做法,因為它無法處理标題欄自動改變,比如我們要檢測 Notepad 是不是已運作而事先不知道Notepad 的标題欄,這時 FindWindow 就無能為力了,可以通過枚舉 windows 任務清單的辦法來實作。 在 機械出版社"Windows 95API開發人員指南"一書有比較詳細的介紹,這裡就不再多說樂。 第二問,Use ExitWindowsEx Function 函數控制系統是重新開機,還是重新開機 windows。
前面已經有人講過了,就不再提了。 5. 怎樣加栽其他的應用程式? 我記得這好象是出場頻度很高的問題。
三個SDK函數 winexec, shellexecute,create process可以使用。
WinExec 最簡單,兩個參數,前一個指定路徑,後一個指定顯示方式。後一個參數值得說一下,比如泥用 SW_SHOWMAXMIZED 方式去加栽一個無最大化按鈕的 程式,呵呵就是Neterm,calc 等等,就不會出現正常的 窗體,但是已經被加到任務清單裡了。
ShellExecute 較 WinExex靈活一點,可以指定工作目錄,下面的 Example就是直接打開c:/temp/1.txt,而不用加栽與 txt 檔案關聯的應用程式,很多安裝程式完成後都會打開一個視窗,來顯示Readme or Faq,偶猜就是這麼作的啦。
ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c://temp"),SW_SHOWMAXMIZED);
CreateProcess最複雜,一共有十個參數,不過大部分都可以用NULL 代替,它可以指定程序的安全屬性,繼承資訊,類的優先級等等。來看個很簡單的 Example:
STARTUPINFO stinfo; //啟動視窗的資訊
PROCESSINFO procinfo; //程序的資訊
CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE, NORMAL_PRIORITY_
CLASS,NULL,NULL, &stinfo,&procinfo); 6. 确定應用程式的路徑 前些天好象有人問過這個問題。
Use GetModuleFileName 獲得應用程式的路徑,然後去掉可執行檔案名。
Example:
TCHAR exeFullPath[MAX_PATH]; // MAX_PATH在API中定義了吧,好象是128
GetModuleFileName(NULL,exeFullPath,MAX_PATH) 7. 獲得各種目錄資訊 Windows目錄: Use "GetWindowsDirectory“
Windows下的system目錄: Use "GetSystemDirectory"
temp目錄: Use "GetTempPath "
目前目錄: Use "GetCurrentDirectory"
請注意前兩個函數的第一個參數為 目錄變量名,後一個為緩沖區; 後兩個相反。 8. 如何自定義消息 也有人問過的,其實不難。
(1) 手工定義消息,可以這麼寫 #define WM_MY_MESSAGE(WM_USER+100), MS 推薦的至少是 WM_USER+100;
(2)寫消息處理函數,用 WPARAM,LPARAM傳回LRESULT。
LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam)
{
//加入你的處理函數
}
(3) 在類的 AFX_MSG處進行聲明,也就是常說的"宏映射" 9. 如何改變視窗的圖示? 向視窗發送 WM_SECTION消息。
Example:
HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON);
ASSERT(hIcon);
AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM) hIcon); 10. 如何改變視窗的預設風格? 重栽 CWnd:: PreCreateWindow 并修改CREATESTRUCT 結構來指定視窗風格和其他建立資訊。
Example: Delete "Max" Button and Set Original Window's Position and Size
BOOL CMainFrame:: PreCreateWindow (CREATESTRUCT &cs)
{
cs.style &=~WS_MAXINIZEMOX;
cs.x=cs.y=0;
cs.cx=GetSystemMetrics(SM_CXSCREEN/2);
cs.cy=GetSystemMetrics(SM_CYSCREEN/2);
return CMDIFramewnd ::PreCreateWindow(cs);
} 11. 如何将視窗居中顯示? Easy, Call Function CWnd:: Center Windows
Example(1): Center Window( ); //Relative to it's parent
// Relative to Screen
Example(2): Center Window(CWnd:: GetDesktopWindow( ));
//Relative to Application's MainWindow
AfxGetMainWnd( ) -> Center Window( ); 12. 如何讓視窗和 MDI視窗一啟動就最大化和最小化? 先說視窗。
在 InitStance 函數中設定 m_nCmdShow的 取值。
m_nCmdShow=SW_SHOWMAXMIZED ; //最大化
m_nCmdShow=SW_SHOWMINMIZED ; //最小化
m_nCmdShow=SW_SHOWNORMAL ; //正常方式
MDI視窗:
如果是建立新的應用程式,可以用 MFC AppWizard 的Advanced 按鈕并在MDI 子視窗風格組中檢測最大化或最小化; 還可以重載 MDI Window 的PreCreateWindow函數,設定WS_MAXMIZE or WS_MINMIZE;如果從 CMDIChildWnd 派生,調用 OnInitialUpdate函數中的 CWnd::Show Window來指定 MDI Child Window的風格。 13. 如何使程式保持極小狀态? 很有意思的問題,這麼辦: 在恢複程式窗體大小時, Windows 會發送WM_QUERY-OPEN 消息,用ClassWizard設定成員函數 OnQueryOpen() ,add following code:
Bool CMainFrame:: OnQueryOpen( )
{
Return false;
} 14. 如何限制視窗的大小? 也就是 FixedDialog 形式。 Windows 發送 WM_GETMAXMININFO消息來跟蹤,響應它,在OnGetMAXMININFO 中寫代碼: 15. 如何使視窗不可見? 很簡單,用SW_HIDE 隐藏視窗,可以結合 FindWindow,ShowWindow 控制。 16. 如何使視窗始終在最前方? 兩種途徑。
BringWindowToTop(Handle);
SetWindowPos函數,指定視窗的 最頂風格,用WS_EX_TOPMOST擴充視窗的風格
Example:
void ToggleTopMost( CWnd *pWnd)
{
ASSERT_VALID(pWnd);
pWnd ->SetWindowPos(pWnd-> GetStyle( ) &WS_EX_TOPMOST)?
&wndNoTopMOST: &wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE};
} 17. 如何建立一個字回繞的CEditView 重載CWnd : : PreCreateWindow 和修改CREATESTRUCT 結構,關閉CEditView 對象的ES_AUTOHSCROLL和WS_HSCROLL風格位, 由于CEditView : : PreCreateWindow顯示設定cs. style,調用基類函數後要修改cs . style。
BOOL CSampleEDitView : : PreCreateWindow (CREATESTRUCT&cs)
{
//First call basse class function .
BOOL bResutl =CEditView : : PreCreateWindow (cs) ;
// Now specify the new window style .
cs.style &= ~ (ES_AUTOHSCROLL |WS_HSCROLL);
return bResult ;
} 18. 通用控件的顯示視窗 MFC提供了幾個CView 派生的視窗類, 封裝了通用控件的功能,但仍然使用工作框文檔顯示視窗體系結構:CEditView 封裝了編輯控件,CTreeView 保持了樹清單控件,CListView封裝了清單顯示視窗控件,CRichEditView可以處理多種編輯控件。 19. 移動視窗 調用CWnd : : SetWindowPos 并指定SWP_NOSIZE 标志。目的位置與_____父視窗有關(頂層視窗與螢幕有關)。調用CWnd : : MoveWindow時必須要指定視窗的大小。
//Move window to positoin 100 , 100 of its parent window .
SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE |SWP_NOAORDER); 20. 重置視窗的大小 調用CWnd: : SetWindowPos 并指定SWP_NOMOVE标志, 也可調用CWnd : : MoveWindow但必須指定視窗的位置。
// Get the size of the window .
Crect reWindow ;
GetWindowRect (reWindow );
//Make the window twice as wide and twice as tall .
SetWindowPos (NULL , 0 , 0 , reWindow . Width ( ) *2,
reWindow . Height () * 2, SWP_NOMOVE |SWP_NOZORDER );
21. 如何單擊除了視窗标題欄以外的區域使視窗移動
當視窗需要确定滑鼠位置時Windows 向視窗發送WM_NCHITTEST 資訊,可以處理該資訊使Windows 認為滑鼠在視窗标題上。對于對話框和基于對話的應用程式,可以使用ClassWizard 處理該資訊并調用基類函數, 如函數傳回HTCLIENT 則表明滑鼠在客房區域,傳回HTCAPTION表明滑鼠在Windows的标題欄中。
UINT CSampleDialog : : OnNcHitTest (Cpoint point )
{
UINT nHitTest =Cdialog: : OnNcHitTest (point );
return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest ;
}
上述技術有兩點不利之處, 其一是在視窗的客戶區域輕按兩下時, 視窗将極大;其二,它不适合包含幾個視窗的主框視窗。還有一種方法,當使用者按下滑鼠左鍵使主框視窗認為滑鼠在其視窗标題上,使用ClassWizard在視窗中處理 WM_LBUTTODOWN 資訊并向主框視窗發送一個WM_NCLBUTTONDOWN資訊和一個單擊測試HTCAPTION。
void CSampleView : : OnLButtonDown (UINT nFlags , Cpoint point )
{
CView : : OnLButtonDow (nFlags , pont );
//Fool frame window into thinking somene clicked on its caption bar .
GetParentFrame ( ) —> PostMessage (
WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (poitn .x , point .y) );
}
該技術也适用于對話框和基于對的應用程式,隻是不必調用CWnd : : GetParentFrame 。
void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point )
{
Cdialog : : OnLButtonDow (nFlags, goint );
//Fool dialog into thinking simeone clicked on its caption bar .
PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x , point. y ) )
} 22. 如何改變視窗的背景顔色 Windows 向視窗發送一個WM_ERASEBKGND 消息通知該視窗擦除背景,可以使用ClassWizard 重載該消息的預設處理程式來擦除背景(實際是畫),并傳回TRUE 以防止Windows擦除視窗。
//Paint area that needs to be erased.
BOOL CSampleView : : OnEraseBkgnd (CDC* pDC)
{
// Create a pruple brush.
CBrush Brush (RGB (128 , 0 , 128) );
// Select the brush into the device context .
CBrush* pOldBrush = pDC—>SelcetObject (&brush);
// Get the area that needs to be erased .
CRect reClip ;
pDC—>GetCilpBox (&rcClip);
//Paint the area.
pDC—> PatBlt (rcClip.left , rcClip.top ,
rcClip.Width ( ) , rcClip.Height ( ) , PATCOPY );
//Unselect brush out of device context .
pDC—>SelectObject (pOldBrush );
// Return nonzero to half fruther processing .
return TRUE;
} 23. 如何改變視窗标題 調用CWnd : : SetWindowText可以改變任何視窗(包括控件)的标題。
//Set title for application's main frame window .
AfxGetMainWnd ( ) —> SetWindowText (_T("Application title") );
//Set title for View's MDI child frame window .
GetParentFrame ( ) —> SetWindowText ("_T ("MDI Child Frame new title") );
//Set title for dialog's push button control.
GetDigitem (IDC_BUTTON) —> SetWindowText (_T ("Button new title ") );
如果需要經常修改視窗的标題(注:控件也是視窗),應該考慮使用半文檔化的函數AfxSetWindowText。該函數在AFXPRIV.H中說明,在 WINUTIL.CPP中實作,在聯機幫助中找不到它,它在AFXPRIV.H中半文檔化, 在以後發行的MFC中将文檔化。
AfxSetWindowText的實作如下:
voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew )
{
itn nNewLen= Istrlen (Ipaznew);
TCHAR szOld [256];
//fast check to see if text really changes (reduces flash in the controls )
if (nNewLen >_contof (szOld) ||
: : GetWindowText (hWndCrtl , szOld , _countof (szOld) !=nNewLen ||
Istrcmp (szOld , IpszNew )! = 0
{
//change it
: : SetWindowText (hWndCtrl , IpszNew );
}
) 24. 如何防止主框視窗在其說明中顯示活動的文檔名 建立主框視窗和MDI子視窗進通常具有FWS_ADDTOTITLE風格位, 如果不希望在說明中自動添加文檔名, 必須禁止該風格位, 可以使用ClassWizard 重置CWnd: :PreCreateWindow并關閉FWS_ADDTOTITLE風格。
BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs)
{
//Turn off FWS_ADDTOTITLE in main frame .
cs.styel & = ~FWS_ADDTOTITLE ;
return CMDIFrameWnd : : PreCreateWindow (cs );
}
關閉MDI子視窗的FWS _ADDTOTITLE風格将建立一個具-_Âu有空标題的視窗,可以調用CWnd: :
SetWindowText來設定标題。記住自己設定标題時要遵循接口風格指南。 25. 如何擷取有關視窗正在處理的目前消息的資訊 調用CWnd: : GetCurrentMessage 可以擷取一個MSG指針。例如,可以使用ClassWizard将幾個菜單項處理程式映射到一個函數中,然後調用GetCurrentMessage 來确定所選中的菜單項。
viod CMainFrame : : OnCommmonMenuHandler ( )
{
//Display selected menu item in debug window .
TRACE ("Menu item %u was selected . /n" ,
GetCruuentMessage ( ) —> wParam );
} 26. 如何建立一個不規則形狀的視窗 可以使用新的SDK 函數SetWindowRgn。該函數将繪畫和滑鼠消息限定在視窗的一個指定的區域,實際上使視窗成為指定的不規則形狀。
使用AppWizard建立一個基于對的應用程式并使用資源編輯器從主對話資源中删除所在的預設控件、标題以及邊界。給對話類增加一個CRgn 資料成員,以後要使用該資料成員建立視窗區域。
Class CRoundDlg : public CDialog
{
…
private :
Crgn m_rgn : // window region
…
} ;
修改OnInitDialog函數建立一個橢圓區域并調用SetWindowRgn 将該區域配置設定給視窗:
BOOL CRoundDlg : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( ) ;
//Get size of dialog .
CRect rcDialog ;
GetClientRect (rcDialog );
// Create region and assign to window .
m_rgn . CreateEllipticRgn (0 , 0 , rcDialog.Width ( ) , rcDialog .Height ( ) );
SetWindowRgn (GetSafeHwnd ( ) , (HRGN) m_ rgn , TRUE );
return TRUE ;
}
通過建立區域和調用SetWindowRgn,已經建立一個不規則形狀的視窗,下面的例子程式是修改OnPaint函數使視窗形狀看起來象一個球形體。
voik CRoundDlg : : OnPaint ( )
{
CPaintDC de (this) ; // device context for painting .
//draw ellipse with out any border
dc. SelecStockObject (NULL_PEN);
//get the RGB colour components of the sphere color
COLORREF color= RGB( 0 , 0 , 255);
BYTE byRed =GetRValue (color);
BYTE byGreen = GetGValue (color);
BYTE byBlue = GetBValue (color);
// get the size of the view window
Crect rect ;
GetClientRect (rect);
// get minimun number of units
int nUnits =min (rect.right , rect.bottom );
//calculate he horiaontal and vertical step size
float fltStepHorz = (float) rect.right /nUnits ;
float fltStepVert = (float) rect.bottom /nUnits ;
int nEllipse = nUnits/3; // calculate how many to draw
int nIndex ; // current ellipse that is being draw
CBrush brush ; // bursh used for ellipse fill color
CBrush *pBrushOld; // previous brush that was selected into dc
//draw ellipse , gradually moving towards upper-right corner
for (nIndex = 0 ; nIndes < + nEllipse ; nIndes ++)
{
//creat solid brush
brush . CreatSolidBrush (RGB ( ( (nIndex *byRed ) /nEllipse ) ,
( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue) /nEllipse ) ) );
//select brush into dc
pBrushOld= dc .SelectObject (&brhsh);
//draw ellipse
dc .Ellipse ( (int) fltStepHorz * 2, (int) fltStepVert * nIndex ,
rect. right -( (int) fltStepHorz * nIndex )+ 1,
rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1) ;
//delete the brush
brush.DelecteObject ( );
}
}
最後,處理WM_NCHITTEST消息,使當擊打視窗的任何位置時能移動視窗。
UINT CRoundDlg : : OnNchitTest (Cpoint point )
{
//Let user move window by clickign anywhere on the window .
UINT nHitTest = CDialog : : OnNcHitTest (point) ;
rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest ;
} 27. 如何在代碼中擷取工具條和狀态條的指針 預設時, 工作框建立狀态條和工具條時将它們作為主框視窗的子視窗,狀态條有一個AFX_IDW_STATUS_BAR 辨別符,工具條有一個AFX_IDW_TOOLBAR辨別符,下例說明了如何通過一起調用CWnd: : GetDescendantWindow和AfxGetMainWnd來擷取這些子視窗的指針: //Get pointer to status bar .
CStatusBar * pStatusBar =
(CStatusBar *) AfxGetMainWnd ( ) —> GetDescendantWindow
(AFX_IDW_STUTUS_BAR);
//Get pointer to toolbar .
CToolBar * pToolBar =
(CToolBar * ) AfxGetMainWnd ( ) —> GetDescendantWindow (AFX_IDW_TOOLBAR); 28. 如何使能和禁止工具條的工具提示 如果設定了CBRS_TOOLTIPS風格位,工具條将顯示工具提示,要使能或者禁止工具提示,需要設定或者清除該風格位。下例通過調用 CControlBar : : GetBarStyle 和CControlBar : : SetBarStyle建立一個完成此功能的成員函數:
void CMainFrame : : EnableToolTips ( BOOL bDisplayTips )
{
ASSERT_VALID (m_wndToolBar);
DWORD dwStyle = m _wndToolBar.GetBarStyle ( ) ;
if (bDisplayTips)
dwStyle |=CBRS_TOOLTIPS ;
else
dwStyle & = ~ CBRS_TOOLTIPS ;
m_wndToolBar.SetBarStyle (dwStyle );
} 29. 如何設定工具條标題 工具條是一個視窗,是以可以在調用CWnd : : SetWindowText來設定标題,例子如下:
int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct )
{
…
// Set the caption of the toolbar .
m_wndToolBar.SetWindowText (_T "Standdard"); 30. 如何建立和使用無模式對話框 MFC 将模式和無模式對話封裝在同一個類中,但是使用無模式對話需要幾個對話需要幾個額處的步驟。首先,使用資源編輯器建立對話資源并使用ClassWizard 建立一個CDialog的派生類。模式和無模式對話的中止是不一樣的:
模式對話通過調用CDialog : : EndDialog 來中止,無模式對話則是調用CWnd: :
DestroyWindow 來中止的,函數CDialog : : OnOK 和CDialog : : OnCancel 調用
EndDialog ,是以需要調用DestroyWindow并重置無模式對話的函數。
void CSampleDialog : : OnOK ( )
{
// Retrieve and validate dialog data .
if (! UpdateData (TRUE) )
{
// the UpdateData rountine will set focus to correct item
TRACEO (" UpdateData failed during dialog termination ./n") ;
return ;
}
//Call DestroyWindow instead of EndDialog .
DestroyWindow ( ) ;
}
void CSampleDialog : : OnCancel ( )
{
//Call DestroyWindow instead of EndDialog .
DestroyWindow ( ) ;
}
其次,需要正确删除表示對話的C++對象。對于模式對來說,這很容易,需要建立函數傳回後即可删除C++對象;無模式對話不是同步的,建立函數調用後立即傳回,因而使用者不知道何時删除C++對象。撤銷視窗時工作框調用CWnd : : PostNcDestroy,可以重置該函數并執行清除操作,諸如删除this指針。
void CSampleDialog : : PostNcDestroy ( )
{
// Declete the C++ object that represents this dialog .
delete this ;
}
最後,要建立無模式對話。可以調用CDialog : : DoModal 建立一個模式對放, 要建立一個無模式對話則要調用CDialog: : Create。下面的例子說明了應用程式是如何建立無模式對話的:
void CMainFrame : : OnSampleDialog ( )
{
//Allocate a modeless dialog object .
CSampleDilog * pDialog =new CSampleDialog ;
ASSERT_VALID (pDialog) ;
//Create the modeless dialog .
BOOL bResult = pDialog —> Creste (IDD_IDALOG) ;
ASSERT (bResult ) ;
} (來源:CSDN)
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1460132