VC++ 的常用編程技巧
應(yīng)用程序的實(shí)例句柄保存在CWinApp m_hInstance 中,可以這么調(diào)用AfxGetInstancdHandle獲得句柄. HANDLE hInstance=AfxGetInstanceHandle() 2 如何通過代碼獲得應(yīng)用程序主窗口的指針? 主窗口的 指針保存在CWinThread::m_pMainWnd中,調(diào)用AfxGetMainWnd實(shí)現(xiàn)。 AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED) //使程序最大化. 3 如何在程序中獲得其他程序的圖標(biāo)? 兩種方法: · SDK函數(shù) SHGetFileInfo 或使用 ExtractIcon獲得圖標(biāo)資源的handle. void CSampleView: OnDraw(CDC * pDC) { if( :: SHGetFileInfo(_T("c:\\pwin95\\notepad.exe"),0, &stFileInfo,sizeof(stFileInfo),SHGFI_ICON)) { pDC ->DrawIcon(10,10,stFileInfo.hIcon) } } · SDK函數(shù) SHGetFileInfo 獲得有關(guān)文件的很多信息,如大小圖標(biāo),屬性,類型等. 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的路徑正規(guī)上來說用GetWindowsDirectory函數(shù)得到,如果是調(diào)用 win95下的畫筆,應(yīng)該用訪問注冊表的方法獲得其路徑,要作成一個(gè)比較考究的程序,考慮應(yīng)該全面點(diǎn). 4 如何編程結(jié)束應(yīng)用程序? 這是個(gè)很簡單又是編程中經(jīng)常要遇到的問題. 向窗口發(fā)送 WM_CLOSE消息,調(diào)用 CWnd::OnClose成員函數(shù).允許對用戶提示是否保存修改過的數(shù)據(jù). //發(fā)送關(guān)閉窗口消息 AfxGetMainWindow()->SendMessage(WM_CLOSE)
//通過標(biāo)題欄尋找需要關(guān)閉的窗口,然后關(guān)閉找到的窗口 void Terminate_Window(LPCSTR pCaption) { CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption)
if (pWnd) pWnd ->SendMessage(WM_CLOSE) } 說明: FindWindow函數(shù)不是提倡的做法,因?yàn)樗鼰o法處理標(biāo)題欄自動改變,比如我們要檢測 Notepad是不是已運(yùn)行而事先不知道Notepad的標(biāo)題欄,這時(shí)FindWindow就無能為力了,可以通過枚舉 windows任務(wù)列表的辦法來實(shí)現(xiàn)。在機(jī)械出版社”Windows 95 API開發(fā)人員指南”一書有比較詳細(xì)的介紹,這里就不再多說了。 5 怎樣加載其他的應(yīng)用程序? 三個(gè)SDK函數(shù) winexec, shellexecute,createprocess可以使用。 WinExec最簡單,兩個(gè)參數(shù),前一個(gè)指定路徑,后一個(gè)指定顯示方式.后一個(gè)參數(shù)值得說一下,比如泥用 SW_SHOWMAXMIZED方式去加載一個(gè)無最大化按鈕的程序,就是Neterm,calc等等,就不會出現(xiàn)正常的窗體,但是已經(jīng)被加到任務(wù)列表里了。 ShellExecute較 WinExex靈活一點(diǎn),可以指定工作目錄,下面的Example就是直接打開 c:\temp\1.txt,而不用加載與 txt文件關(guān)聯(lián)的應(yīng)用程序,很多安裝程序完成后都會打開一個(gè)窗口,來顯示Readme or Faq,我猜就是這么作的啦. ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c:\\temp"),SW_SHOWMAXMIZED) CreateProcess最復(fù)雜,一共有十個(gè)參數(shù),不過大部分都可以用NULL代替,它可以指定進(jìn)程的安全屬性,繼承信息,類的優(yōu)先級等等.來看個(gè)很簡單的Example: STARTUPINFO stinfo //啟動窗口的信息 PROCESSINFO procinfo //進(jìn)程的信息
CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE, NORMAL_PRIORITY_
CLASS,NULL,NULL, &stinfo,&procinfo)
6 如何確定應(yīng)用程序的路徑? Use GetModuleFileName 獲得應(yīng)用程序的路徑,然后去掉可執(zhí)行文件名。 Example: TCHAR exeFullPath[MAX_PATH] GetModuleFileName(NULL,exeFullPath,MAX_PATH) 7 如何獲得各種目錄信息? Windows目錄: Use “GetWindowsDirectory” Windows下的system目錄: Use “GetSystemDirectory” temp目錄: Use “GetTempPath” 當(dāng)前目錄: Use “GetCurrentDirectory” 請注意前兩個(gè)函數(shù)的第一個(gè)參數(shù)為目錄變量名,后一個(gè)為緩沖區(qū)后兩個(gè)相反 8 如何自定義消息? (1) 手工定義消息,可以這么寫 #define WM_MY_MESSAGE(WM_USER+100), MS 推薦的至少是 WM_USER+100 (2)寫消息處理函數(shù),用 WPARAM,LPARAM返回LRESULT. LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam) 9 如何改變窗口的圖標(biāo)? 向窗口發(fā)送 WM_SECTION消息。 Example: HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON) ASSERT(hIcon) AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM)hIcon) 10 如何改變窗口的缺省風(fēng)格? 重載 CWnd:: PreCreateWindow 并修改CREATESTRUCT結(jié)構(gòu)來指定窗口風(fēng)格和其他創(chuàng)建信息. //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如何將窗口居中顯示? 調(diào)用窗口函數(shù) CWnd::Center_window() 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 函數(shù)中設(shè)定 m_nCmdShow的取值. m_nCmdShow=SW_SHOWMAXMIZED 最大化 m_nCmdShow=SW_SHOWMINMIZED 最小化 m_nCmdShow=SW_SHOWNORMAL 正常方式 MDI窗口: 如果是創(chuàng)建新的應(yīng)用程序,可以用MFC AppWizard 的Advanced 按鈕并在MDI子窗口風(fēng)格組中檢測最大化或最小化還可以重載 MDI Window 的PreCreateWindow函數(shù),設(shè)置WS_MAXMIZE or WS_MINMIZE 如果從 CMDIChildWnd派生,調(diào)用 OnInitialUpdate函數(shù)中的 CWnd::Show Window來指定 MDI Child Window的風(fēng)格。 OnQueryOpen() ,add following code Bool CMainFrame:: OnQueryOpen( ) { Return false } </code> 13 如何使程序保持極小狀態(tài)? 這么辦: 在恢復(fù)程序窗體大小時(shí),Windows會發(fā)送WM_QUERY-OPEN消息,用 ClassWizard設(shè)置成員函數(shù) <code cpp> 14 如何限制窗口的大小? 也就是 FixedDialog形式。 Windows發(fā)送 WM_GETMAXMININFO消息來跟蹤, 響應(yīng)它,在 OnGetMAXMININFO 中寫代碼: 15 如何使窗口不可見? 很簡單,用SW_HIDE 隱藏窗口,可以結(jié)合 FindWindow,ShowWindow控制. 16 如何使窗口始終在最前方? BringWindowToTop(Handle) SetWindowPos函數(shù),指定窗口的 最頂風(fēng)格,用WS_EX_TOPMOST擴(kuò)展窗口的風(fēng)格 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 如何創(chuàng)建一個(gè)字回繞的CEditView? 重載CWnd : : PreCreateWindow和修改CREATESTRUCT結(jié)構(gòu),關(guān)閉CEditView對象的ES_AUTOHSCROLL和WS_HSCROLL 風(fēng)格位, 由于CEditView : : PreCreateWindow顯示設(shè)置cs. style,調(diào)用基類函數(shù)后要修改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提供了幾個(gè)CView派生的視窗類,封裝了通用控件的功能,但仍然使用工作框文檔顯示窗口體系結(jié)構(gòu):CEditView封裝了編輯控件,CTreeView保持了樹列表控件,CListView封裝了列表顯示窗口控件,CRichEditView可以處理多種編輯控件。 19 如何移動窗口? 調(diào)用CWnd : : SetWindowPos并指定SWP_NOSIZE標(biāo)志。目的位置與父窗口有關(guān)(頂層窗口與屏幕有關(guān))。調(diào)用CWnd : : MoveWindow時(shí)必須要指定窗口的大小。 //Move window to positoin 100 , 100 of its parent window . SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE |SWP_NOAORDER) 20 如何重置窗口的大小? 調(diào)用CWnd: : SetWindowPos并指定SWP_NOMOVE標(biāo)志, 也可調(diào)用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如何單擊除了窗口標(biāo)題欄以外的區(qū)域使窗口移動? 當(dāng)窗口需要確定鼠標(biāo)位置時(shí)Windows向窗口發(fā)送WM_NCHITTEST信息,可以處理該信息使Windows認(rèn)為鼠標(biāo)在窗口標(biāo)題上。對于對話框和基于對話的應(yīng)用程序,可以使用ClassWizard處理該信息并調(diào)用基類函數(shù), 如果函數(shù)返回HTCLIENT 則表明鼠標(biāo)在客房區(qū)域,返回HTCAPTION表明鼠標(biāo)在Windows的標(biāo)題欄中。 UINT CSampleDialog : : OnNcHitTest (Cpoint point ) { UINT nHitTest =Cdialog: : OnNcHitTest (point ) return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest }
上述技術(shù)有兩點(diǎn)不利之處, 其一是在窗口的客戶區(qū)域雙擊時(shí),窗口將極大; 其二, 它不適合包含幾個(gè)視窗的主框窗口。還有一種方法,當(dāng)用戶按下鼠標(biāo)左鍵使主框窗口認(rèn)為鼠標(biāo)在其窗口標(biāo)題上,使用ClassWizard在視窗中處理WM_LBUTTODOWN信息并向主框窗口發(fā)送一個(gè)WM_NCLBUTTONDOWN信息和一個(gè)單擊測試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) )
} 該技術(shù)也適用于對話框和基于對的應(yīng)用程序,只是不必調(diào)用 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向窗口發(fā)送一個(gè)WM_ERASEBKGND消息通知該窗口擦除背景,可以使用ClassWizard重載該消息的缺省處理程序來擦除背景(實(shí)際是畫),并返回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 如何改變窗口標(biāo)題? 調(diào)用CWnd : : SetWindowText可以改變?nèi)魏未翱冢ò丶┑臉?biāo)題。 //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 ") )
如果需要經(jīng)常修改窗口的標(biāo)題(注:控件也是窗口),應(yīng)該考慮使用半文檔化的函數(shù)AfxSetWindowText。該函數(shù)在AFXPRIV.H中說明,在WINUTIL.CPP中實(shí)現(xiàn),在聯(lián)機(jī)幫助中找不到它,它在AFXPRIV.H中半文檔化, 在以后發(fā)行的MFC中將文檔化。 AfxSetWindowText的實(shí)現(xiàn)如下: 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 如何防止主框窗口在其說明中顯示活動的文檔名 創(chuàng)建主框窗口和MDI子窗口進(jìn)通常具有FWS_ADDTOTITLE風(fēng)格位,如果不希望在說明中自動添加文檔名, 必須禁止該風(fēng)格位, 可以使用ClassWizard重置 CWnd: : PreCreateWindow并關(guān)閉FWS_ADDTOTITLE風(fēng)格。 BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs) { //Turn off FWS_ADDTOTITLE in main frame . cs.styel & = ~FWS_ADDTOTITLE return CMDIFrameWnd : : PreCreateWindow (cs ) } 關(guān)閉MDI子窗口的FWS _ADDTOTITLE風(fēng)格將創(chuàng)建一個(gè)具有空標(biāo)題的窗口,可以調(diào)用CWnd: : SetWindowText來設(shè)置標(biāo)題。記住自己設(shè)置標(biāo)題時(shí)要遵循接口風(fēng)格指南。 25 如何獲取有關(guān)窗口正在處理的當(dāng)前消息的信息? 調(diào)用CWnd: : GetCurrentMessage可以獲取一個(gè)MSG指針。例如,可以使用ClassWizard將幾個(gè)菜單項(xiàng)處理程序映射到一個(gè)函數(shù)中,然后調(diào)用GetCurrentMessage來確定所選中的菜單項(xiàng)。 viod CMainFrame : : OnCommmonMenuHandler ( ) { //Display selected menu item in debug window . TRACE ("Menu item %u was selected . \n" ,GetCruuentMessage ( ) —> wParam ) } 26 如何創(chuàng)建一個(gè)不規(guī)則形狀的窗口 ? 可以使用新的SDK函數(shù)SetWindowRgn。該函數(shù)將繪畫和鼠標(biāo)消息限定在窗口的一個(gè)指定的區(qū)域,實(shí)際上使窗口成為指定的不規(guī)則形狀。使用AppWizard創(chuàng)建一個(gè)基于對的應(yīng)用程序并使用資源編輯器從主對話資源中刪除所在的缺省控件、標(biāo)題以及邊界。給對話類增加一個(gè)CRgn數(shù)據(jù)成員,以后要使用該數(shù)據(jù)成員建立窗口區(qū)域。 Class CRoundDlg : public CDialog { … private : Crgn m_rgn : // window region … } 修改OnInitDialog函數(shù)建立一個(gè)橢圓區(qū)域并調(diào)用SetWindowRgn將該區(qū)域分配給窗口: 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 } 通過建立區(qū)域和調(diào)用SetWindowRgn,已經(jīng)建立一個(gè)不規(guī)則形狀的窗口,下面的例子程序是修改OnPaint函數(shù)使窗口形狀看起來象一個(gè)球形體。 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消息,使當(dāng)擊打窗口的任何位置時(shí)能移動窗口。 UINT CRoundDlg : : OnNchitTest (Cpoint point ) { //Let user move window by clickign anywhere on thewindow . UINT nHitTest = CDialog : : OnNcHitTest (point) rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest
} 27 如何在代碼中獲取工具條和狀態(tài)條的指針? 缺省時(shí),工作框創(chuàng)建狀態(tài)條和工具條時(shí)將它們作為主框窗口的子窗口,狀態(tài)條有一個(gè)AFX_IDW_STATUS_BAR標(biāo)識符,工具條有一個(gè) AFX_IDW_TOOLBAR標(biāo)識符,下例說明了如何通過一起調(diào)用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) 分類: cpp |
|