Visual C++编程技巧

1. 如何获取应用程序的实例句柄?
            应用程序的 实例句柄保存在CWinAppIm_hInstance 中,可以这么调用
            AfxGetInstancdHandle获得句柄.
            Example: HANDLE hInstance=AfxGetInstanceHandle();

2. 如何通过代码获得应用程序主窗口的指针?
            主窗口的 指针保存在CWinThread::m_pMainWnd中,调用 AfxGetMainWnd实现。
            AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //使程序最大化.
 

3. 如何在程序中获得其他程序的 图标?
            两种方法:
            (1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle,
            (2) SDK函数 SHGetFileInfo获得有关文件的 很多信息,如大小图标,属性,类型等.
            Example(1): 在程序窗口左上角显示 NotePad图标.
            void 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 的重新引导?
            这是个很简单又是编程中经常要遇到的问题.
            第一问,向窗口发送 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开发人员指南一书有比较详细的介绍,这里就不再多说乐。
            第二问,Use ExitWindowsEx Function 函数控制系统是重新引导,还是重启 windows.
            前面已经有人讲过乐,就不再提了。

5. 怎样加栽其他的应用程序?
            我记得这好象是出场频度很高的问题。
            三个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);

6. 确定应用程序的 路径
            前些天好象有人问过这个问题.
            Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名。
            Example:
            TCHAR exeFullPath[MAX_PATH]; // MAX_PATH在API中定义了吧,好象是128
            GetModuleFileName(NULL,exeFullPath,MAX_PATH)

7. 获得各种目录信息
            Windows目录: Use GetWindowsDirectory“
            Windows下的system目录: Use GetSystemDirectory
            temp目录: Use GetTempPath
            当前目录: Use GetCurrentDirectory
            请注意前两个函数的第一个参数为 目录变量名,后一个为缓冲区; 后两个相反.

 8. 如何自定义消息
            也有人问过的,其实不难。
            (1) 手工定义消息,可以这么写 #define WM_MY_MESSAGE(WM_USER+100), MS 推荐的至
            少是 WM_USER+100;
            (2)写消息处理函数,用 WPARAM,LPARAM返回LRESULT.
            LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam)
            {
            //加入你的处理函数
            }
            (3) 在类的 AFX_MSG处进行声明,也就是常说的宏映射

9. 如何改变窗口的图标?
            向窗口发送 WM_SECTION消息。
            Example:
            HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON);
            ASSERT(hIcon);
            AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM) hIcon);

10. 如何改变窗口的缺省风格?
            重栽 CWnd:: PreCreateWindow 并修改CREATESTRUCT 结构来指定窗口风格和其他创建
            信息.
            Example: Delete Max Button and Set Original Window's Position and
            Size
            BOOL CMainFrame:: PreCreateWindow (CREATESTRUCT &cs)
            {
            cs.style &=~WS_MAXINIZEMOX;
            cs.x=cs.y=0;
            cs.cx=GetSystemMetrics(SM_CXSCREEN/2);
            cs.cy=GetSystemMetrics(SM_CYSCREEN/2);
            return CMDIFramewnd ::PreCreateWindow(cs);
            }

11. 如何将窗口居中显示?
            Easy, Call Function CWnd:: Center Windows
            Example(1): Center Window( ); //Relative to it's parent
            // Relative to Screen
            Example(2): Center Window(CWnd:: GetDesktopWindow( ));
            //Relative to Application's MainWindow
            AfxGetMainWnd( ) -> Center Window( );

12. 如何让窗口和 MDI窗口一启动就最大化和最小化?
            先说窗口。
            在 InitStance 函数中设定 m_nCmdShow的 取值.
            m_nCmdShow=SW_SHOWMAXMIZED ; //最大化
            m_nCmdShow=SW_SHOWMINMIZED ; //最小化
            m_nCmdShow=SW_SHOWNORMAL ; //正常方式
            MDI窗口:
            如果是创建新的应用程序,可以用 MFC AppWizard 的Advanced 按钮并在MDI 子窗口风
            格组中检测最大化或最小化; 还可以重载 MDI Window 的PreCreateWindow函数,设置
            WS_MAXMIZE or WS_MINMIZE;如果从 CMDIChildWnd 派生,调用 OnInitialUpdate函数中
            的 CWnd::Show Window来指定 MDI Child Window的 风格。

13. 如何使程序保持极小状态?
            很有意思的 问题
            这么办: 在恢复程序窗体大小时, Windows 会发送WM_QUERY-OPEN 消息,用
            ClassWizard设置成员函数 OnQueryOpen() ,add following code:
            Bool CMainFrame:: OnQueryOpen( )
            {
            Return false;
            }

14. 如何限制窗口的大小?
            也就是 FixedDialog 形式。 Windows 发送 WM_GETMAXMININFO消息来跟踪, 响应它,在
            OnGetMAXMININFO 中写代码:

 15. 如何使窗口不可见?
            很简单,用SW_HIDE 隐藏窗口,可以结合 FindWindow,ShowWindow 控制.

16. 如何使窗口始终在最前方?
            两种途径.
            BringWindowToTop(Handle);
            SetWindowPos函数,指定窗口的 最顶风格,用WS_EX_TOPMOST扩展窗口的 风格
            Example:
            void ToggleTopMost( CWnd *pWnd)
            {
            ASSERT_VALID(pWnd);
            pWnd ->SetWindowPos(pWnd-> GetStyle( ) &WS_EX_TOPMOST)?
            &wndNoTopMOST: &wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE};
            }
  

17. 如何创建一个字回绕的CEditView
            重载CWnd : : PreCreateWindow 和修改CREATESTRUCT 结构,关闭CEditView 对象的
            ES_AUTOHSCROLL和WS_HSCROLL风格位, 由于CEditView : : PreCreateWindow显示设
            置cs. style,调用基类函数后要修改cs . style。
            BOOL CSampleEDitView : : PreCreateWindow (CREATESTRUCT&cs)
            {
            //First call basse class function .
            BOOL bResutl =CEditView : : PreCreateWindow (cs) ;
            // Now specify the new window style .
            cs.style &= ~ (ES_AUTOHSCROLL |WS_HSCROLL);
            return bResult ;
            }

18. 通用控件的显示窗口
            MFC提供了几个CView 派生的视窗类, 封装了通用控件的功能,但仍然使用工作框文档
            显示窗口体系结构:CEditView 封装了编辑控件,CTreeView 保持了树列表控件,
            CListView封装了列表显示窗口控件,CRichEditView可以处理多种编辑控件。

19. 移动窗口
            调用CWnd : : SetWindowPos 并指定SWP_NOSIZE 标志。目的位置与_____父窗口有关(顶层
            窗口与屏幕有关)。调用CWnd : : MoveWindow时必须要指定窗口的大小。
            //Move window to positoin 100 , 100 of its parent window .
            SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE |SWP_NOAORDER);

20. 重置窗口的大小
            调用CWnd: : SetWindowPos 并指定SWP_NOMOVE标志, 也可调用CWnd : : MoveWindow
            但必须指定窗口的位置。
            // Get the size of the window .
            Crect reWindow ;
            GetWindowRect (reWindow );
            //Make the window twice as wide and twice as tall .
            SetWindowPos (NULL , 0 , 0 , reWindow . Width ( ) *2,
            reWindow . Height () * 2, SWP_NOMOVE |SWP_NOZORDER );

21. 如何单击除了窗口标题栏以外的区域使窗口移动
            当窗口需要确定鼠标位置时Windows 向窗口发送WM_NCHITTEST 信息,可以处理该信息
            使Windows 认为鼠标在窗口标题上。对于对话框和基于对话的应用程序,可以使用
            ClassWizard 处理该信息并调用基类函数, 如果函数返回HTCLIENT 则表明鼠标在客房
            区域,返回HTCAPTION表明鼠标在Windows的标题栏中。
            UINT CSampleDialog : : OnNcHitTest (Cpoint point )
            {
            UINT nHitTest =Cdialog: : OnNcHitTest (point );
            return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest ;
            }
            上述技术有两点不利之处, 其一是在窗口的客户区域双击时, 窗口将极大;其二, 它
            不适合包含几个视窗的主框窗口。还有一种方法,当用户按下鼠标左键使主框窗口认为
            鼠标在其窗口标题上,使用ClassWizard在视窗中处理WM_LBUTTODOWN 信息并向主框窗
            口发送一个WM_NCLBUTTONDOWN信息和一个单击测试HTCAPTION。
            void CSampleView : : OnLButtonDown (UINT nFlags , Cpoint point )
            {
            CView : : OnLButtonDow (nFlags , pont );
            //Fool frame window into thinking somene clicked on its caption bar
.
            GetParentFrame ( ) —> PostMessage (
            WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (poitn .x , point .y) );
            }
            该技术也适用于对话框和基于对的应用程序,只是不必调用CWnd : : GetParentFrame 。
            void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point )
            {
            Cdialog : : OnLButtonDow (nFlags, goint );
            //Fool dialog into thinking simeone clicked on its caption bar .
            PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x ,
            point. y ) )
            }

22. 如何改变视窗的背景颜色
            Windows 向窗口发送一个WM_ERASEBKGND 消息通知该窗口擦除背景,可以使用
            ClassWizard 重载该消息的缺省处理程序来擦除背景(实际是画),并返回TRUE 以防止
            Windows擦除窗口。
            //Paint area that needs to be erased.
            BOOL CSampleView : : OnEraseBkgnd (CDC* pDC)
            {
            // Create a pruple brush.
            CBrush Brush (RGB (128 , 0 , 128) );
            // Select the brush into the device context .
            CBrush* pOldBrush = pDC—>SelcetObject (&brush);
            // Get the area that needs to be erased .
            CRect reClip ;
            pDC—>GetCilpBox (&rcClip);
            //Paint the area.
            pDC—> PatBlt (rcClip.left , rcClip.top ,
            rcClip.Width ( ) , rcClip.Height ( ) , PATCOPY );
            //Unselect brush out of device context .
            pDC—>SelectObject (pOldBrush );
            // Return nonzero to half fruther processing .
            return TRUE;
            }

23. 如何改变窗口标题
            调用CWnd : : SetWindowText可以改变任何窗口(包括控件)的标题。
            //Set title for application's main frame window .
            AfxGetMainWnd ( ) —> SetWindowText (_T(Application title) );
            //Set title for View's MDI child frame window .
            GetParentFrame ( ) —> SetWindowText (_T (MDI Child Frame new title)
            );
            //Set title for dialog's push button control.
            GetDigitem (IDC_BUTTON) —> SetWindowText (_T (Button new title ) );
            如果需要经常修改窗口的标题(注:控件也是窗口),应该考虑使用半文档化的函数
            AfxSetWindowText。该函数在AFXPRIV.H中说明,在WINUTIL.CPP中实现,在联机帮助
            中找不到它,它在AFXPRIV.H中半文档化, 在以后发行的MFC中将文档化。
            AfxSetWindowText的实现如下:
            voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew )
            {
            itn nNewLen= Istrlen (Ipaznew);
            TCHAR szOld [256];
            //fast check to see if text really changes (reduces flash in the
            controls )
            if (nNewLen >_contof (szOld) ||
            : : GetWindowText (hWndCrtl , szOld , _countof (szOld) !=nNewLen ||
            Istrcmp (szOld , IpszNew )! = 0
            {
            //change it
            : : SetWindowText (hWndCtrl , IpszNew );
            }
            )

24. 如何防止主框窗口在其说明中显示活动的文档名
            创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位, 如果不希望在说明中
            自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard 重置CWnd: :
            PreCreateWindow并关闭FWS_ADDTOTITLE风格。
            BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs)
            {
            //Turn off FWS_ADDTOTITLE in main frame .
            cs.styel & = ~FWS_ADDTOTITLE ;
            return CMDIFrameWnd : : PreCreateWindow (cs );
            }
            关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具-_Âu有空标题的窗口,可以调用CWnd: :
            SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。

25. 如何获取有关窗口正在处理的当前消息的信息
            调用CWnd: : GetCurrentMessage 可以获取一个MSG指针。例如,可以使用ClassWizard
            将几个菜单项处理程序映射到一个函数中,然后调用GetCurrentMessage 来确定所选中
            的菜单项。
            viod CMainFrame : : OnCommmonMenuHandler ( )
            {
            //Display selected menu item in debug window .
            TRACE (Menu item %u was selected . /n ,
            GetCruuentMessage ( ) —> wParam );
            }

26. 如何创建一个不规则形状的窗口
            可以使用新的SDK 函数SetWindowRgn。该函数将绘画和鼠标消息限定在窗口的一个指定
            的区域,实际上使窗口成为指定的不规则形状。
            使用AppWizard创建一个基于对的应用程序并使用资源编辑器从主对话资源中删
            除所在的缺省控件、标题以及边界。给对话类增加一个CRgn 数据成员,以后要使用该
            数据成员建立窗口区域。
            Class CRoundDlg : public CDialog
            {
            …
            private :
            Crgn m_rgn : // window region
            …
            } ;
            修改OnInitDialog函数建立一个椭圆区域并调用SetWindowRgn 将该区域分配给窗口:
            BOOL CRoundDlg : : OnInitDialog ( )
            {
            CDialog : : OnInitDialog ( ) ;
            //Get size of dialog .
            CRect rcDialog ;
            GetClientRect (rcDialog );
            // Create region and assign to window .
            m_rgn . CreateEllipticRgn (0 , 0 , rcDialog.Width ( ) , rcDialog
            .Height ( ) );
            SetWindowRgn (GetSafeHwnd ( ) , (HRGN) m_ rgn , TRUE );
            return TRUE ;
            }
            通过建立区域和调用SetWindowRgn,已经建立一个不规则形状的窗口,下面的例子程序
            是修改OnPaint函数使窗口形状看起来象一个球形体。
            voik CRoundDlg : : OnPaint ( )
            {
            CPaintDC de (this) ; // device context for painting .
            //draw ellipse with out any border
            dc. SelecStockObject (NULL_PEN);
            //get the RGB colour components of the sphere color
            COLORREF color= RGB( 0 , 0 , 255);
            BYTE byRed =GetRValue (color);
            BYTE byGreen = GetGValue (color);
            BYTE byBlue = GetBValue (color);
            // get the size of the view window
            Crect rect ;
            GetClientRect (rect);
            // get minimun number of units
            int nUnits =min (rect.right , rect.bottom );
            //calculate he horiaontal and vertical step size
            float fltStepHorz = (float) rect.right /nUnits ;
            float fltStepVert = (float) rect.bottom /nUnits ;
            int nEllipse = nUnits/3; // calculate how many to draw
            int nIndex ; // current ellipse that is being draw
            CBrush brush ; // bursh used for ellipse fill color
            CBrush *pBrushOld; // previous brush that was selected into dc
            //draw ellipse , gradually moving towards upper-right corner
            for (nIndex = 0 ; nIndes < + nEllipse ; nIndes ++)
            {
            //creat solid brush
            brush . CreatSolidBrush (RGB ( ( (nIndex *byRed ) /nEllipse ) ,
            ( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue) /nEllipse )
            ) );
            //select brush into dc
            pBrushOld= dc .SelectObject (&brhsh);
            //draw ellipse
            dc .Ellipse ( (int) fltStepHorz * 2, (int) fltStepVert * nIndex ,
            rect. right -( (int) fltStepHorz * nIndex )+ 1,
            rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1) ;
            //delete the brush
            brush.DelecteObject ( );
            }
            }
            最后,处理WM_NCHITTEST消息,使当击打窗口的任何位置时能移动窗口。
            UINT CRoundDlg : : OnNchitTest (Cpoint point )
            {
            //Let user move window by clickign anywhere on the window .
            UINT nHitTest = CDialog : : OnNcHitTest (point) ;
            rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest ;
            }

27. 如何在代码中获取工具条和状态条的指针
            缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个
            AFX_IDW_STATUS_BAR 标识符,工具条有一个AFX_IDW_TOOLBAR标识符,下例说明了如何
            通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些
            子窗口的指针:
            //Get pointer to status bar .
            CStatusBar * pStatusBar =
            (CStatusBar *) AfxGetMainWnd ( ) —> GetDescendantWindow
            (AFX_IDW_STUTUS_BAR);
            //Get pointer to toolbar .
            CToolBar * pToolBar =
            (CToolBar * ) AfxGetMainWnd ( ) —> GetDescendantWindow
            (AFX_IDW_TOOLBAR);

28. 如何使能和禁止工具条的工具提示
            如果设置了CBRS_TOOLTIPS风格位,工具条将显示工具提示,要使能或者禁止工具提示,
            需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle 和
            CControlBar : : SetBarStyle建立一个完成此功能的成员函数:
            void CMainFrame : : EnableToolTips ( BOOL bDisplayTips )
            {
            ASSERT_VALID (m_wndToolBar);
            DWORD dwStyle = m _wndToolBar.GetBarStyle ( ) ;
            if (bDisplayTips)
            dwStyle |=CBRS_TOOLTIPS ;
            else
            dwStyle & = ~ CBRS_TOOLTIPS ;
            m_wndToolBar.SetBarStyle (dwStyle );
            }

 29. 如何设置工具条标题
            工具条是一个窗口,所以可以在调用CWnd : : SetWindowText来设置标题,例子如下:
            int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct )
            {
            …
            // Set the caption of the toolbar .
            m_wndToolBar.SetWindowText (_T Standdard);
            30. 如何创建和使用无模式对话框
            MFC 将模式和无模式对话封装在同一个类中,但是使用无模式对话需要几个对话需要几
            个额处的步骤。首先,使用资源编辑器建立对话资源并使用ClassWizard 创建一个
            CDialog的派生类。模式和无模式对话的中止是不一样的:
            模式对话通过调用CDialog : : EndDialog 来中止,无模式对话则是调用CWnd: :
            DestroyWindow 来中止的,函数CDialog : : OnOK 和CDialog : : OnCancel 调用
            EndDialog ,所以需要调用DestroyWindow并重置无模式对话的函数。
            void CSampleDialog : : OnOK ( )
            {
            // Retrieve and validate dialog data .
            if (! UpdateData (TRUE) )
            {
            // the UpdateData rountine will set focus to correct item
            TRACEO ( UpdateData failed during dialog termination ./n) ;
            return ;
            }
            //Call DestroyWindow instead of EndDialog .
            DestroyWindow ( ) ;
            }
            void CSampleDialog : : OnCancel ( )
            {
            //Call DestroyWindow instead of EndDialog .
            DestroyWindow ( ) ;
            }
            其次,需要正确删除表示对话的C++对象。对于模式对来说,这很容易,需要创建函数
            返回后即可删除C++对象;无模式对话不是同步的,创建函数调用后立即返回,因而用
            户不知道何时删除C++对象。撤销窗口时工作框调用CWnd : : PostNcDestroy,可以重
            置该函数并执行清除操作,诸如删除this指针。
            void CSampleDialog : : PostNcDestroy ( )
            {
            // Declete the C++ object that represents this dialog .
            delete this ;
            }
            最后,要创建无模式对话。可以调用CDialog : : DoModal 创建一个模式对放, 要创
            建一个无模式对话则要调用CDialog: : Create。下面的例子说明了应用程序是如何创
            建无模式对话的:
            void CMainFrame : : OnSampleDialog ( )
            {
            //Allocate a modeless dialog object .
            CSampleDilog * pDialog =new CSampleDialog ;
            ASSERT_VALID (pDialog) ;
            //Create the modeless dialog .
            BOOL bResult = pDialog —> Creste (IDD_IDALOG) ;
            ASSERT (bResult ) ;
            }

31. 如何在对话框中显示一个位图
            这要归功于Win 32先进的静态控件和Microsoft 的资源编辑器, 在对话框中显示位图
            是很容易的, 只需将图形控件拖到对话中并选择适当属性即可,用户也可以显示图标、
            位图以及增强型元文件。

32. 如何改变对话或窗体视窗的背景颜色
            调用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 );
            }

33. 如何获取一个对话控件的指针
            有两种方法。其一,调用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对话。

34. 如何禁止和使能控件
            控件也是窗口,所以可以调用CWnd : : EnableWindow使能和禁止控件。
            //Disable button controls .
            m_wndOK.EnableWindow (FALSE ) ;
            m_wndApply.EnableWindow (FALSE ) ;

35. 如何改变控件的字体
            由于控件是也是窗口,用户可以调用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 );
            …
            }

36. 如何在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 background color .
            pdc—> FilllRect (rcBounds , &brushBack) ;
            //other drawign commands
            …
            }

37. 在不使用通用文件打开对话的情况下如何显示一个文件列表
            调用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 ;
            }

38. 为什么旋转按钮控件看起来倒转
            需要调用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 按钮时拷贝的数目增加。

39. 为什么旋转按钮控件不能自动地更新它下面的编辑控件
            如果使用旋转按钮的autu buddy特性, 则必须保证在对话的标记顺序中buddy窗口优
            先于旋转按钮控件。从Layout 菜单中选择Tab Order 菜单项(或者按下Crtl+D)可以
            设置对话的标签顺序。

40. 如何用位图显示下压按钮
            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 .
            m_wndButton1.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION1) )
            m_wndButton2.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION2) )
            m_wndButton3.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION3) )
            return TRUE ;
            } //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 )

41. 如何限制编辑框中的准许字符
            如果用户在编辑控件中只允许接收数字,可以使用一个标准的编辑控件并指定新的创建
            标志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 )) ;
            )

42. 如何改变控件的颜色
            有两种方法。其一,可以在父类中指定控件的颜色,或者利用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 ()
            }
            现在,控件可以自己决定如何绘画,与父窗口无关。

43. 当向列表框中添加多个项时如何防止闪烁
            调用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 ();

44. 如何向编辑控件中添加文本
            由于没有CEdit:: AppendText 函数,用户只好自己做此项工作。调用CEdit:: SetSel
            移动到编辑控件末尾,然后调用CEdit:: ReplaceSel 添加文本。下例是AppendText 的
            一种实现方法:
            void CMyEdit:: AppendText (LPCSTR pText)
            {
            int nLen=GetWindowTextLength ();
            SetFocus ();
            SetSel (nLen, nLen);
            ReplaceSel (pText);
            }

45. 如何访问预定义的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);
            }

46. 如何获取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);
            }

47. 如何实现一个橡皮区矩形
            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);
            }

转载于:https://www.cnblogs.com/cwbo-win/p/3332191.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值