|   
 | 
| 41、如何一个创建三态下压按钮 
 可以使用新的bs_pushbutton 风格位和检测框以及按钮来创建一个三态下压按钮。这很容易,只需将检测框和按钮拖拉到对话中并指定属性push—like即可。不用任何附加程序就可以成为三态下压按钮。
 
 42、如何动态创建控件
 
 分配一个控件对象的实例并调用其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 )
 
 43、如何限制编辑框中的准许字符
 
 如果用户在编辑控件中只允许接收数字,可以使用一个标准的编辑控件并指定新的创建标志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 )) ;
 
 }
 
 44、如何改变控件的颜色
 
 有两种方法。其一,可以在父类中指定控件的颜色,或者利用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 ()
 
 }
 
 现在,控件可以自己决定如何绘画,与父窗口无关。
 
 45、当向列表框中添加多个项时如何防止闪烁
 
 调用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 ();
 
 46、如何向编辑控件中添加文本
 
 由于没有cedit:: appendtext函数,用户只好自己做此项工作。调用cedit:: setsel移动到编辑控件末尾,然后调用cedit:: replacesel添加文本。下例是appendtext 的一种实现方法:
 
 void cmyedit:: appendtext (lpcstr ptext)
 
 {
 
 int nlen=getwindowtextlength ();
 
 setfocus ();
 
 setsel (nlen, nlen);
 
 replacesel (ptext);
 
 }
 
 47、如何访问预定义的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);
 
 }
 
 48、如何获取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);
 
 }
 | 
 |