(1) 如何經過代碼得到應用程序主窗口的 指針?
主窗口的 指針保存在CWinThread::m_pMainWnd中,調用AfxGetMainWnd實現。
AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED)
//使程序最大化.c++
(2) 肯定應用程序的路徑
Use GetModuleFileName 得到應用程序的路徑,而後去掉可執行文件名。
Example:
TCHAR
exeFullPath[MAX_PATH] // MAX_PATH在API中定義了吧,好象是
128
GetModuleFileName(NULL,exeFullPath,MAX_PATH)
git
(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"
請注意前兩個函數的第一個參數爲目錄變量名,後一個爲緩衝區後兩個相反.shell
(5) 如何自定義消息
1) 手工定義消息,能夠這麼寫
#define WM_MY_MESSAGE(WM_USER+100),
MS 推薦的至少是 WM_USER+100
(2)寫消息處理函數,用
WPARAM,LPARAM返回LRESULT.
LRESULT CMainFrame::OnMyMessage(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_CXSCREEN/2)
cs.cy=GetSystemMetrics(SM_CYSCREEN/2)
return CMDIFramewnd ::PreCreateWindow(cs)
}windows
(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函數中的 CWnd::Show 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 = 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 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 : : 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就是直接打開 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: : 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_NOSIZE|WSP_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 , 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指針,要保證在控件撤消以前不能撤消字體對象。下例將下壓按鈕的字體改成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] = {"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。下例將旋轉按鈕控件的範圍設置爲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() );
1)當文檔被修改時,如何在標題上加上標誌'*'?
重載CDocument類的虛函數virtual SetModifiedFlag:
void CTest2Doc::SetModifiedFlag(BOOL bModified)
{
CString strTitle = GetTitle();
CString strDirtyFlag = " *"; // note space before the '*'
// so we don't break Save As dialog
if (!IsModified() && bModified)
{
SetTitle(strTitle + strDirtyFlag);
}
else if ( IsModified() && !bModified )
{
int nTitleLength = strTitle.GetLength();
int nDirtyLength = strDirtyFlag.GetLength();
SetTitle( strTitle.Left(nTitleLength - nDirtyLength) );
}
UpdateFrameCounts();
CDocument::SetModifiedFlag(bModified);
}
(2)VC6.0對VC5.0的兼容性?
很不幸,vc6.0在調試模式對vc5.0不兼容,但發行模式沒有問題.緣由在微軟改變了調試模式所用dll的格式,而保留了原文件名. 所以,不要在vc6.0中打開vc5.0的調試版本工程.
(3)打印和打印機的問題?
我碰到這麼一個問題:在打印方法中使用了MM_LOMETRIC模式,在LOGFONT結構中改變了字體的大小,但不知道173(或者對於屏幕而言是25)是從哪來的,它是自動的.然而當我用另一個打印機時173並不適合.我想知道的是:我如何對全部的打印來調整這個數字.
我之前也碰到過相似的問題,我讓用戶改變字體(大小,顏色等等).這些改變在屏幕上看起來挺好,可是打印時過小(個人同事在程序包中加入一個放大類).緣由很是簡單:打印機的分辨率多是300dpi,而屏幕的分辨率則低得多.我是這麼解決的:在得到屏幕字體信息後,我獲取屏幕字體的毫米級大小(使用LPtoDP,而後將模式變爲MM_LOMETRIC,調用DPtoLP),接着對打印機設定了相同的模式,再調用LPtoDP.切換回原來的模式以後,我調用了DPtoLP,這樣就獲得了想要的字體高度和寬度. 在LOGFONT中使用這個值,而且帶有其它諸以下劃線,斜體等字體信息,我實現了用戶的要求.
(4)CRichEditCtrl滾動條的問題?
我使用了CRichEditCtrl控制來顯示某個文件中的數據(將該控制設置爲只讀).我已經設置了ES_MULTILINE | ES_AUTOVSCROLL,但當數據內容比控制顯示多的時候,滾動條並不出現,是否是由於設置了只讀屬性而引發了其它的問題?
ES_AUTOVSCROLL | ES_AUTOHSCROLL屬性只在控制是可編輯時有效.你可心使用下面的滾動條風格來使滾動條出現:WS_VSCROLL | WS_HSCROLL,可是這樣一來,無論你的數據量有多大,滾動條老是會出現.
(5)從數據庫中讀大於32k的內容?
我在從數據庫中讀數據時碰到了問題.當數據欄包含超過32k的內容時,我就讀不出來,我試過ODBC::SQLGetData()也不行.
哪一種類型的數據庫?MS SQL,SYBASE... 試試設置一下大小:
BOOL CGetBlobStmt::Execute(LPCTSTR stmt)
{
m_cbSize = 0;
m_size = 0;
LPBYTE
lpData;
lpData = (LPBYTE)GlobalLock(m_hData);
m_retcode = SQLSetStmtOption(GetHandle(),SQL_MAX_LENGTH,m_dwBytesLeft);
m_retcode = SQLExecDirect(GetHandle(),(UCHAR*)stmt,SQL_NTS);
if (m_retcode == SQL_SUCCESS)
{
m_retcode = SQLFetch(GetHandle());
if (m_retcode == SQL_SUCCESS ||m_retcode == SQL_SUCCESS_WITH_INFO)
{
m_retcode = SQLGetData(GetHandle(),1,SQL_C_BINARY,lpData,254,&m_cbSize);
while(m_retcode == SQL_SUCCESS_WITH_INFO)
{
lpData+= 254;
m_retcode = SQLGetData(GetHandle(),1,SQL_C_BINARY,lpData,254,&m_cbSize);
}
GetError();
}
}
GlobalUnlock(m_hData);
#if TESTDATA
TRACE("%ld",m_size);
#endif
SaveFile();
return RETVALUE;
}
(6)如何得到CRichEditCtrl中字符的位置?
我想在CRichEditCtrl中使用右鍵菜單,所以想斷定光標處字符的位置,請指點.
查看以下的幫助:
IRichEditOleCallback::GetContextMenu
EM_SETOLECALLBACK
(7)如何限制mdi子框架最大化時的大小?
用ptMaxTrackSize代替prMaxSize,以下所示:
void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
// TOD Add your message handler code here and/or call default
CChildFrame::OnGetMinMaxInfo(lpMMI);
lpMMI->ptMaxTrackSize.x = 300;
lpMMI->ptMaxTrackSize.y = 400;
}
(8)如何切換視口而不破壞它們?
我建立了一個帶有靜態分隔區的sdi應用程序,左邊顯示工做區,右過顯示左邊選取的東西.我想達到的是若是在分隔區之間進行切換,而不覆蓋或破壞原來的CView對象.
如下代碼是你所想要的:
class CExSplitterWnd : public CSplitterWnd
{
// Construction
public:
CExSplitterWnd();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CExSplitterWnd)
//}}AFX_VIRTUAL
// Implementation
virtual ~CExSplitterWnd();
BOOL AttachView(CWnd* pView, int row, int col);
BOOL DetachView(int row, int col);
// Generated message map functions
//{{AFX_MSG(CExSplitterWnd)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CExSplitterWnd::CExSplitterWnd()
{
}
CExSplitterWnd::~CExSplitterWnd()
{
}
BOOL CExSplitterWnd::AttachView(CWnd* pView, int row, int col)
{
//Make sure the splitter window was created
if (!IsWindow(m_hWnd))
{
ASSERT(0);
TRACE(_T("Create the splitter window before attaching windows to panes"));
return (FALSE);
}
//Make sure the row and col indices are within bounds
if (row >= GetRowCount() || col >= GetColumnCount())
{
ASSERT(0);
return FALSE;
}
//Is the window to be attached a valid one
if (pView == NULL || (!IsWindow(pView->m_hWnd)))
{
ASSERT(0);
return FALSE;
}
pView->SetDlgCtrlID(IdFromRowCol(row, col));
pView->SetParent(this);
pView->ShowWindow(SW_SHOW);
pView->UpdateWindow();
return (TRUE);
}
BOOL CExSplitterWnd::DetachView(int row, int col)
{
//Make sure the splitter window was created
if (!IsWindow(m_hWnd))
{
ASSERT(0);
TRACE(_T("Create the splitter window before attaching windows to panes"));
return (FALSE);
}
//Make sure the row and col indices are
//within bounds
if (row >= GetRowCount() || col >= GetColumnCount())
{
ASSERT(0);
return FALSE;
}
CWnd* pWnd = GetPane(row, col);
if (pWnd == NULL || (!IsWindow(pWnd->m_hWnd)))
{
ASSERT(0);
return FALSE;
}
pWnd->ShowWindow(SW_HIDE);
pWnd->UpdateWindow();
//Set the parent window handle to NULL so that this child window is not
//destroyed when the parent (splitter) is destroyed
pWnd->SetParent(NULL);
return (TRUE);
}
(9)改變列表控制時發生閃爍現象?
我建立了一個簡單的對話框,在對話框中設置了一個列表控件,這個控件佔用了對話框的所有客戶區.對話框是能夠改變大小的,所以我要保證列表控件在對話框中維持正確的位置,在對話框的ONSize()事件中我對列表控件使用了MoveWindow(),這起到了做用,但當用戶改變對話框的大小時,列表控件不停地閃爍.
要解決這個問題,在用MoveWindow以前,先用ShowWindow(SW_HIDE)隱藏列表控件,而後在MoveWindow以後用ShowWindow(SW_SHOW)來顯示列表控件.
(10)處理列表控件可見項的問題?
我在一個列表控件中加入了好多條目.我經過獲取某個條目是否可見或最後是哪一個條目來進行處理.我看了CListCtrl::GetItem()的幫助,可是沒有找到如何判斷一個條目是否可見的方法.
若是你只想處理可見的條目,你能夠用GetTopIndex.它返回最大可見條目的索引值,而後你再用GetCountPerPage來獲得在可見區域的條目數.
(11)產生線程的問題?
我在使用CreateThread時碰到了問題.我想讓調用的函數和被調用的函數屬於同一個類,結果在我調用CreateThread時獲得以下錯誤:
error C2440: 'type cast' : cannot convert from 'unsigned long (__stdcall Cdmi::*)(void *)' to 'unsigned long (__stdcall *)(void *)'
方法一:
(1)'unsigned long (__stdcall Cdmi::*)(void *)'是指向Cdmi某個成員函數的指針.
(2)'unsigned long (__stdcall *)(void *)'僅僅只是一個c形式函數的指針. 編譯器沒法將(1)轉換爲(2)是由於c++成員函數取第一個(隱藏)參數"this pointer"做爲成員函數,但當是一個靜態的成員時則例外.可按以下方法解決.
class XMyThread
{
public:
void StartThread(void);
virtual UINT ThreadFunction(void);
static UINT __bogusthreadfunc(LPVOID lpparam);
};
void XMyThread::StartThread()
{
AfxBeginThread(__bogusthreadfunc,this);
}
UINT XMyThread::ThreadFunction(void)
{
//here you do all your real work
return 0;
}
UINT XMyThread::__bogusthreadfunc(LPVOID lpparam)
{
XMyThread* This = dynamic_cast(lpparam);
return This->ThreadFunction();
}
for the sake of clairty, I did not add StopThread and I did not save the
CWinThread* returned by AfxBeginThread.
If you wanted a thread that does other things, simply derive from XMyThread
and override ThreadFunction()
example:
class XAnotherThread : public XMyThread
{
virtual UINT ThreadFunction(void);
};
UINT XAnotherThread :: ThreadFunction(void)
{
//do some other work here
return 0;
}
方法二:Cdmi::MonitorFiles()是個靜態的成員函數.
(12)CFile使用了緩衝區嗎?
請告訴我CFile到底有沒有使用緩衝區來處理文件?
CFile沒有使用運行庫的I/O緩衝例程,從這個意義上講CFile並無使用緩衝.可是有可能操做系統在處理文件時使用了緩衝區,若是你徹底不須要緩衝區,你能夠設置FILE_FLAG_NO_BUFFERING.CFile工做在這種模式下的惟一的方法是CFile::Attach().
(13)DAO的密碼?
我建立了一個使用數據庫的mfc應用程序.用類模板生成CDaoRecordset直接打開數據庫(不經過ODBC),但問題是我如何打開有密碼保護的數據庫?
方法一:試試下面的代碼:
DAODBEngine* pDBEngine = AfxDaoGetEngine();
ASSERT(pDBEngine != NULL);
COleVariant varUserName (strUserName, VT_BSTRT);
COleVariant varPassword (strPassword, VT_BSTRT);
DAO_CHECK(pDBEngine->put_DefaultUser (V_BSTR(&varUserName));
DAO_CHECK(pDBEngine->put_DefaultPassword (V_BSTR(&varPassword));
方法二:你可使用CDaoDatabase的Open方法來打開:
MyDaoDatabase->Open("C:\MyDatabaseFile.mdb",FALSE,FALSE,";PWD=MyPassWord");
btw:不要忘了PWD=前面的;號.
(14)如何知道CListBox何時滾動了?
每次繪製列表框都要重繪某項,經過消息WM_CTLCOLOR從父窗口得到DC顏色.所以每欠列表框的滾動你均可以用WM_CTLCOLOR來檢驗是否滾動.
HBRUSH CParentDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
// is the control _the_ list box we're interested in?
if( nCtlColor == CTLCOLOR_LISTBOX &&
pWnd->GetDlgCtrlID() == IDC_LIST )
{
// if the top index changed, the list box has been scrolled
int iTop = ((CListBox*)pWnd)->GetTopIndex();
if( iTop != m_iTopOld )
{
// keeps tracking of the top index changes
m_iTopOld = iTop;
// process scrolling
...
}
}
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
}
使用這種方法能夠沒必要爲了實現這個功能而去產生一個繼承類.
(15)視口的不活動性如何處理?
有什麼方法使CListView成爲相似WM_DIASBLED的風格,或者使它和背景色一致.
方法一:你所要作的是處理CListView的WM_SETFOCUS消息,而後在TreeView中調用SetFocus,
這樣,ListView就永遠不會得到焦點.
afx_msg void CMyListView::OnSetFocus(CWnd* pOldWnd);
{
// assuming m_pwndTreeView points to the valid TreeView
// on the left side
m_pwndTreeView->SetFocus();
}
方法二:重載PreTranslateMessage,而後當消息爲WM_LBUTTONDOWN或WM_RBUTTONDOWN時返回真便可.
(16)如何使用COleClientItem的IDispatch接口?
我建立了一個如何使用COleClientItem對象,我想使用它的自動化方法.有什麼方法來得到IDispatch的接口?我試過以CCmdTarget爲基類的的GetIDispatch函數但卻出錯,我用過EnableAutomation和GetIDispatch,卻什麼也沒獲得.
MSDN中有一篇關於這個的文章(TN039).以下的代碼也多是你所須要的:
LPDISPATCH CMyClientItem::GetIDispatch()
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
LPUNKNOWN lpUnk = m_lpObject;
Run(); // must be running
LPOLELINK lpOleLink = NULL;
if (m_lpObject->QueryInterface(IID_IOleLink,
(LPVOID FAR*)&lpOleLink) == NOERROR)
{
ASSERT(lpOleLink != NULL);
lpUnk = NULL;
if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)
{
TRACE0("Warning: Link is not connected!\n");
lpOleLink->Release();
return NULL;
}
ASSERT(lpUnk != NULL);
}
LPDISPATCH lpDispatch = NULL;
if (lpUnk->QueryInterface(IID_IDispatch, &lpDispatch)
!= NOERROR)
{
TRACE0("Warning: does not support IDispatch!\n");
return NULL;
}
ASSERT(lpDispatch != NULL);
return lpDispatch;
}
(17)關於用戶自定義的消息使用?
我寫了一個基於MFC應用程序的對話框,在這個程序中,我建立了等待網絡傳輸數據的線程,一旦該線程接收到數據,它就傳送一個用戶自定義的消息到對話框,使對話框知道有數據過來.可是爲什麼在CMyDialog::PreTranslateMessage(MSG* pMsg)中能捕捉到WM_MYCMD這個消息,卻不能和OnMyCommand相映射?
將你全部自定義消息的基類設爲WM_APP,而不是WM_USER.
(18)在打開一個文檔時退出?
我有一個mdi程序,在打開文件的處理過程當中,我想判斷該文檔是否是應用程序須要處理的文檔,所以,我檢測文檔中的某個數字是否符合要求,如何在發現不是該文檔時出現一個錯誤提示,而後不打開該文檔?
給文檔設定某個標誌,若是文檔不是所要的就設定它.而後OnOpenDocument中檢測,當發現標誌被設定後返回FALSE.
(19)在CListCtrl控件中多選擇項的刪除?
如何從在CListCtrl中刪除多個選擇項?
按以下方法處理:若是你的在CListCtrl是m_list,to_delete是個整數數組.
i=3D0;
POSITION pos=3Dm_list.GetFirstSelectedItemPosition();
if(pos)
while(pos)
to_delete[i++]=3Dm_list.GetNextSelectedItem(pos);
而後用刪除保存在to_delete中的項目,用GetSelectedCount來獲得已選項的個數.
(20)工做線程的登陸狀態?
我使用循環刪除了用AfxBeginThread建立的線程的好幾個實例.每一個線程打開一個iNET鏈接,打開一個URL並返回結果.我須要找出哪個或者什麼時候這些線程進入到登陸狀態.
按以下方法處理:(僞代碼)
// Start Threads
for( unsigned u = 0; u < NUMBER_OF_THREADS; u++ )
{
ThreadHandleArray[ u ] = AfxBeginThread( ...... )->m_hThread;
}
DWORD count = NUMBER_OF_THREADS
DWORD dwWait;
while( count )
{
dwWait = ::WaitForMultipleObjects( count, ThreadHandleArray, FALSE,
INFINITE );
if( dwWait >= WAIT_OBJECT_0 && dwWait < ( WAIT_OBJECT_0 + count ) )
{
dwWait -= WAIT_OBJECT_0;
// dwWait now has index to thread that completed do whatever
you want to do with it
// set array back up for next wait
if( dwWait != ( count - 1 ) )
ThreadHandleArray[ dwWait ] = ThreadHandleArray[
count - 1 ];
count--;
}
}
(21)如何增長視圖中ActiveX控件的事件處理函數?
若是我在對話框中加入微軟的網絡瀏覽器,很容易經過類模板加入對事件的處理.但我如今在視圖中用m_pBrowser=new CWebBrowser2加入了網絡瀏覽器,我該如何對事件進行處理?
到http://www.vcdj.com(inet/章節)去看看,有一篇文章名爲"Building a Webbrowser in a Afternoon".以下的代碼也多是你所須要的:
#include // For AFX_EVENT def.
BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
AFX_EVENT *pEvent = (AFX_EVENT *)pExtra;
//If this is a control notification event.
if (nCode == CN_EVENT)
{
// If we have information on this event.
if (pEvent)
{
// Event DISPID is stored at pEvent->m_dispid
// Event DISPPARAMS are stored at pEvent->m_pDispParams
// Handle the event from here...
}
}
return CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
(22)如何建立一個動態的Tree控件?
我想建立一個動態的tree控件,就象彈出窗口同樣,但它並不象想象中那麼容易.
方法一:用CreateWindow(SDK)建立風格爲WS_POPUP,WS_CAPTION和WS_TICKFRAME的窗口,並做爲父窗口.
方法二:建立一個包含Tree控件的對話框.
(23)SDI程序開始時不打開文檔?
我建立了一個SDI應用,但每次啓動時它都會打開一個文檔("untitled"),如何不讓它打開該文檔呢?
看看InitInstance函數中有沒有關於OnFileNew的調用,去掉它便可.
(24)List控件中整欄選擇?
我在處理List控件時碰到了麻煩,我想建立一個ListView,來依據Tree控件的選擇同時在ListView和ReportView中顯示列表的信息.如下是相關的代碼:
// Set full line select
ListView_SetExtendedListViewStyle(m_plstCustomers->GetSafeHwnd(),
LVS_EX_FULLROWSELECT);
按以下方法處理:
// -------------------- begin of snippet --------------------------------
bool CCommCtrlUtil32::ListCtrl_ModifyExtendedStyle(CListCtrl& p_rListCtrl,
const DWORD p_dwStyleEx,
const bool p_bAdd)
{
HWND t_hWnd = p_rListCtrl.GetSafeHwnd();
DWORD t_dwStyleEx = ListView_GetExtendedListViewStyle(t_hWnd);
if(p_bAdd)
{
if(0 == (p_dwStyleEx & t_dwStyleEx))
{
// add style
t_dwStyleEx |= p_dwStyleEx;
}
}
else
{
if(0 != (p_dwStyleEx & t_dwStyleEx))
{
// remove style
t_dwStyleEx &= ~p_dwStyleEx;
}
}
ListView_SetExtendedListViewStyle(t_hWnd, t_dwStyleEx);
return true;
}
(25)如何重載MRU文件?
我建立了一個應用程序能夠載入圖象文件,但當我點擊FILE菜單下MRU文件列表時,卻不能從磁盤載入之前曾經打開過的文件.
下面是我所能想到的解決方案:
(1)在文檔類中定義一個成員函數(例如:CMyDoc::Reopen)來處理從新打開這個問題,指明參數和返回值.
(2)產生一個CMultiDocTemplate的繼承類(如CMyDocTemplate),定義一個構造函數,取和基類相同的參數,不作任何事,只是調用基類的構造函數.
(3)重載MatchDocType:
CMyDocTemplate::Confidence CMyDocTemplate::MatchDocType(
LPCTSTR lpszPath,
CDocument *&rpDocMatch
)
{
Confidence match = CMultiDocTemplate::MatchDocType(lpszPath, rpDocMatch);
if(yesAlreadyOpen == match) // clear enough
{
ASSERT_KINDOF(CMyDoc, rpDocMatch);
((CMyDoc *) rpDocMatch)->Reopen(/* your parameters */);
// you can take any other actions here...
}
return match;
}
當這個函數返回"yesAlreadyOpen"時,你的文檔框架將會被激活.
--------------------------------------------------
(26)CImageList控件中圖象橙色被顯示爲黃色?
我使用了一個CImageList控件來裝入位圖,用於TREE控件,其它的色彩都很正常就是橙色被顯示成爲黃色.
你只能使用系統指定的20種顏色(橙色不包括在內);固然,你也能夠用下面的方法來裝載位圖資源而不受顏色數的限制.
HBITMAP LoadResourceBitmap(HINSTANCE hInstance, LPSTR lpString,
HPALETTE FAR* lphPalette)
{
HRSRC hRsrc;
HGLOBAL hGlobal;
HBITMAP hBitmapFinal = NULL;
LPBITMAPINFOHEADER lpbi;
HDC hdc;
int iNumColors;
if (hRsrc = ::FindResource(hInstance, lpString, RT_BITMAP))
{
hGlobal = ::LoadResource(hInstance, hRsrc);
lpbi = (LPBITMAPINFOHEADER)LockResource(hGlobal);
hdc = ::GetDC(NULL);
*lphPalette = CreateDIBPalette ((LPBITMAPINFO)lpbi, &iNumColors);
if (*lphPalette)
{
::SelectPalette(hdc,*lphPalette,FALSE);
::RealizePalette(hdc);
}
hBitmapFinal = ::CreateDIBitmap(hdc,
(LPBITMAPINFOHEADER)lpbi,
(LONG)CBM_INIT,
(LPSTR)lpbi + lpbi->biSize + iNumColors * sizeof(RGBQUAD),
(LPBITMAPINFO)lpbi,
DIB_RGB_COLORS );
::ReleaseDC(NULL,hdc);
// ::UnlockResource(hGlobal);
// ::FreeResource(hGlobal);
}
return (hBitmapFinal);
}
// internally used by LoadResourceBitmap
HPALETTE CreateDIBPalette (LPBITMAPINFO lpbmi, LPINT lpiNumColors)
{
LPBITMAPINFOHEADER lpbi;
LPLOGPALETTE lpPal;
HANDLE hLogPal;
HPALETTE hPal = NULL;
int i;
lpbi = (LPBITMAPINFOHEADER)lpbmi;
if (lpbi->biBitCount <= 8)
*lpiNumColors = (1 << lpbi->biBitCount);
else
*lpiNumColors = 0; // No palette needed for 24 BPP DIB
if (lpbi->biClrUsed > 0)
*lpiNumColors = lpbi->biClrUsed; // Use biClrUsed
if (*lpiNumColors)
{
hLogPal = GlobalAlloc (GHND, sizeof (LOGPALETTE) +
sizeof (PALETTEENTRY) * (*lpiNumColors));
lpPal = (LPLOGPALETTE) GlobalLock (hLogPal);
lpPal->palVersion = 0x300;
lpPal->palNumEntries = *lpiNumColors;
for (i = 0; i < *lpiNumColors; i++)
{
lpPal->pal
PalEntry.
peRed = lpbmi->bmiColors.rgbRed;
lpPal->palPalEntry.peGreen = lpbmi->bmiColors.rgbGreen;
lpPal->palPalEntry.peBlue = lpbmi->bmiColors.rgbBlue;
if (i<=10 || i>=246)
lpPal->palPalEntry.peFlags = PC_NOCOLLAPSE;
else
lpPal->palPalEntry.peFlags = 0;
}
hPal = CreatePalette (lpPal);
GlobalUnlock (hLogPal);
GlobalFree (hLogPal);
}
return hPal;
}
該函數也重載了位圖調色板,這個功能被CBitmap::LoadBitmap忽略了(它假定位圖只使用20種顏色).所以要保證在DC中有SelectPalette和RealizePalette.
(27)沒法正確改變應用程序的圖標?
我有一個基於對話框的應用程序,在初始化時我使用了AfxGetApp()->LoadIcon(IDI_BRIEFCASE)來載入本身的圖標,當把程序拷貝到桌面上時,圖標是我所指望的.但在資源管理器中的圖標卻仍是MFC的圖標.
資源管理器僅使用16x16的小圖標,可能你在資源編輯器中只修改了32x32的標準圖標.你須要重建16x16的小圖標.
(28)工具條狀態的問題?
在應用程序中我建立了三個工具條,我想讓它們在應用程序啓動的時候排成一行正好在主菜單的下面,我該如何去作?
在VC CDs上有一個例子:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
//other stuff here...
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar,AFX_IDW_DOCKBAR_TOP);
DockControlBarLeftOf(&m_wndListToolBar,&m_wndToolBar);
return 0;
}
void CMainFrame::DockControlBarLeftOf(CToolBar* Bar,CToolBar* LeftOf)
{
CRect rect;
DWORD dw;
UINT n;
// get MFC to adjust the dimensions of all docked ToolBars
// so that GetWindowRect will be accurate
RecalcLayout();
LeftOf->GetWindowRect(&rect);
rect.OffsetRect(1,0);
dw=LeftOf->GetBarStyle();
n = 0;
n = (dw & CBRS_ALIGN_TOP) ? AFX_IDW_DOCKBAR_TOP :n;
n = (dw & CBRS_ALIGN_BOTTOM && n==0) ? AFX_IDW_DOCKBAR_BOTTOM :n;
n = (dw & CBRS_ALIGN_LEFT && n==0) ? AFX_IDW_DOCKBAR_LEFT :n;
n = (dw & CBRS_ALIGN_RIGHT && n==0) ? AFX_IDW_DOCKBAR_RIGHT :n;
// When we take the default parameters on rect, DockControlBar will dock
// each Toolbar on a seperate line. By calculating a rectangle, we in effect
// are simulating a Toolbar being dragged to that location and docked.
DockControlBar(Bar,n,&rect);
}
(29)在SDI應用程序中使用Active控件?
我剛瞭解到如何在MFC應用程序中使用Active控件,文檔上說只能在視圖爲CFormView和CDialog時使用,但要是其它的狀況該怎麼辦呢?
你能夠在你應用程序的任何地方使用Active控件,而不只僅侷限於CFormView和CDialog爲視圖基類的狀況.DevStudio經過資源編輯器和對話框模板來使得在上述兩個條件下使用Active控件更容易.所以,你也能夠在任何視圖中使用Active控件,條件是你直接操縱該控件,建立它並手工的佈置好它的位置(這也是DevStudio爲你所作的事).
(30)有RichEdit控件的對話框沒法正常顯示?
我在對話框中放置了一個RichEdit控件,可是對話框卻沒法正常顯示.
在你的應用程序InitInstance()中調用了::AfxInitRichEdit()嗎?
(31)DLL中的模板成員函數?
在一個DLL中,我在本身建立的類中使用了模板成員函數來代替預處理宏.但出現如下錯誤:
error C2664: 'double Data::extract(double &)' : cannot convert parameter 1
from 'class CArray' to 'double &'
爲何在匹配模板定義時它要尋找一個DOUBLE參數?
我以爲你多是在表達成員函數(內聯)時出現了問題,請參照下面的示例:
class AFX_EXT_CLASS Data : public CObject //This is not a template
{
public:
Data();
Data(BYTE * buffer,int size);
template
Data(const CArray& array);
template
CArray& extract(CArray& array)
{
CArchive ar(&buffer, CArchive::store);
ar >> array;
};
double extract(double&);
(...)
private:
CMemFile buffer;
}
(32)CFormView中的上下文幫助?
我想在基於CFormView類的SDI應用程序中加入真正的上下文幫助,但沒有成功.
你應該重載CMyFormView類的OnHelpHitTest函數:
LRESULT CMyFormView::OnHelpHitTest(WPARAM, LPARAM lParam)
{
LRESULT lResult = (LRESULT)0x00;
CWnd* pWndChild = ChildWindowFromPoint(CPoint(lParam),
CWP_ALL|CWP_SKIPINVISIBLE);
if (pWndChild && ::IsWindow(pWndChild->m_hWnd))
{
lResult = ::GetWindowLong(pWndChild->m_hWnd, GWL_ID);
if (lResult)
lResult += HID_BASE_COMMAND;
}
if (lResult == (LRESULT)0x00)
lResult = ::GetWindowLong(m_hWnd, GWL_ID) + HID_BASE_RESOURCE;
return lResult;
}
而後你就可使用平時用的幫助文件了,但你要保證有正確的前綴,請參照
TN028:Context-Sensitive Help Support.
例如:
ID_SOME_MENU_ITEM_OR_COMMAND_BUTTON
IDR_SOME_WINDOW_OR_DIALOG
IDP_PROMPT
IDW_CONTROL_THAT_IS_NOT_A_COMAND_BUTTON
你要確認你所使用的控件的ID包含在文件resource.hm中.
(33)CArchive類的WriteObject函數問題?
誰知道在使用CArchive類的WriteObject函數時,如何避免將類名寫入文件嗎?
WriteObject函數不只寫入了類名,並且還寫入PID(請查看TN02),若是你只想寫進一個文本文件,而且你也想用串行化,你可使用文件指針(用GetFile)來存儲字符串.或者,你可使用CFILE類來處理這個問題,若是是文本文件,你也能夠用CStdioFile類.
(34)RegisterWindowMessage中的BroadcastSystemMessage如何處理?
我想用BroadcastSystemMessage來在兩個進程之間通信,我從一個進程發送了一個用RegisterWindowMessage註冊過的消息,但在目的進程中卻沒有收到該消息.
我認爲你應該在兩個進程的最高級窗口中都註冊該消息.請看下例:
static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand"));
BEGIN_MESSAGE_MAP( Gui_Top_Level_MainFrame, Gui_MainFrame )
ON_REGISTERED_MESSAGE( sBroadcastCommand, onBroadcastCommand )
END_MESSAGE_MAP()
LRESULT Gui_MainFrame :: onBroadcastCommand( UINT aMsg, LPARAM lParam )
{
your code...
}
而後發送進行應該包含:
While the sending process would contain:
static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand"));
void Someclass :: someMethod( void )
{
::PostMessage( (HWND)HWND_BROADCAST,
sBroadcastCommand, 0,
yourMessageId );
}
(35)CListCtrl中選擇變化時如何得到通知?
我在Report View中使用了一個CListCtrl(自繪製類型),我想知道何時選擇項發生了改變.
在選擇項變化時,可使用按鈕有效或失效,按以下操做:
加入LVN_ITEMCHANGED消息處理.
void CYourClassNameHere::OnItemchangedEventList(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
*pResult = 0;
if (pNMListView->uChanged == LVIF_STATE)
{
if (pNMListView->uNewState)
GetDlgItem(IDC_DELETE)->EnableWindow(TRUE);
else
GetDlgItem(IDC_DELETE)->EnableWindow(FALSE);
}
}
(36)如何向ATL-COM對象傳送一個數組?
我想建立一個函數來向ATL-COM對象傳送數組.
以下代碼的方法用於ACTIVEX中,可能對ATL-COM也有啓發吧.
CoInitialize(NULL);
CLSID m_clsid;
USES_CONVERSION;
::CLSIDFromString(T2OLE("ROUNDANALOG.RoundAnlgAARCtrl.1"), &m_clsid);
IDispatch FAR* pObj = (IDispatch FAR*)NULL;
CString str = "UpdateControl";
BSTR bstr = str.AllocSysString();
HRESULT hr = CoCreateInstance(m_clsid, NULL, CLSCTX_ALL, IID_IDispatch,
(void**)&pObj);
SafeArrayAccessData(psa, (void**)&bstrArray);
bstrArray[0] = str.AllocSysString();
bstrArray[1] = str.AllocSysString();
SafeArrayUnaccessData(psa);
VARIANTARG* pvars = new VARIANTARG[1];
VariantInit(&pvars[0]);
pvars[0].vt = VT_ARRAY|VT_BYREF|VT_BSTR;
pvars[0].pparray = &psa;
DISPID dispid;
hr = pObj->GetIDsOfNames(IID_NULL, &bstr, 1,LOCALE_USER_DEFAULT, &dispid);
DISPPARAMS disp = {pvars, &dispid, 1,1};
hr = pObj->Invoke(dispid, IID_NULL,
LOCALE_USER_DEFAULT,DISPATCH_PROPERTYPUT,&disp,NULL, NULL, NULL);
delete[] pvars;
pObj->Release();
CoUninitialize();
在你的控制中創建以下並變量參考:
void CRoundAnlgAARCtrl::SaveFunc(const VARIANT FAR& var)
{
// TOD Add your dispatch handler code here
ASSERT(var.vt == VT_ARRAY | VT_BYREF | VT_BSTR);
SAFEARRAY* psa = *var.pparray;
}
(37)如何選擇CTreeCtrl中的節點文本進行編輯?
在向CTreeCtrl中加入一項後,有什麼方法能夠編輯該節點的文本呢?
首先設置你的CcompTreeCtrl具備TVS_EDITLABELS屬性.在設計時用控件屬性來設置在運行時用GetStyle()/SetStyle()成員函數來設置.而後請看下述代碼:
HTREEITEM CCompTreeCtrl::AddSet()
{
static int setCnt =3D 1;
HTREEITEM hItem;
CString csSet;
//create text for new note: New Set 1, New Set 2 ...
csSet.Format( _T( "New Set %d" ), setCnt++ );
hItem =3D InsertItem( csSet, IMG_CLOSEDFOLDER, IMG_CLOSEDFOLDER );
if( hItem !=3D NULL )
EditLabel( hItem );
return hItem;
}
(38)如何改變默認的光標形狀?
我試着將光標改變爲其它的形狀和顏色,但卻沒有變化.
在對話框/窗口/你須要的地方加上對WM_SETCURSOR消息的處理.
BOOL MyDialog::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TOD Add your message handler code here and/or call default
::SetCursor(AfxGetApp()->LoadCursor(IDC_MYCURSOR));
return TRUE;
//return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
你沒有成功的緣由是由於窗口類光標風格不能爲NULL.
(39)如何用鍵盤滾動分割的視口?
個人問題是當我用鼠標滾動分割窗口時,視口滾動都很正常,但用鍵盤時,卻什麼也沒有發生.
在你的視圖繼承類中加入以下兩個函數,假定該類爲CScrollerView:
void CScrollerView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
BOOL processed;
for (unsigned int i=0;i< nRepCnt&&processed;i++)
processed=KeyScroll(nChar);
if (!processed)
CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
}
BOOL CScrollerView::KeyScroll(UINT nChar)
{
switch (nChar)
{
case VK_UP:
OnVScroll(SB_LINEUP,0,NULL);
break;
case VK_DOWN:
OnVScroll(SB_LINEDOWN,0,NULL);
break;
case VK_LEFT:
OnHScroll(SB_LINELEFT,0,NULL);
break;
case VK_RIGHT:
OnHScroll(SB_LINERIGHT,0,NULL);
break;
case VK_HOME:
OnHScroll(SB_LEFT,0,NULL);
break;
case VK_END:
OnHScroll(SB_RIGHT,0,NULL);
break;
case VK_PRIOR:
OnVScroll(SB_PAGEUP,0,NULL);
break;
case VK_NEXT:
OnVScroll(SB_PAGEDOWN,0,NULL);
break;
default:
return FALSE; // not for us
// and let the default class
// process it.
}
return TRUE;
}
(40)如何在線程中處理狀態條?
在個人應用程序CWnd的繼承中有指針指向狀態條,用pStatusBar->SetPaneText(0,status,TRUE)在狀態條上顯示一些文本都很正常.但在第二個線程中調用該函數卻不行,出現hwnd警告.
當你傳送一個CWnd的指針到另一個線程時,m_hWnd將爲空.個人辦法是用PostThreadMessage傳送消息到狀態條的父類,讓它對狀態條進行處理.
(41)如何阻止WINDOWS關閉?
我有一個應用程序會不停地工做.當該程序正常運行時,該如何避免用戶關掉系統?是否是該用WM_QUERYENDSESSION.
是的,在你的主框架窗口類中使用.
// in the class header
afx_msg BOOL OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason );
// in the Message Map
ON_MESSAGE( WM_QUERYENDSESSION, OnQueryEndSession )
// in the class body
BOOL CMainFrame::OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason )
{
if( lEndReason =3D=3D ENDSESSION_LOGOFF ) {
// user is logging off
else
// Windows is going down
return( bCanExit );
}
(42)如何使一個按鈕Disable?
我使用下面代碼來Disable一個爲ID_BUTTON的按鈕,爲何會沒有變化.
GetDlgItem(IDC_BUTTON)->EnableWindow(FALSE);
CWnd類中的EnableWindow函數用來Enable或Disable一個窗口類的對象,由於CButton類繼承於類CWnd,因此你可使用來操做一個按鈕.Enable一個基於窗口類的對象能夠用如下代碼:
pWnd->EnableWindow(TRUE);
Disable一個對象可用
pWnd->EnableWindow(FALSE);
其中pWnd爲一個指向窗口對象的指針VC++中消息WM_ENABLE告訴窗口它正在Disable或Enable,但它並不能使一個窗口Enable或Disable.
(43)怎樣從MFC擴展動態鏈結庫(DLL)中顯示一個對話框?
我在過去的幾天中試着在DLL中定義的函數中顯示一個對話框,但是已經在DLL中定義好的對話框資源,在常規DLL調用時,我能夠正常的顯示出來,爲何在擴展DLL中一樣的資源我卻不能顯示.
當你在DLL中使用資源時,有些小細節須要注意,首先,在DLL運行時,必須保存DLL的實例,能夠經過AfxInitExtensionModule
static AFX_EXTENSION_MODULE extensionDLL;
extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(extensionDLL, hInstance))
return false;
}
return(true);
}
而後,每次使用DLL資源時,你必須改變資源的句柄,使其指向DLL,並保存exe的資源,以便之後正確恢復
void get_DLL_resource(void)
{
/* this function changes the resource handle to that of the DLL */
//這個函數改變資源句柄使其指向DLL
if (resource_counter == 0)
{
save_hInstance = AfxGetResourceHandle();
AfxSetResourceHandle(extensionDLL.hModule);
}
resource_counter++;
}
接着你須要其它函數來恢復資源句柄
void reset_DLL_resource(void)
{
/* this function restores the resource handle set by
'get_DLL_resource()' */
if (resource_counter > 0)
resource_counter--;
if (resource_counter == 0)
AfxSetResourceHandle(save_hInstance);
}
接下來一點很是重要,只要有可能就必須恢復資源句柄,不然,你將會遇到許多問題.緣由是可執行文件必須重畫工具條等等,好比說,若是用戶移動DLL的對話框,若是資源句柄仍然爲DLL的資源,程序就崩潰了,我發現最好恢復句柄的時機在對話框的OnInitDialog()中,這時對話框的模板等已經讀出了.
(44)想隱藏用戶界面怎麼辦?
我編了一個小巧而有趣的工具,當用戶使用時我不想讓它顯示出任何用戶界面。聽聽各位有辦法可將視關閉。
你能夠註冊一個新的窗口類型,它擁有除了WS_VISBLE屬性外的任何屬性,相似CFrameWnd,在PreCreateWindow方法中實現。另外,你能在OnCreate方法中經過設置m_nCmdShow爲SW_HIDE來實現,具體方法以下:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// hide our app
AfxGetApp()->m_nCmdShow = SW_HIDE;
return 0;
}
(45)如何實現SDI與MDI的轉換?
我想將一個編好的SDI應用程序轉換爲MDI,很明顯要有多處的改變。
你能夠這樣作:創建一個繼承於CMDIChidWnd的類,不防設爲CChldFrm.在CWinApp中做以下變化。
InitInstance()
{
. ...
//instead of adding CSingleDocTemplate
// Add CMultiDocTemplate.
pDocTemplate = new CMultiDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CSDIDoc),
RUNTIME_CLASS(CChldFrm),
// For Main MDI Frame change this frame window from
// CFrameWnd derivative ( i.e. CMainFrame )
// to your CMDIChildWnd derived CChldFrm.
RUNTIME_CLASS(CSDIView));
/// After this it is required to create the main frame window
// which will contain all the child windows. Now this window is
// what was initially frame window for SDI.
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
.....
}
在從CMDIFrameWnd中繼承的類CMainFrame代替CFramWnd後,全部的類都將從CMDIFrame繼承,而不是CFrameWnd,編譯運行後你就會發現程序已經從SDI變換到MDI。
注意:在CMainFram中必須將構造函數從private改成public.不然會出錯。
(46) CDC中的豎排文本?
在OnDraw成員函數中我想讓文本豎直對齊,但CDC相似乎不支持該處理
方法一:若是你的豎直對齊是指旋轉文本的話,下面的代碼會對你有幫助:該代碼檢查一個Check box控制,查看文本是否須要旋轉.
// m_pcfYTitle is a CFont* to the selected font.
// m_bTotateYTitle is a bool (==TRUE if rotated)
void CPage1::OnRotateytitle()
{
LOGFONT lgf;
m_pcfYTitle->GetLogFont(&lgf);
m_bRotateYTitle=
((CButton*)GetDlgItem(IDC_ROTATEYTITLE))->GetCheck()>0;
// escapement is reckoned clockwise in 1/10ths of a degree:
lgf.lfEscapement=-(m_bRotateYTitle*900);
m_pcfYTitle->DeleteObject();
m_pcfYTitle->CreateFontIndirect(&lgf);
DrawSampleChart();
}
注意若是你從CFontDialog中選擇了不一樣的字體,你應該本身設定LOGFONT的lfEscapement成員.將初始化後的lfEscapement值傳到CFontDialog中.
方法二:還有一段代碼可參考:
LOGFONT LocalLogFont;
strcpy(LocalLogFont.lfFaceName, TypeFace);
LocalLogFont.lfWeight = fWeight;
LocalLogFont.lfEscapement = Orient;
LocalLogFont.lfOrientation = Orient;
if (MyFont.CreateFontIndirect(&LocalLogFont))
{
cMyOldFont = cdc->SelectObject(&MyFont);
}
(47)如何激活變灰的彈出菜單?
在設計菜單時設定爲GRAYED的菜單項,如何在運行時激活它?
請看下面的示例代碼:
void CMyView::OnRButtonDown(UINT nFlags, CPoint point)
{
CScrollView::OnRButtonDown(nFlags, point);
CMenu *menu, *popup;
menu = new CMenu();
// load menu from resource file
menu->LoadMenu( IDR_POPUPMENU );
popup = menu->GetSubMenu(0); // item 0 is DUMMY
UINT nEnable;
nEnable = MF_BYCOMMAND|MF_GRAYED;
if( your test )
{
nEnable = MF_BYCOMMAND|MF_ENABLED;
}
popup->EnableMenuItem( ID_YOUR_ID, nEnable );
//display menu
ClientToScreen(&point);
popup->TrackPopupMenu(
TPM_LEFTALIGN | TPM_RIGHTBUTTON,
point.x, point.y, this );
delete menu;
}
(48)線程消息?
如何正確地在線程之間傳送消息?
下面的代碼將會幫你的忙:
void CThread::OnUserOpen( WPARAM wParm, LPARAM lParm )
{
UNUSED( wParm ) ;
UNUSED( lParm ) ;
AfxMessageBox("User Open", MB_OK|MB_ICONEXCLAMATION);
}
固然,也別忘了如下聲明:
class CThread : public CWinThread
{
DECLARE_DYNCREATE(CThread)
protected:
CThread(); // protected constructor used by dynamic creation
afx_msg void OnUserOpen( WPARAM wParm, LPARAM lParm );
(49)TreeCtrl控制的顯示速度太慢?
我從CTreeCtrl繼承了一個TREE控制類,重載主要是爲了改寫每一個節點的文本.我在 OnPaint函數中寫了一些代碼,但這嚴重地影響了TREE控制的滾動速度.
OnPaint函數
1.可見節點,對於GetFirstVisibleItem和GetNextVisibleItem來說,是:
a.根節點;b.父節點已展開的節點;所以,"可見"意味着"沒有被未展開的父節點隱藏".當節點滾動到客戶外時,它對上述兩個函數來說還是可見的.
2.當TREE的內容改變時,它默認只將變爲可見的節點重繪.另外其它已是可見的節點沒有必要重繪,TREE只是滾動DC的位圖而已.
上面的意思是不要繪製你不須要看的節點,那會致使速度下降.建議,測試節點矩形是否在客戶區,使得只有須要繪製的節點纔會被繪製.
void CIndentTree::OnPaint()
{
CPaintDC dc(this); // device context for painting
HTREEITEM hItem = NULL;
DRAWITEMSTRUCT dis;
CRect rc;
// redraw only visible items with indentation
for(
hItem = GetFirstVisibleItem();
hItem; hItem = GetNextVisibleItem( hItem ) )
{
if( !GetItemRect( hItem, rc, FALSE ) )
continue;
if( rc.top <= dc.m_ps.rcPaint.bottom &&
rc.bottom > dc.m_ps.rcPaint.top &&=20
rc.left <= dc.m_ps.rcPaint.right &&
rc.right > dc.m_ps.rcPaint.left )
{
dis.hwndItem = (HWND)hItem;
dis.rcItem = rc;
OnDrawItem(0, &dis, &dc);
}
}
}
OnDrawItem函數
1.刪掉以下代碼:
IMAGEINFO* pinfo = new IMAGEINFO;
...
delete pinfo;
沒有必要使用動態的IMAGEINFO變量,你能夠將其定義爲堆棧變量.
2.GetItemState和GetItemText都是使用的GetItem,所以,你只需調用一次, 就能夠從節點得到你要的全部信息.
(50)關於工具條?
我須要在程序中作一個FLAT工具條,因而我加入一個變量m_wndToolBar. 在程序主體窗口的OnCreate()函數中修改工具條狀態(0,TBSTYLE_FLAT). 在NT中運行正常,爲何在95中工具條變得透明?
在COMCTL32.DLL中的舊版本中有些小bug,繪畫時會帶來一些問題, 你可使用一些定製代碼,在http://www.codeguru.com/站點上有下載,若是你使用的是6.0版本,你也可使用下列代碼(摘自個人mainfrm.cpp文件)
m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP |
CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
用CreateEx替換ModifyStyle在同一尺寸的工具條中有些不一樣((CreateEx 創建的略小些),試一下,若是你仍然有這個問題,檢查一下COMCTL32.DLL的版本使用標準按鈕替換FLAT.
(51)關於線程消息?
真奇怪,OnUserOpen()函數和OnUserOpen(WPARAM, LPARAM)函數居然不是一個函數,編譯器在查到OnUserOpen(WPARAM, LPARAM)時,不會調用OnUserOpen 莫非有人在消息映象作了什麼手腳?
其實,這是MFC嚴密的表現,處理時,經過函數指針來調用,而該指針是由發生的事件所決定的.若是句柄不正肯定義的話,調用固然是非法的
(52)關於控件的焦點?
有誰能給我一個有效的方法:當一個控件失去焦點時,怎樣管理才能使對話框的焦點進入到正確的控件.
我有一個可運行的程序來實現,不必定很全面,但能工做.
const int WM_VALIDATE_PARAMS WM_APP + 101;
void CMyDlg::OnKillfocusName()
{
PostMessage(WM_VALIDATE_PARAMS, ED_NAME, 0L);
}
void CMyDlg::OnKillfocusAddress()
{
PostMessage(WM_VALIDATE_PARAMS, ED_ADDRESS, 0L);
}
bool CMyDlg::OnValidateParams(WPARAM rcId, LPARAM)
{
switch( rcId )
{
case ED_NAME:
if( !validateName() )
m_edName.SetFocus();
break;
case ED_ADDRESS:
if( !validateAddress() )
m_edAddress.SetFocus();
break;
default:
break;
}
return true;
}
上面的代碼能夠在用戶使用TAB鍵或鼠標操縱時,使用焦點跳至下一個控制.當你想DISABLE一個控件或重設焦點時,會有些問題,特別是在Killfocus事件中。
(53)如何捕獲鍵盤按鍵?
在CTabCtrl的子對話框怎樣才能捕獲ALT+0組合鍵
能夠在PreTranslateMessage中截取鍵盤消息。
(54)怎樣實現3D效果?
在對話框中怎樣實現Edit和Listboxes控件的3D效果?(環境95/NT VC5.0)
1). 使用帶WS_EX_CLIENTEDGE標誌的::CreateWindowEx來替換::CreateWindow 或者用CWnd::CreateEx替換CWnd::Create.
2).在創建控件以後,調用ModifyStyleEx(0, WS_EX_CLIENTEDGE).
(55)怎樣創建客戶CSocket?
我有一個客戶socket想在socket中創建一個局域聯接.我使用下列順序:
CSocket* m_pSocket;
m_pSocket = new CSMSSocket(this);
m_pSocket->Create();
m_pSocket->Bind(m_intHostPort, m_strHostIPAddress);
m_pSocket->Connect(lpszAddress, nPort);
但每次Windows Socket都定向到別的端口,怎樣才能定向到同一個端口(環境:95/NT VC5.0).
1).若是你想用Client Socket,你就不能在connect()以前調用bind(),由於局域端口地址由TCP/IP設置,咱們不可能知道下一次將使用那一個端口,我想咱們沒必要這作.
2).看一下Create()的幫助,裏面告訴咱們必須給Create()指定一個端口值, 缺省的狀況爲0,也就是由Window爲咱們選擇一個端口,經過Create()將會自動捆綁. 3).我不認爲你應該完成全部的工做,但想老是用一個相同的端口來鏈接遠程機器是一個不正確的想法.
問題出在端口數/地址結合必須惟一,若是你想在Create()中指一個固定的端口數,你只能與遠程機器建一個單個鏈接.在你所寫的代碼中是容許局域端口數可變化,能夠打開多個鏈接來取得相同的地址.在偵聽(listening)Socket中有許多理由使用一個固定端口,但在鏈接(connecting Socket中我想沒有太多的必要.
(56)Disable一個非模態對話框的客戶區?
我在OCX(對象鏈接和嵌入客戶控制程序)有一個非模態對話框.它有一個菜單以及工具條.如今我想Disable客戶區(只是客戶區,例如:設置特殊變量時顯示一個等待光標,區域裏的全部控制都不能夠處理)但在客戶區的全部控制要看上去沒有變化(也就是不能夠Disable)
能夠這樣試一下,創建一個子窗口,覆蓋對話框的所有的用戶區域,用WS_EX_TRANSPAPENT 透明類型,而後調用函數EnableWindow(FALSE),使用SetClassLong或者別的方法,在子窗口調用"忙"光標,這時光標就正確了,但對話框中的菜單還能正常使用.(說白了就是創建一個透明的子窗口蓋住全部的用戶區域,而後Disable該透明窗口,在這個窗口中設置光標爲"忙") 這個方法我沒有試過,但在一些老的Windows的書介紹過這種方法.
(57)關於使用SetClassLong和SetCapture問題
我用SetClassLong設置對話框光標時遇到了一些問題,當我使用SetCapture捕獲鼠標時,
光標形狀並無變化時,如下爲原代碼:
void CMouseMoveSimDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
myDragging = TRUE;
myhPrevCursor = (HCURSOR)SetClassLong( m_hWnd, GCL_HCURSOR,
(long)LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_SELECTCURSOR )));
SetCapture(m_hWnd);
CDialog::OnLButtonDown(nFlags, point);
}
若是移去SetCapture這一行,光標就會正確的設置,但它就不能正確的捕獲鼠標消息.那兒出問題了(環境NT4.0 VC6.0)?
1).若是我沒有記錯的話,SetClassLong隻影響調用它之後的創建的窗口.可使用 SetWindowLong來改變已存在的窗口的屬性.(爲何要用SetClassLong來改變光標形狀, 爲何不在消息WM_SETCURSOR中替換.)
2).我也不清楚問題出在那兒,但下面的方法能夠克服SetCapture帶來的問題,它是從個人程序裏面提出來的:
void CScribbleView::OnLButtonDown(UINT nFlags, CPoint point)
{
........
SetCapture(); // Capture the mouse until button up
myhPrevCursor = (HCURSOR)SetClassLong( m_hWnd, GCL_HCURSOR,
(long)LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CURSOR1)));
SetCursor(LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CURSOR1)));
........
}
void CScribbleView::OnLButtonUp(UINT nFlags, CPoint point)
{
if( GetCapture() != this )
return;
........
ReleaseCapture();
SetClassLong( m_hWnd, GCL_HCURSOR, (long)myhPrevCursor);
return;
}
(58)動畫控件?
我在對話框中使用一個動畫控件,一般我都是用CAnimated的open成員函數,並加上avi的文件名來使用動畫控件,怎樣在資源文件加入一個avi文件,做爲資源使用?
1).簡單,將avi文件引入資源,按你的喜歡來決定是屬於那一種類型的,經過ID來代替文件的名字,這樣你就可使用了.
2).在資源窗口中單擊右鍵,在彈出的菜單中選擇"Import".這時會打開文件選擇框,選擇所要的文件,這時系統將會詢問自定義資源類型,輸入avi.一個AVIS的資源組將會創立,你所選的avi文件將會出如今該組中並擁有一個ID.
3).手動在資源文件中加入一個AVI資源說明,好比:
//在這手工編輯資源文件
IDR_ANIMATION AVI res\animate.avi
(59)錯誤聲明的消息?
我給一個視發送一條消息
pView->SendMessage (MY_MESSAGE, wparam, lparam);
消息聲明被認爲是不正確的
afx_msg void OnMyMessage();
高手一看就知道這是一條命令錯誤的聲明對象,正確的聲明應該爲:
afx_msg LERSULT OnMyMessage (WPAPRAM wparam, LPARAM lparam);
由於我不使用參數,程序工做也很好,因此我不知道爲何會有這種錯誤,該過程處理完以後也沒有任何錯誤的信息出現.但如今release版本中有一個奇怪的現象(debug版本中沒有)程序會非正常終止,一般這現象發生在SendMessage()返回以後。爲何?
1.相信問題是出在錯誤的堆棧上,"thiscall"調用後就應該清除堆棧,調用者調用時將兩個參數壓入堆棧,但參數卻沒有被清除.若是你真的不須要WPARAM,LPARAM,也不須要返回值的話,你可使用ON_MESSAGE_VOID 消息聲明.在afxpriv.h中定義,是非文檔的,意思就是它不會有什麼提示或可能中斷程序, 另外,須要注意一下線程消息,注意線程消息是可變的,它們將返回void,沒有LRESULT,一樣的聲明.
2.若是你不使用WParam和LParam,爲何不在視中定義一個用戶函數來處理本身想作的?
(59)怎樣模擬鼠標動做?
這是困擾我多時的一個問題,怎樣才能實現模擬鼠標的動做,就是說要使一個程序實現鼠標的單擊,雙擊,拖放等功能.我認爲必需要實現相應的消息傳遞,但每次都不成功.
好比說,我想關閉記事本窗口,能夠傳送WM_lBUTTONDOWN和WM_LBUTTONUP(X,Y值爲記事本的右上角關閉按鈕的位置)給記事本窗口,但窗口並無關閉.固然,我也知道關閉一個窗口能夠經過傳送WM_QUIT或WM_CLOSE來實現,但鼠標的消息爲何會丟失?
請教各位大師,怎樣模式模擬實現鼠標的動做,或者給我一些怎樣發送消息來關閉窗口的建議(不是WM_CLOSE或WM_QUIT)
1).試一下window hooks,你可使用SetWindowsHookEx和JournalPlayback來處理鼠標事件.
2).你可使用文檔中的SendInput(),它能實現模擬鍵盤或鼠標事件.若是你使用NT,那也能夠用老的函數像mouse_event(),keyb_event等,在Win98中,SendInput()同樣可使用.
3).抱歉不能給你一個滿意的回答,你能夠在網站http://www.microsoft.com/enable/dev/tooldev.htm 中找到一篇關於模擬輸入的文章.
4).在NT中可使用mouse_event()傳遞事件,文檔上說這種方法已通過時了,那麼你能夠用 SendInput()替換,但找不到關於此函數的使用說明,因此我依然使用mouse_event,沒有任何問題.
(60)改變對話框標題字體?
怎樣改變對話框標題文件的字體,改變資源中對話框屬性中的字體,將改變全部的控件的字體, 卻沒有改變標題,但我只想改變標題字體,不改基餘控件的屬性.是否是我錯過一些明顯的選項. 經過查找一些MFC代碼,我發現有一個CDialog模塊,裏面調用了一引發字體方法,但該對話框不是公用的,我相信它不會給我任何幫助.
1).就我所知,對話框的標題字體和其它的窗口標題同樣,它能夠經過系統--顯示器--屬性--外觀來設置,若是本身想這樣作,我想你應該取得WM_NCPAINT句柄本身來畫出非用戶區域(包括標題在內),我從未作這樣作過,多是個錯誤的方向.
2).若是你是在CView繼承的,那你能夠在構造函數中看見以下代碼:
if( !my_CFont .CreatePointFont( 180,"Helvetica",NULL ) )
return false;
GetEditCtrl().SetFont( &my_CFont ,true )
接下來若是你想改變在對話框中的一個CEdit控件字體時,可使用如下代碼:
if( !my_CFont .CreatePointFont( 180,"Helvetica",NULL ) )
return false;
( GetDlgItem (ID_ANY_CEDIT) ) ->SetFont( &my_CFont );
(61)怎樣知道CWinThread對象的狀態?
怎樣才能知道一個線程是在運行仍是已經終止?
能夠利用線程句柄所指的::GetExitCodeThread()函數,若是線程已經結束, 它將返回一個退出代碼,若是還在運行,則返回一個STILL_ACTIVE.不過在之此前,先將 CWinThread成員對象m_bAutoDelete設置爲FALSE.另外對象在線程結束時會自動檢測到.
(62)如何調整控件對話框條的大小?
我想讓用戶可以在控制條出現時控制它的大小,在全部的例子中,在控件浮動時,改變尺寸還能夠,但在工具條停靠在框架上時就沒法調整其大小,該怎樣實現?
1)也許你錯過了一些注意點,我用的是codeguru站點上下載的CCoolDialogBar類, 在工具條停靠時也能夠從新改變其大小.
2)我開發了一個應用程序,它的界面跟你所說的差很少,讓我試着解釋一下我是怎樣作的.
1.從CDialogBar類中繼承一個類,名爲CMyBar;
2.在CMyBar中增長一個成員變量,int m_iWidth;
3.在CMyBar中的OnPaint和OnNcPaint中畫出工具條(grab bar);
4.拖動工具條時在鼠標事件時繪出軌跡;
5.釋放鼠標時,計算CMyBar新寬度.能夠經過取得當前軌跡位置,使m_iWidth等於新的寬度;
6.(重要)GetDockingFrame()->RecalcLayout();
7.在CMybar中增長一個成員方法CalcDynamicLayout;
8.在CalcDynamicLayout中,當工具條停靠時,經過計算m_iWidth返回值.
固然,這只是一個很簡單的方法,你能夠作得比這更好.
3)能夠試一下VC6.0中的CReBar類
(63)如何頂端顯示CStatic類文字?
我正寫一個小的應用程序,我想顯示一串文本(CStatic)而且不管別的應用程序運行時是否覆蓋,這些文字總會在最上面顯示.
1)用CreateEx來創建一個WS_POPUP窗口,使這個窗口總在最上面(always on top) 而後在該窗口中實現文字顯示.
2)創建窗口時用SetWindowPos()函數,用&wndTopMost做爲第一個參數,這樣就能夠完成你想作的了.
(64)消息句柄出了什麼事?
我在CParentView中爲WM_LBUTTONDOWN定義一個句柄,但我建個新的CChildView, 句柄得不處處理.
1)仔細看一下你ChildView文件中的MESSAGE_MAP,可能在第兩個參數匹配 BEGIN_MESSAGE_MAP(Child,Parent)中有着錯誤的基類.若是你是用嚮導生成器, 那麼你很容易就會發生這種事情.
2)檢查一下消息映象宏中的類名和父類名是否正確,好比BEGIN_MESSAGE_MAP (CChildView,CParentView).
若是你用本身的消息句柄手工代替了嚮導所作的,確信你的改動是正確的, 一個錯誤的參數或者加了一個"const"將會改變消息映象而不會被正確調用.
3)我猜測你必定是用類嚮導生成器來創建你的CChildView,並且在基類的選擇中必定是選了CView,本身動手在消息映象中把它修改過來.
(65)樹形控件爲什麼閃爍?
我從CTreeCtrl中繼承了一個類,以縮進的格式顯示節點,如今我碰上些問題,當樹被重畫兩次以後(一次爲缺省,另外一次爲對齊文本時)點選節點樹就會閃爍.
1)試一下LockWindowUpdate()API函數。
2)試一下加入TVS——HASBUTTONS標誌,
ModifyStyleEx(TVS_HASBUTTONS, 0);
....//drawing
ModifyStyleEx(0, TVS_HASBUTTONS);
若是它再也不閃爍,那麼在將其定義爲自畫屬性,用PreCreateWindow()中加入CS——OWNDC。
(66)怎樣才能關閉樹形控件中的滾動條?
我想關閉樹形控件的滾動條,但它依然顯示出來,怎樣才能隱藏它?
1)在創建時加入TVS_NOSCROLL,注意此時你就不能夠用鍵盤來實現翻頁,這種類型須要comct32.dll4.71版本以上才能夠,而且要在commctrl.h中定義如#define TVS_NOSCROLL 0x2000.
2)值得這樣試一下 ModifyStyle(WS_VSCROLL,0),將這段代碼放在創建以後,顯示以前。
(67)如何創建一個帶滾動條的窗口?
我想創建一個帶滾動的子窗口,但我沒有用嚮導生成器。
若是你讓你的窗口有一個滾動條,你必須首先初始化。以下
SCROLLINFO si;
si.cbSize = sizeof( SCROLLINFO );
si.fMask = SIF_PAGE | SIF_RANGE;
si.nMin = 0;
si.nMax = 100;
si.nPage = 10;
SetScrollInfo( SB_HORZ, &si );
si.nMin = 0;
si.nMax = 50;
si.nPage = 5;
SetScrollInfo( SB_VERT, &si );
若是程序運行時你的窗口內容已經改變或者窗口被改變大小而重畫時,你必須從新設置滾動條。在MFC中包含類CScrollView,它已內建滾動條。
(68)如何實現對話框的拖放?
我有一個對話框程序,想讓它實現拖放。但不管用OnDrag或OnDrop等等,全部的的消息都發送給CView類而不是CDialog類,爲何?
你應該使用COleDropTarget類,試一下這些:
class CMyOleDropTarget: public COleDropTarget
{
protected:
virtual DROPEFFECT OnDragEnter( CWnd* pWnd, COleDataObject*
pDataObject, DWORD dwKeyState, CPoint point )
{
TRACE( "DRAG Enter\n" );
return DROPEFFECT_MOVE;
};
virtual DROPEFFECT OnDragOver( CWnd* pWnd, COleDataObject*
pDataObject, DWORD dwKeyState, CPoint point )
{
TRACE( "DRAG Over\n" );
return DROPEFFECT_MOVE;
};
};
CMyOleDropTarget DropTarget;
BOOL CDlgDlg::OnInitDialog()
{
CDialog::OnInitDialog();
DropTarget.Register( this );
不要忘記調用AfxOleInit()
BOOL CDlgApp::InitInstance()
{
AfxEnableControlContainer();
AfxOleInit();
}
(69)TrackMouseEvent()怎麼了
我使用TrackMouseEvent()函數來跟蹤鼠標是否已經離開個人窗口,但在MFC中,若是我使用 ::TrackMouseEvent()系統告訴我沒有定義,爲何?
1).請使用_TrackMouseEvent
2).在commctrl.h顯示爲_TrackMouseEvent(),請注意下劃線.
3).可能TrackMouseEvent()不支持Win98(在NT中工做得很是好),建議你結合WM_MOUSEMOVE消息和 SetCapture()函數,當鼠標移出窗口時你依然能夠控制.
(70)奇怪的組合框控件
我有一個對話框程序,裏面只有幾個下拉式給合框.但當鼠標箭頭移動到組合框的上下按鈕時,會變成"6"或"9",一下子又恢復到原狀,這是爲何?
1)也許是你的操做系統有問題,不防從新起動一次也許就好了(機率很是小8%-())你也能夠試一下系統清除工具,若是這事情常常發生,可能你真的須要重裝一下95或NT,這也是個好的建議,每隔半年左右能夠重裝一下系統.
2).我猜測多是comctl32.dll文件被破壞了.
3).這個問題的緣由頗有多是系統的資源不夠,你能夠試着關閉一些程序、減小屏幕的分辨率來增長一些系統資源。
(71)關於使用MS SANS SERIF字體
我看過好多關於建立對話框、組合框等等使用MS SANS SERIF的例子,本身也作過屢次。如: m_font.CreatePointFont (80, _T("MS Sans Serif")); 或 m_font.Create (-8, ....., _T("MS Sans Serif")); 那麼想問一下:1)該字體是否在全部的版本中都能實現(包括國際版本) 2)在控制面板上有沒有更好的字體代替「SYSTEM」字體?若是有人這樣作了,那又是怎樣設置字體大小等相關設置的?我但願有一個完全的方法來選擇組合框等的字體。
1)有件事情我作過,在我全部的程序界面中都改變了字體.消息框來顯示用戶選擇的字體. 菜單,工具條以及其餘控件的字體都隨用戶意願改變.但在對話框中最好仍是用對話框編輯器, 其基本字體都是MS SANS SERIF,因此我也以這種字體來做爲全部的用戶界面. 如下爲我所作的代碼:
// here's the font I use:
SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
m_fntUI.CreateFontIndirect(&ncm.lfMessageFont);
// here's the code to change the font for a wnd and all it's children, and
resize the controls appropriately
void ChangeDialogFont(CWnd* pWnd, CFont* pFont, int nFlag)
{
CRect windowRect;
// grab old and new text metrics
TEXTMETRIC tmOld, tmNew;
CDC * pDC = pWnd->GetDC();
CFont * pSavedFont = pDC->SelectObject(pWnd->GetFont());
pDC->GetTextMetrics(&tmOld);
pDC->SelectObject(pFont);
pDC->GetTextMetrics(&tmNew);
pDC->SelectObject(pSavedFont);
pWnd->ReleaseDC(pDC);
long oldHeight = tmOld.tmHeight+tmOld.tmExternalLeading;
long newHeight = tmNew.tmHeight+tmNew.tmExternalLeading;
if (nFlag != CDF_NONE)
{
// calculate new dialog window rectangle
CRect clientRect, newClientRect, newWindowRect;
pWnd->GetWindowRect(windowRect);
pWnd->GetClientRect(clientRect);
long xDiff = windowRect.Width() - clientRect.Width();
long yDiff = windowRect.Height() - clientRect.Height();
newClientRect.left = newClientRect.top = 0;
newClientRect.right = clientRect.right * tmNew.tmAveCharWidth /
tmOld.tmAveCharWidth;
newClientRect.bottom = clientRect.bottom * newHeight / oldHeight;
if (nFlag == CDF_TOPLEFT) // resize with origin at top/left of window
{
newWindowRect.left = windowRect.left;
newWindowRect.top = windowRect.top;
newWindowRect.right = windowRect.left + newClientRect.right + xDiff;
newWindowRect.bottom = windowRect.top + newClientRect.bottom + yDiff;
}
else if (nFlag == CDF_CENTER) // resize with origin at center of window
{
newWindowRect.left = windowRect.left -
(newClientRect.right - clientRect.right)/2;
newWindowRect.top = windowRect.top -
(newClientRect.bottom - clientRect.bottom)/2;
newWindowRect.right = newWindowRect.left + newClientRect.right + xDiff;
newWindowRect.bottom = newWindowRect.top + newClientRect.bottom + yDiff;
}
pWnd->MoveWindow(newWindowRect);
}
pWnd->SetFont(pFont);
// iterate through and move all child windows and change their font.
CWnd* pChildWnd = pWnd->GetWindow(GW_CHILD);
while (pChildWnd)
{
pChildWnd->SetFont(pFont);
pChildWnd->GetWindowRect(windowRect);
CString strClass;
::GetClassName(pChildWnd->m_hWnd, strClass.GetBufferSetLength(32), 31);
strClass.MakeUpper();
if(strClass==_T("COMBOBOX"))
{
CRect rect;
pChildWnd->SendMessage(CB_GETDROPPEDCONTROLRECT,0,(LPARAM) &rect);
windowRect.right = rect.right;
windowRect.bottom = rect.bottom;
}
pWnd->ScreenToClient(windowRect);
windowRect.left = windowRect.left * tmNew.tmAveCharWidth /
tmOld.tmAveCharWidth;
windowRect.right = windowRect.right * tmNew.tmAveCharWidth /
tmOld.tmAveCharWidth;
windowRect.top = windowRect.top * newHeight / oldHeight;
windowRect.bottom = windowRect.bottom * newHeight / oldHeight;
pChildWnd->MoveWindow(windowRect);
pChildWnd = pChildWnd->GetWindow(GW_HWNDNEXT);
}
}
(72)爲何DLL在字符串表中找不到字符串
我用嚮導生成器中的"Use MFC in a Shared DLL"選項創建一個DLL,在字符串表資源中加一個字符串,當我使用csMyString.LoadString( IDS_MY_STRING ) csMyString 是空的,爲何會這樣?
1)MFC是由AfxGetResourceHandle調用資源的.因此,若是你想在你的DLL中讀出資源應該使用 AfxSetResourceHandle.你也能夠在LoadLibrary的返回值中獲得它,若是不想調用該DLL時也可使用DLLMain函數的hInstance參數.
2)試一下在你函數打頭處使用AFX_MANAGE_STATE(AfxGetStaticModuleState()) (事實上每一個被外部DLL調用的每個函數都會使用它)
3)我記得先前的列表講過這個問題,試一下如下兩種方法: 若是你是用LoadLibrary()來調用DLL的,它會返回一個句柄,你能夠在 AfxSetResourceHandle()中使用它.如:
hinstnew = Loadbrary(...);
...
hinstOld = AfxGetResourceHandle();
AfxSetResourceHandle(hinstnew);
LoadString(IDS_MY_STRING);
AfxSetResourceHandle(hinstOld); // remember to set this back,
// or your night won't be nice.
若是你不是用LoadLibrary來調用DLL又該怎樣辦呢?你可使用 GetModule("You DLL Name")來取得用戶句柄,剩下的就好辦了.
(73)關於複選框的文本顏色
有誰知道怎樣才能改變複選框中的文本選項的顏色?
1)你有沒有試過在控件中使用OnCtlColor,它將在重畫任何控件以前被調用,因此你能夠有機會來改變文本選項的顏色。
2)爲何你必定要用PreDrawItem()?你是想在裏面作一些特定的代碼?我認爲DrawItem() 也能處理。在調用重畫函數以前取得索引號並改變顏色。
(74)系列化與版本的問題
我須要使用系列化來讀取個人文件,爲了保證文件能在各個版本中都能實現,我做了儘量的努力,爲何會不成功.
答:下面的代碼是我過去使用過的,但願能對你有所幫助
// Use this macro to fix the versioning problem in the MFC
// Place it at the beginning of your CMyObject::Serialize implementation -
// it will guarantee that the correct version of the class is written to
// and read from the archive
//
// Usage: SERIALIZE_VERSION(CMyObject)
#define SERIALIZE_VERSION(this_class) ar.SerializeClass(this_class::GetRuntimeClass());
// For classes which cannot use IMPLEMENT_SERIAL (such as abstract
// base classes). This guarantees the object can have
[Read/Write][Class/Object]
// called on it by placing a schema number in it. It also puts it in the
// list of known class names (AFX_CLASSINIT).
// Note: this is almost the same as IMPLEMENT_SERIAL_ABC
// in "MFC Internals", but this version uses AFX_CLASSINIT,
// with the result that it works!
#define DECLARE_DYNAMIC_SERIAL(class_name) DECLARE_SERIAL(class_name)
#define IMPLEMENT_DYNAMIC_SERIAL(class_name, base_class_name, wSchema) _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, NULL) static const AFX_CLASSINIT
_init_##class_name(RUNTIME_CLASS(class_name)); CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) { pOb = (class_name*)
ar.ReadObject(RUNTIME_CLASS(class_name)); return ar; }
或者也能夠這樣實現:
CMySerialRootDerivedClass::Serialize(CArchive& ar)
{
//CMySerialRoot::Serialize(ar); // <- do not call this here
if (ar.IsStoring())
{
... store derived stuff here
}
else
{
int nVersion = ar.GetObjectSchema();
switch(nVersion)
{
case 1:
... load derived version 1 stuff here
break;
case 2:
... load derived version 2 stuff here
break;
default:
// report unknown version of
// this object
break;
}
}
// serialize the base class version information
// -> then serialize the base class
ar.SerializeClass(RUNTIME_CLASS(CMySerialRoot));
CMySerialRoot::Serialize( ar );
}
(75)在一個控件內檢測並使用ON_COMMAND消息
有一個控件(繼承CWnd)在CRormView.可不能夠將它的ID在ON_COMMAND消息中發出,若是用pCtrl->OnCommand(ID_VIEW_ZOOMIN,..), 編譯器會報告參數不匹配,該怎麼辦?
1)爲何不用pCtrl->Post/SendMessage (WM_COMMAND, ID_VIEW_ZOOMIN)
2)經過重載CYourFormView::OnCmdMsg就能夠.如:
BOOL CYourFormView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
return pCtrl->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)
|| CFormView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
3)使用WM_COMMAND消息,看一下關於WM_COMMAND和CWnd::PostMessage()的幫助.
DWORD wParam;
HIWORD(wParam) = wNotifyCode; // notification code
LOWORD(wParam) = ID_VIEW_ZOOMIN;
pCtrl->PostMessage(WM_COMMAND,(WPARAM)wParam, pCtrl->m_hWnd);
4)可以這樣作,但不是象大家作法,大家必須獲得控件的句柄或CWnd指針而後在句柄中使用::SendMessage() or ::PostMessage();在CWnd中使用 CWnd::SendMessage() or CWnd::PostMessage() 試一下這個.
CMyCtrl *pCtrl;
/* call GetDlgItem() from an instance of your form view */
pCtrl = ( CMyCtrl * )GetDlgItem( IDC_MYCONTROL );
if( pCtrl != NULL && ::IsWindow( pCtrl->GetSafeHwnd( ) )
pCtrl->SendMessage( WM_COMMAND, /*wParam*/, /*lParam*/ );
// see WM_COMMAND description on help/MSDN for a detailed explanation of
// {W|L}PARAM
(76)爲什麼MDI程序中有子窗口打開時主應用程序不能關.
我在MDI程序中增長了一個CRichEditView文檔模板,在子窗口視中我增長了下面一些代碼.
StartReport (void)
{
CReportFrame *rpt;
CReportDoc *rptDoc;
// First get the right document template
POSITION pPos = theApp.GetFirstDocTemplatePosition();
theApp.GetNextDocTemplate ( pPos );
theApp.GetNextDocTemplate ( pPos );
CDocTemplate *pTemplate = theApp.GetNextDocTemplate ( pPos );
// Verify validity
ASSERT(pTemplate != NULL);
ASSERT_KINDOF(CDocTemplate, pTemplate);
// Create the frame
rptDoc = new CReportDoc;
rpt = (CReportFrame*)pTemplate->CreateNewFrame ( rptDoc, NULL );
pTemplate->InitialUpdateFrame (rpt, rptDoc);
// Get access to the display area
CReportView *rptView = static_cast(rpt->GetActiveView());
CRichEditCtrl &rptCtrl = rptView->GetRichEditCtrl();
}
CReportFrame繼承於CMDIChildWnd
CReportDoc繼承於CRichEditDoc
CReportView繼承於from CRichEditView
若是我關閉程序前不關閉新建的視,調試器將認爲程序依然在運行(程序管理器中依然存在) 我須要用調試菜單中的stop debugging來關閉程序;若是我手工關閉該視,程序將會正常關閉.若是有什麼不一樣的話,在手工關閉新的視以前程序會詢問是否保存. 那麼怎樣我才能關閉程序呢?
1)我也碰上過對話框,窗口不能自動關閉的狀況,這主要是由於繼承的對象不正確所形成的。一般應該在主程序中設置AfxGetMainWnd().
你的程序讓我搞糊塗了,一連使用了多個GetNextDocTemplate(pPos),在這些文檔指針是NULL時一般會引發一些循環.在你的文檔模板中是否已經精心算好了數目?這樣可能會產生些bugs 我建議找出當前的文檔模板用CDocTemplate::CreateNewDocument()來代替你的"new CReportDoc"
2) 記住一個公共規則,關閉程序前要關閉全部的視.
(77)滾動視中LPtoDP失敗
在WINDOWS98/95中,當你給光標指針位置大於32767或者小於-21768函數CDC::LPtoDP 將失敗,程序工做在NT上但在95/98中用滾動視工做時卻出現了問題. LPtoDP是在下面函數中被調用的:
SetScrollSizes(MM_HIMETRIC, sizeTotal);
函數是在CScrollView中調用的.我使用的是HIMETRIC映射方式,在我想將A4擴大150%時這個問題就會出現。怎樣才能解決這個問題?
1)在95中確實存在這樣的問題,95中的GDI不是32位的.當咱們開發一個程序有編輯矢量圖象時手動而不是由LPtoDP()函數來完成轉換.(在NT中也存在一樣的問題)
2)簡言之,CScrollView或CWnd之因此32位參數會失敗是由於95/98並非真正的32 位操做系統,裏面仍然包含16位代碼.好比Scrollbars仍是隻接受16位的值來調整範圍. NT是一個真正的32位操做系統,就沒有這些困惑.
在95中不得不面對相似的滾動大文檔的問題時,咱們只能另外寫些代碼來實現滾動的實際位置,當它超出-32K或+32K時,你也必須在你的應用中作些映射.
做爲一個有關的注意點(可能你已經碰上過這個問題)若是在MFC處理滾動消息時,如: void CSomeWnd::OnVScroll (UINT nSBCode,UINT nPos, CScrollBar *pscrollBar) 中的 nPos參數只有16位長.克服這個限制可使用SCROOLINFO結構運行::GetScrollInfo.SCROLLINFO 結構中的nTrackPos是一個真正的32位。
(78)ODBC許可問題
我有個程序想經過ODBC來使用一個MS Access數據庫,可是卻碰上了錯誤,系統顯示 "Records can't be read; no read permission on table SESSION".(記錄不能讀, 表單不容許讀)
)首先我假設access數據庫有一個缺省的用戶爲"admin",能夠這樣完成"ODBC;UID=admin". 而後,當你繼承CRecordset類時你就沒必要帶參數打開,但下面的方法可能更好些:
Open(CRecordset::dynaset, NULL,CRecordset::useBookmarks | CRecordset::skipDeletedRecords)
固然你必須提供DSN表示鏈接名字的數據庫在ODBC之下.
(79)怪異的字體
咱們有一個MFC應用程序,主窗口是在客戶區域內畫些文本和圖形. 咱們但願能在客戶區域內顯示文本,在不須要時則擦除.因此咱們先獲得一個DC(CClientDC), 而後設置字體和文本顏色就開始寫文本,在擦除時,咱們用一樣的字體,一樣的地方用背景色重寫文本.
這種方法絕大部分狀況下都工做得很好,但偶爾文本並不能徹底擦除,有些像素點依然可見. 好象在寫文本時比一般略微胖了些,就象用粗體同樣.字體是在寫文本時使用的,之後也沒有進行過任何的調整. 下面是咱們使用的寫與擦除的函數.
void CSign::DrawSignName(CDC* pDC)
{
int OldBkMode;
// select the appropriate font
CFont* pOldFont = (CFont*) pDC->SelectObject(pSignNameFont);
OldBkMode = pDC->SetBkMode(TRANSPARENT);
// determine the colour of the text
if (IsSignNameVisible())
pDC->SetTextColor(aColours[SIGN_NAME_COLOUR]);
else
pDC->SetTextColor(aColours[DEVICE_INVISIBLE_COLOUR]);
// draw the text
pDC->TextOut(m_pointNameCoords.x, m_pointNameCoords.y, m_strName);
// restore the previously used font and background mode
pDC->SelectObject(pOldFont);
pDC->SetBkMode(OldBkMode);
} // DrawSignName
函數是在消息句柄中調用的,而參數中的DC是這樣創建的:
CClientDC dc(AfxGetMainWnd()).
字體是在程序初始化時創建的:
pSignNameFont = new CFont;
pSignNameFont->CreateFont(10,5,0,0,150,
FALSE,FALSE,0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS, "Helvetica");
是否是一次使用兩個指向同一個客戶窗口的DC有問題?程序中的DrawSignName()被多個消息句柄調用。
1)加入如下代碼:
{
m_strName.Empty();
Invalidate();
UpdateWindow();
more stuff;;;
}
上面代碼會產生一個WM_ERASEBKGND消息,將會用背景色填滿窗口,而後再調用OnDraw(),這時只要將字符串置空便可。
2)我不清楚爲何程序不能正常工做,但我有個主意(它會更快些)能夠在顯示文本的地方用一個背景色的矩形畫一下便可。我也不清楚爲何大家爲何要用透明文本,它將會給圖形系統帶來大量的工做。字體之因此有這種狀況,是否大家安裝了文本輸出的圖形保真軟件?它會給大家帶來困惑的。
3)你只想簡單的用一個指針來保存一個指向DC的GDI對象,並試圖再次調用它時指望它能指向正確的對象。恕我直言,這不是正確的方法(我不知道是否這是顯示不正常的惟一緣由)將它轉化爲一個Windows句柄纔是正確的:
//
// Creating:
//
pSignNameFont = new CFont;
pSignNameFont->CreateFont(10,5,0,0,150,
FALSE,FALSE,0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS, "Helvetica");
// Now converting into a windows handle
m_hSNFont = (HFONT) pSignNameFont->GetSafeHandle();
直接保存一個對象是不安全的。
(80)自畫列表框樣例
好久之前,有人散發關於自畫列表框控件代碼,而自畫列表框外觀就象一個標準列表框,在那時我就有個想法想把程序員開發的全部自畫控件的代碼懼收集起來,這樣程序員們就可使用現存的代碼了。
我想問一下在1996年關於MFC站點那兒有才能關於列表框或其它控件的代碼?
1)自畫列表框代碼以下,看看是否是你所想要的。
Header file
class CCustomListBox : public CListBox
{
public:
// Operations
DECLARE_DYNCREATE(CCustomListBox)
int AddLBItem(LPSTR);
void HandleSelectionState(LPDRAWITEMSTRUCT lpdis);
void HandleFocusState(LPDRAWITEMSTRUCT lpdis);
virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);
};
cpp file
IMPLEMENT_DYNCREATE(CCustomListBox, CListBox)
int CCustomListBox::AddLBItem(LPSTR itemStr)
{
AddString((LPCSTR)itemStr);
return 0;
}
void CCustomListBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
if ((lpDIS->itemState & ODS_SELECTED) &&
(lpDIS->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))
{
pDC->InvertRect(&lpDIS->rcItem);
pDC->DrawFocusRect(&lpDIS->rcItem);
}
if (!(lpDIS->itemState & ODS_SELECTED) &&
(lpDIS->itemAction & ODA_SELECT))
{
pDC->InvertRect(&lpDIS->rcItem);
pDC->DrawFocusRect(&lpDIS->rcItem);
}
}
void CCustomListBox::HandleSelectionState(LPDRAWITEMSTRUCT lpdis)
{
// Ordinarily could check for "if (lpdis->itemState & ODS_SELECTED)"
// and do drawing for selected state, "else" draw non-selected state.
// But second call to InvertRect restores rectangle to original
// state, so will just call function whether selected or unselected.
::InvertRect (lpdis->hDC, (LPRECT)&lpdis->rcItem);
}
void CCustomListBox::HandleFocusState(LPDRAWITEMSTRUCT lpdis)
{
// Ordinarily would check for "if (lpdis->itemState & ODS_FOCUS)"
// and do drawing for focus state, "else" draw non-focus state.
// But second call to DrawFocusRect restores rectangle to original
// state, so will just call function whether focus or non-focus.
// New to Windows 3.0, this function draws a black dashed-rect
// border on the border of the specified rectangle
::DrawFocusRect( lpdis->hDC, (LPRECT) &lpdis->rcItem );
}
2)http://toronto.planeteer.com/~zalmoxe/
(81)CWnd::GetMenu()的問題
我有個程序用下面代碼:
CWnd *pWnd = CWnd::GeForegroundWindow();
if (pWnd == NULL) return FALSE;
CMenu *pMenu = pWnd->GetMenu();
if (pMenu == NULL) return FALSE;
for (int i = 0; i < pMenu->GetMenuItemCount; i++) {
pMenu->GetMenuItemID(...);
pMenu->GetMenuString(...);
}
上述代碼工做除了在IE窗口外,別的窗口工做都很正常,請問怎樣才能在IE窗口中正常使用,若是不是用這種方法,那又該用什麼方法?
IE有一個定義菜單,是用自定義系列控件中的彈出菜單。因此你就不能再使用枚舉這種方法了,試一下處理WM_INITMENUPOPUP或WM_INITMENU。在VC的CD中有相似的例子(關於剪切與複製)你獲得消息句柄時就能夠列出全部的菜單項。上面的代碼之所不工做多是由於微軟的自畫菜單項的保存菜單項用了不一樣的格式,想要明白菜單和畫標是不是自畫的,你能夠用這種方法測試lpmii->fType & MFT_OWNERDRAW.Ipmii是一個菜單結構,返回獲得的菜單項信息。lpmii->dwTypeData 返回(菜單)項目的類型,若是dwTypeData返回的值沒有什麼用的話還有一個機會,lpmii->dwItemData將指向一個(程序)開始時的菜單項中的字符串結構。以上方法比較好,由於如今好多程序都使用自定義菜單。
(82)用MFC製做彈出窗口
我正在試着用MFC來製做彈出窗口,我看過一些關於創建彈出窗口的文章,它們是使用 CWnd對象的。但在文檔,視窗結構中是怎樣實現的?
你能夠創建一個非模態對話框(使用Create函數),你能夠在任何創建窗口,子窗口等。若是你必定要在文檔、視窗結構中實現,你也能夠用CCreateContest類。下面是創建MDI窗口的例子:
{
LPCTSTR lpszClassName = NULL;
CCreateContext cContext;
cContext.m_pNewViewClass = RUNTIME_CLASS ( CMyView )
DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW &
~WS_THICKFRAME & ~WS_MAXIMIZEBOX;
// TOD Add your specialized code here and/or call the base class
if ( CMDIChildWnd::Create(lpszClassName, lpszWindowName, dwStyle,
pParentWnd->rectDefault, pParentWnd, &cContext) )
{
InitialUpdateFrame ( NULL, TRUE );
CScrollView *pView = ( CScrollView* ) GetActiveView();
if ( pView )
pView->ResizeParentToFit ( FALSE );
return TRUE;
}
else
return FALSE;
}
CCreateContext有一個成員爲m_pCurrentDoc,你能夠用它來將一個文檔分配到相應的窗口上.
(83)怎樣取消一個彈出式菜單
我有一個應用程序不顯示窗口(創建窗口時使用了SW_HIDE參數),它只在任務條顯示一個圖標,我是這樣作的:
NOTIFYICONDATA tnid;
tnid.cbSize = sizeof(NOTIFYICONDATA);
tnid.hWnd = m_hWnd;
tnid.uID = 1;
tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
tnid.uCallbackMessage = MYWM_NOTIFYICON;
tnid.hIcon = AfxGetApp()->LoadIcon( IDI_ICON1 );
lstrcpyn(tnid.szTip, "Giroimag Image Mail Exchange", strlen("Giroimag Image Mail Exchange")+1);
Shell_NotifyIcon(NIM_ADD, &tnid);
當我點擊任務條時,程序會顯示一個彈出菜單:
CMenu m_Menu;
m_Menu.CreatePopupMenu();
m_Menu.AppendMenu( MF_STRING, IDM_ABOUT, "Op&1" );
m_Menu.AppendMenu( MF_SEPARATOR, 0 );
m_Menu.AppendMenu( MF_STRING, IDM_CONFIG, "Op&2" );
m_Menu.AppendMenu( MF_STRING, IDM_STATUS, ""Op&3" );
m_Menu.AppendMenu( MF_SEPARATOR, 0 );
m_Menu.AppendMenu( MF_STRING, IDM_SEND, "Op&4" );
m_Menu.AppendMenu( MF_STRING, IDM_RECEIVE, "Op&5" );
m_Menu.AppendMenu( MF_SEPARATOR, 0 );
m_Menu.AppendMenu( MF_STRING, IDM_CLOSE, "Op&6" );
POINT p;
GetCursorPos( & p );
m_Menu.TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, this );
到這爲止,程序運行很正常,問題在於若是我不選擇任何菜單該怎樣取消它?我覺得按ESC或者在菜單外面點擊就能夠取消,但事實並非這樣。我也試過用WIN32API中的TrackPopupMenuEx函數但沒有用,到底我該怎麼作?
1)最簡單的方法在消息映象中加"Cancel Menu"命令便可。
2)儘管你的主窗口不可見,但在你能夠在調用m_Menu.TrackPopupMenu();時將其置爲最前。
3)在你彈出菜單以前,設置你的窗口爲最前窗口,調用下面的代碼,問題就會迎刃而解。
POINT p;
GetCursorPos( & p );
// Increase the thread priority by invoking SetForegroundWindow.
SetForegroundWindow();
m_Menu.TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, this );
4)調用TrackPopupMenu()以前,你必須先調用SetForegroundWindow( m_hWnd ),而後調用PostMessage( m_hWnd, WM_NULL, 0, 0 ):
POINT point; GetCursorPos( &point ); SetForegroundWindow( m_hWnd ); TrackPopupMenu( hPopup, TPM_RIGHTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, point.x, point.y, 0, m_hWnd, 0 ); PostMessage( m_hWnd, WM_NULL, 0, 0 );