(1) 如何通过代码获得应用程序主窗口的 指针?
主窗口的 指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现。
应用
实例:
AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED)
//使程序最大化.
(2) 确定应用程序的路径
Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名。
Example:
TCHAR
exeFullPath[MAX_PATH] // MAX_PATH是已定义宏
GetModuleFileName(NULL,exeFullPath,MAX_PATH)
(3) 如何在程序中获得其他程序的 图标?
两种方法:
(1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle,
(2) SDK函数 SHGetFileInfo 获得有关文件的很多信息,如大小图标,属性,
类型等.
Example(1):
在程序窗口左上角显示 NotePad图标.
void CSampleView: OnDraw(CDC * pDC)
{
if( :: SHGetFileInfo(_T("c://pwin95//notepad.exe"),0, &stFileInfo,sizeof(stFileInfo),SHGFI_ICON))
{
pDC ->DrawIcon(10,10,stFileInfo.hIcon);
}
}
Example(2):
同样功能,
Use ExtractIcon Function
void CSampleView:: OnDraw(CDC *pDC)
{
HICON hIcon = ::ExtractIcon(AfxGetInstanceHandle(),_T ("NotePad.exe"),0);
if (hIcon &&hIcon!=(HICON)-1)
pDC->DrawIcon(10,10,hIcon)
}
说明: 获得notepad.exe的路径正规上来说用GetWindowsDirectory函数得到, 如果是调用 win95下的画笔,应该用访问注册表的方法获得其路径,要作成一个比较考究的程序,考虑应该全面点.
(4) 获得各种目录信息
Windows目录: Use "GetWindowsDirectory"
Windows下的system目录: Use "GetSystemDirectory"
temp目录: Use "GetTempPath"
当前目录: Use "GetCurrentDirectory"
请注意前两个函数的第一个参数为目录变量名,后一个为缓冲区后两个相反.
(5) 如何自定义消息
(1) 手工定义消息,可以这么写
#define WM_MY_MESSAGE(WM_USER+100),
MS 推荐的至少是 WM_USER+100
(2)写消息处理函数,用
WPARAM,LPARAM返回LRESULT.
LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam)
{
//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);
}
(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 (Cpo
int po
int ) { 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= I
strlen (Ipaznew) TCHAR szOld [256] //fast check to see if text really changes (reduces flash in the controls ) if (nNewLen >_contof (szOld) || : : GetWindowText (hWndCrtl, szOld , _countof (szOld) !=nNewLen || 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"))