Part V高级对话框用户界面类.docx

上传人:b****5 文档编号:7930152 上传时间:2023-01-27 格式:DOCX 页数:19 大小:90.67KB
下载 相关 举报
Part V高级对话框用户界面类.docx_第1页
第1页 / 共19页
Part V高级对话框用户界面类.docx_第2页
第2页 / 共19页
Part V高级对话框用户界面类.docx_第3页
第3页 / 共19页
Part V高级对话框用户界面类.docx_第4页
第4页 / 共19页
Part V高级对话框用户界面类.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

Part V高级对话框用户界面类.docx

《Part V高级对话框用户界面类.docx》由会员分享,可在线阅读,更多相关《Part V高级对话框用户界面类.docx(19页珍藏版)》请在冰豆网上搜索。

Part V高级对话框用户界面类.docx

PartV高级对话框用户界面类

MFC程序员的WTL指南:

PartV-高级对话框用户界面类

原作:

MichaelDunn[英文原文]

翻译:

Orbit(桔皮干了)[]

下载演示程序代码

本章内容

∙第五章介绍

∙特别的自画和外观定制类

oCOwnerDraw

oCCustomDraw

∙WTL的新控件

oCBitmapButton

oCCheckListViewCtrl

oCTreeViewCtrlEx和CTreeItem

oCHyperLink

∙对话框中控件的UIUpdating

∙DDV

o处理DDV验证失败

∙改变对话框的大小

∙继续

∙参考

∙修改记录

第五章介绍

在上一篇文章我们介绍了一些与对话框和控件有关的WTL的特性,它们和MFC的相应的类作用相同。

本文将介绍一些新类实现高级界面特性新类:

控件自画和自定外观控件,新的WTL控件,UIupdating和对话框数据验证(DDV)。

特别的自画和外观定制类

由于自画和定制外观控件在图形用户界面中是很常用的手段,所以WTL提供了几个嵌入类来完成这些令人厌烦的工作。

我接着就会介绍它们,事实上我们在上一个例子工程ControlMania2的结尾部分已经这么做了。

如果你正随着我的讲解用应用程序生成向导创建新工程,请不要忘了使用无模式对话框,为了使正常工作必须使用无模式对话框,我会在对话框中控件的UIUpdating部分详细解释为什么这样作。

COwnerDraw

控件的自画需要响应四个消息:

WM_MEASUREITEM,WM_DRAWITEM,WM_COMPAREITEM,和WM_DELETEITEM,在atlframe.h头文件中定义的COwnerDraw类可以简化这些工作,使用这个类就不需要处理这四个消息,你只需将消息链入COwnerDraw,它会调用你的类中的重载函数。

如何将消息链入COwnerDraw取决与你是否将消息反射给控件,两种方法有些不同。

下面是COwnerDraw类的消息映射链,它使得两种方法的差别更加明显:

templateclassCOwnerDraw

{

public:

BEGIN_MSG_MAP(COwnerDraw

MESSAGE_HANDLER(WM_DRAWITEM,OnDrawItem)

MESSAGE_HANDLER(WM_MEASUREITEM,OnMeasureItem)

MESSAGE_HANDLER(WM_COMPAREITEM,OnCompareItem)

MESSAGE_HANDLER(WM_DELETEITEM,OnDeleteItem)

ALT_MSG_MAP

(1)

MESSAGE_HANDLER(OCM_DRAWITEM,OnDrawItem)

MESSAGE_HANDLER(OCM_MEASUREITEM,OnMeasureItem)

MESSAGE_HANDLER(OCM_COMPAREITEM,OnCompareItem)

MESSAGE_HANDLER(OCM_DELETEITEM,OnDeleteItem)

END_MSG_MAP()

};

注意,消息映射链的主要部分处理WM_*消息,而ATL部分处理反射的消息,OCM_*。

自画的通知消息就像WM_NOTIFY消息一样,你可以在父窗口处理它们,也可以将它们反射会控件,如果你使用前一种方法,消息被直接链入COwnerDraw:

classCSomeDlg:

publicCOwnerDraw,...

{

BEGIN_MSG_MAP(CSomeDlg)

//...

CHAIN_MSG_MAP(COwnerDraw

END_MSG_MAP()

voidDrawItem(LPDRAWITEMSTRUCTlpdis);

};

当然,如果你想要控件自己处理这些消息,你需要使用CHAIN_MSG_MAP_ALT宏将消息链入ALT_MSG_MAP

(1)部分:

classCSomeButtonImpl:

publicCOwnerDraw,...

{

BEGIN_MSG_MAP(CSomeButtonImpl)

//...

CHAIN_MSG_MAP_ALT(COwnerDraw,1)

DEFAULT_REFLECTION_HANDLER()

END_MSG_MAP()

voidDrawItem(LPDRAWITEMSTRUCTlpdis);

};

COwnerDraw类将对消息传递的参数展开,然后调用你的类中的实现函数。

上面的例子中,我们自己的类实现DrawItem()函数,当有WM_DRAWITEM或OCM_DRAWITEM消息被链入COwnerDraw时,这个函数就会被调用。

你可以重载的方法有:

voidDrawItem(LPDRAWITEMSTRUCTlpDrawItemStruct);

voidMeasureItem(LPMEASUREITEMSTRUCTlpMeasureItemStruct);

intCompareItem(LPCOMPAREITEMSTRUCTlpCompareItemStruct);

voidDeleteItem(LPDELETEITEMSTRUCTlpDeleteItemStruct);

如果你不想处理某个消息,你可以调用SetMsgHandled(false),消息会被传递给消息映射链中的其他响应者。

SetMsgHandled()事实上是COwnerDraw类的成员函数,但是它的作用和在BEGIN_MSG_MAP_EX()中使用SetMsgHandled()一样。

对于ControlMania2,它从ControlMania1中的树控件开始,添加了自画按钮处理反射的WM_DRAWITEM消息,下面是资源编辑器中的新按钮:

现在我们需要一个新类实现自画按钮:

classCODButtonImpl:

publicCWindowImpl,

publicCOwnerDraw

{

public:

BEGIN_MSG_MAP_EX(CODButtonImpl)

CHAIN_MSG_MAP_ALT(COwnerDraw,1)

DEFAULT_REFLECTION_HANDLER()

END_MSG_MAP()

voidDrawItem(LPDRAWITEMSTRUCTlpdis);

};

DrawItem()使用了像BitBlt()这样的GDI函数向按钮的表面画位图,代码应该很容易理解,因为WTL使用的类名和函数名都和MFC类似。

voidCODButtonImpl:

:

DrawItem(LPDRAWITEMSTRUCTlpdis)

{

//NOTE:

m_bmpisaCBitmapinit''edintheconstructor.

CDCHandledc=lpdis->hDC;

CDCdcMem;

dcMem.CreateCompatibleDC(dc);

dc.SaveDC();

dcMem.SaveDC();

//Drawthebutton''sbackground,redifithasthefocus,blueifnot.

if(lpdis->itemState&ODS_FOCUS)

dc.FillSolidRect(&lpdis->rcItem,RGB(255,0,0));

else

dc.FillSolidRect(&lpdis->rcItem,RGB(0,0,255));

//Drawthebitmapinthetop-left,oroffsetby1pixelifthebutton

//isclicked.

dcMem.SelectBitmap(m_bmp);

if(lpdis->itemState&ODS_SELECTED)

dc.BitBlt(1,1,80,80,dcMem,0,0,SRCCOPY);

else

dc.BitBlt(0,0,80,80,dcMem,0,0,SRCCOPY);

dcMem.RestoreDC(-1);

dc.RestoreDC(-1);

}

我们的按钮看起来是这个样子:

CCustomDraw

CCustomDraw类使用和COwnerDraw类相同的方法处理NM_CUSTOMDRAW消息,对于自定绘制的每个阶段都有相应的重载函数:

DWORDOnPrePaint(intidCtrl,LPNMCUSTOMDRAWlpNMCD);

DWORDOnPostPaint(intidCtrl,LPNMCUSTOMDRAWlpNMCD);

DWORDOnPreErase(intidCtrl,LPNMCUSTOMDRAWlpNMCD);

DWORDOnPostErase(intidCtrl,LPNMCUSTOMDRAWlpNMCD);

DWORDOnItemPrePaint(intidCtrl,LPNMCUSTOMDRAWlpNMCD);

DWORDOnItemPostPaint(intidCtrl,LPNMCUSTOMDRAWlpNMCD);

DWORDOnItemPreErase(intidCtrl,LPNMCUSTOMDRAWlpNMCD);

DWORDOnItemPostEraset(intidCtrl,LPNMCUSTOMDRAWlpNMCD);

DWORDOnSubItemPrePaint(intidCtrl,LPNMCUSTOMDRAWlpNMCD);

这些函数默认都是返回CDRF_DODEFAULT,如果想自画控件或返回一个不同的值,就需要重载这些函数:

你可能注意到上面的屏幕截图将“道恩”(Dawn:

女名)显示成绿色,这是因为CBuffyTreeCtrl将消息链入CCustomDraw并重载了OnPrePaint()和OnItemPrePaint()方法。

向树控件中添加节点时,节点的itemdata字段被设置成1,OnItemPrePaint()检查这个值,然后改变文字的颜色。

DWORDCBuffyTreeCtrl:

:

OnPrePaint(intidCtrl,

LPNMCUSTOMDRAWlpNMCD)

{

returnCDRF_NOTIFYITEMDRAW;

}

DWORDCBuffyTreeCtrl:

:

OnItemPrePaint(intidCtrl,

LPNMCUSTOMDRAWlpNMCD)

{

if(1==lpNMCD->lItemlParam)

pnmtv->clrText=RGB(0,128,0);

returnCDRF_DODEFAULT;

}

CCustomDraw类也有SetMsgHandled()函数,你可以像在COwnerDraw类那样使用这个函数。

WTL的新控件

WTL有几个新控件,它们要么是其他封装类的扩展(像CTreeViewCtrlEx),要么是提供windows标准控件没有的新功能(像CHyperLink)。

CBitmapButton

WTL的CBitmapButton类声明在atlctrlx.h中,它比MFC的同名类使用起来要简单的多。

WTL的CBitmapButton类使用imagelist而不是单个的位图资源,你可以将多个按钮的图像放到一个位图文件中,减少GDI资源的占用。

这对于使用很多图片并需要在Windows9X系统上运行的程序很有好处,因为使用太多的单个位图将会很快耗尽GDI资源并导致系统崩溃。

CBitmapButton是一个CWindowImpl派生类,它又很多特色:

自动调整控件的大小,自动生成3D边框,支持hot-tracking,每个按钮可以使用多个图像分别表示按钮的不同状态。

在ControlMania2中,我们对前面的例子创建的自画按钮使用CBitmapButton类。

现在CMainDlg对话框类中添加CBitmapButton类型的变量m_wndBmpBtn,调用SubclassWindow()函数或使用DDX将其和控件联系起来,将位图装载到imagelist并告诉按钮使用这个imagelist,还要告诉按钮每个图像分别对应按钮的什么状态。

下面是OnInitDialog()函数中建立和使用这个按钮的代码段:

//Setupthebitmapbutton

CImageListiml;

iml.CreateFromImage(IDB_ALYSON_IMGLIST,81,1,CLR_NONE,

IMAGE_BITMAP,LR_CREATEDIBSECTION);

m_wndBmpBtn.SubclassWindow(GetDlgItem(IDC_ALYSON_BMPBTN));

m_wndBmpBtn.SetToolTipText(_T("Alyson"));

m_wndBmpBtn.SetImageList(iml);

m_wndBmpBtn.SetImages(0,1,2,3);

默认情况下,按钮只是引用imagelist,所以OnInitDialog()不能delete它所创建的imagelist。

下面显示的是新按钮的一般状态,注意控件是如何根据图像的大小来调整自己的大小。

因为CBitmapButton是一个非常有用的类,我想介绍一下它的公有方法。

CBitmapButtonmethods

CBitmapButtonImpl类包含了实现一个按钮的所有代码,除非你想重载某个方法或消息处理,你可以对控件直接使用CBitmapButton类。

CBitmapButtonImplconstructor

CBitmapButtonImpl(DWORDdwExtendedStyle=BMPBTN_AUTOSIZE,HIMAGELISThImageList=NULL)

构造函数可以指定按钮的扩展样式(这与窗口的样式不冲突)和图像列表,通常使用默认参数就足够了,因为可以使用其他的方法设定这些属性。

SubclassWindow()

BOOLSubclassWindow(HWNDhWnd)

SubclassWindow()是个重载函数,主要完成控件的子类化和初始化控件类保有的内部数据。

Bitmapbuttonextendedstyles

DWORDGetBitmapButtonExtendedStyle()

DWORDSetBitmapButtonExtendedStyle(DWORDdwExtendedStyle,DWORDdwMask=0)

CBitmapButton支持一些扩展样式,这些扩展样式会对按钮的外观和操作方式产生影响:

BMPBTN_HOVER

使用hot-tracking,当鼠标移到按钮上时按钮被画成焦点状态。

BMPBTN_AUTO3D_SINGLE,BMPBTN_AUTO3D_DOUBLE

在按钮图像周围自动产生一个三维边框,当按钮拥有焦点时会显示一个表示焦点的虚线矩形框。

另外如果你没有指定按钮按下状态的图像,将会自动生成一个。

BMPBTN_AUTO3D_DOUBLE样式生成的边框稍微粗一些,其他特征和BMPBTN_AUTO3D_SINGLE一样。

BMPBTN_AUTOSIZE

按钮调整自己的大小以适应图像大小,这是默认样式。

BMPBTN_SHAREIMAGELISTS

如果指定这个样式,按钮不负责销毁按钮使用的imagelist,如果不使用这个样式,CBitmapButton的析构函数会销毁按钮使用的imagelist。

BMPBTN_AUTOFIRE

如果设置这个样式,在按钮上按住鼠标左键不放将会产生连续的WM_COMMAND消息。

调用SetBitmapButtonExtendedStyle()时,dwMask参数控制着那个样式将被改变,默认值是0,意味着用新样式完全替换旧的样式。

Imagelistmanagement

HIMAGELISTGetImageList()

HIMAGELISTSetImageList(HIMAGELISThImageList)

调用SetImageList()设置按钮使用的imagelist。

Tooltipmanagement

intGetToolTipTextLength()

boolGetToolTipText(LPTSTRlpstrText,intnLength)

boolSetToolTipText(LPCTSTRlpstrText)

CBitmapButton支持显示工具提示(tooltip),调用SetToolTipText()指定显示的文字。

Settingtheimagestouse

voidSetImages(intnNormal,intnPushed=-1,intnFocusOrHover=-1,intnDisabled=-1)

调用SetImages()函数告诉按钮分别使用imagelist的拿一个图像表示那个状态。

nNormal是必须的,其它是可选的,使用-1表示对应的状态没有图像。

CCheckListViewCtrl

CCheckListViewCtrl类在atlctrlx.h中定义,它是一个CWindowImpl派生类,实现了一个带检查框的listview控件。

它和MFC的CCheckListBox不同,CCheckListBox只是一个listbox,不是listview。

CCheckListViewCtrl类非常简单,只添加了很少的函数,当然,它使用了一个新的辅助类CCheckListViewCtrlImplTraits,它和CWinTraits类的作用类似,只是第三个参数是listview控件的扩展样式属性,如果你没有定义自己的CCheckListViewCtrlImplTraits,它将使用没默认的样式:

LVS_EX_CHECKBOXES|LVS_EX_FULLROWSELECT。

下面是一个定义listview扩展样式属性的例子,加入了一个使用这个样式的新类。

(注意,扩展属性必须包含LVS_EX_CHECKBOXES,否则会因起断言错误消息。

typedefCCheckListViewCtrlImplTraits<

WS_CHILD|WS_VISIBLE|LVS_REPORT,

WS_EX_CLIENTEDGE,

LVS_EX_CHECKBOXES|LVS_EX_GRIDLINES|LVS_EX_UNDERLINEHOT|

LVS_EX_ONECLICKACTIVATE>CMyCheckListTraits;

classCMyCheckListCtrl:

publicCCheckListViewCtrlImpl

CMyCheckListTraits>

{

private:

typedefCCheckListViewCtrlImpl

CMyCheckListTraits>baseClass;

public:

BEGIN_MSG_MAP(CMyCheckListCtrl)

CHAIN_MSG_MAP(baseClass)

END_MSG_MAP()

};

CCheckListViewCtrlmethodsSubclassWindow()

当子类化一个已经存在的listview控件时,SubclassWindow()查看CCheckListViewCtrlImplTraits的扩展样式属性并将之应用到控件上。

未用到前两个参数(窗口样式和扩展窗口样式)。

SetCheckState()andGetCheckState()

这些方法实际上是在CListViewCtrl中,SetCheckState()使用行的索引和一个布尔类型参数,该布尔参数的值表示是否check这一行。

GetCheckState()以行索引未参数,返回改行的checked状态。

CheckSelectedItems()

这个方法使用item的索引作为参数,它翻转这个item的check状态,这个item必须是被选定的,同时还将其他所有被选择的item设置成相应状态(译者加:

多选状态下)。

你大概不会用到这个方法,因为CCheckListViewCtrl会在checkbox被单击或用户按下了空格键时设置相应的item的状态。

下面是ControlMania2中的CCheckListViewCtrl的样子:

CTreeViewCtrlExandCTreeItem

有两个类使得树控件的使用简化了很多:

CTreeItem类封装了HTREEITEM,一个CTreeItem对象含有一个HTREEITEM和一个指向包含这个HTREEITEM的树控件的指针,使你不必每次调用都引用树控件;CTreeViewCtrlEx和CTreeViewCtrl一样,只是它的方法操作CTreeItem而不是HTREEITEM。

例如,InsertItem()函数返回一个CTreeItem而不是HTREEITEM,你可以使用CTreeItem操作新添加的item。

下面是一个例子:

//UsingplainHTREEITEMs:

HTREEITEMhti,hti2;

hti=m_wndTree.InsertItem("foo",TVI_ROOT,TVI_LAST);

hti2=m_wndTree.InsertItem("bar",hti,TVI_LAST);

m_wndTree.SetItemData(hti2,100);

//UsingCTreeItems:

CTreeItemti,ti2;

ti=m_wndTreeEx.InsertItem("foo",TVI_ROOT,TVI_LAST);

ti2=ti.AddTail("bar",0);

ti2.SetData(100);

CTreeViewCtrl对HTREEITEM的每一个操作,CTreeItem都有与之

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 生产经营管理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1