风中之歌

我是世界的光

林镇群ID:linzhengqun
79537次访问,排名1189好友4人,关注者14
程序,设计,音乐,
linzhengqun的文章
原创 49 篇
翻译 0 篇
转载 0 篇
评论 117 篇
linzhenqun的公告

我们生的时候啊,
要像夏季的花一样灿烂;
而在死的时候,
须如秋天的叶一般静美!

seo sydney
seo sydney Counter

最近评论
wwp3321:只能说声谢谢了,谢谢楼主的共享精神
trytobegood:好东东!!!收藏了
yunhaisoft://你的这个版本中文乱码,我参考Cnpack的代码帮着你改了一下,你看看。经测试已经没有乱码了。
procedure TConvRTF.ChangeSpeString(var S: String);
var
Str: string;
i: Integer;
Len: Integer;
tmpWide, tmpStr:……
antimatterworld::SetWindowOrgEx(hDC, 100, 100, NULL);

::SetViewportOrgEx(hDC, 200, 200, NULL);

理解为:逻辑坐标的(100,100)映射为设备坐标的(200,200),其他的点以此为依据映射。
====================
就数……
antimatterworld:就看映射方式了,映射方式很重要,绘图很方便.
3Q了
文章分类
收藏
相册
CodeGear纪念
GDI绘制
MFC文档视图
MFC消息分派
玻璃效果
汇编与高级语言
接口的实现
增量搜索
最简单的MFC程序
友情链接
Ari
天蝎蝴蝶的专栏
还猪哥哥
醉到天亮说晚安
风中之歌-非技术Blog
存档
软件项目交易
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

原创 MFC-对话框与数据交换收藏

新一篇: MFC-最简单的MFC程序 | 旧一篇: MFC-窗口封装

       对话框是非常重要的一种窗体,就我看过的应用,除了MDI程序,对话框比文档视图框架用得更多。原因大概有两个,首先对话框可以利用资源编辑器来编辑,这就有了一点快速开发的感觉,尽管比真正的快速开发弱得多;其次,对话框提供一种叫数据交换的方法,让控件与某种数据类型关联起来,比如Edit控件与CString变量关联,对CString变量的操作间接映射到Edit控件,这种方便性是不言而喻的。

对话框的创建

对话框如何创建,它是对SDK的对话框资源的封装,说得简单一点,就是对CreateDlgIndirect的封装。

对话框的显示几乎是MFC最简单的窗体创建,用下面两句代码就可以做到:

CMFCTest2Dlg dlg;

dlg.DoModal();

       对话框资源对应一个资源ID,这个ID在对话框类构造时保存:

CMFCTest2Dlg::CMFCTest2Dlg(CWnd* pParent /*=NULL*/)

    : CDialog(CMFCTest2Dlg::IDD, pParent)

{

    ... ...

}

       DoModal只是利用这个ID创建对话框窗口,不过它还要做几件事情,让对话框融入MFC框架,总体上可以描述如下:

1.         根据资源ID从程序的资源段中读出对话框资源。

2.         将对话框的Owner窗口置为Disable

3.         调用AfxHookWindowCreate监视对话框的创建,让对话框可以进行消息映射。

4.         调用CreateDlgIndirect创建对话框。

5.         调用RunModalLoop进入消息循环。

整个过程就是这样,创建之后与其他窗体类型没有什么区别,只是要操作对话框的控件会有些麻烦,好在MFC提供了数据交换。

数据交换

       由于MFC的对话框直接封装自CreateDlgIndirect,因此对话框里面的控件并没有转换成相应的控件类,我们只能通过GetDlgItem取得控件句柄,然后使用API来操作这些控件,这又回到SDK时代了。

       为了简化对话框控件的操作,MFC提出了数据交换。这里的数据交换分两种,一种是控件与数据类型的关联;另一种是控件与控件类的关联。   

控件与数据类型怎么关联起来的呢?全靠CWnd::UpdateData(BOOL bSaveAndValidate)这个成员函数,如果bSaveAndValidateTrue,数据从控件赋给类型变量;反之,数据从类型变量赋给控件。

假设一个CString变量m_EnterIDC_ENTER的编辑控件关联,则我们只需这样写:

m_Enter = "Enter";

UpdateData(FALSE);

       那么m_Enter的值就会赋给IDC_ENTER。看看UpdateData是怎么做到的:

BOOL CWnd::UpdateData(BOOL bSaveAndValidate)

{

    CDataExchange dx(this, bSaveAndValidate);

    DoDataExchange(&dx);

    return bOK;

}

       UpdateData创建一个CDataExchange实例,然后调用DoDataExchange进行数据交换。Dx保存着当前的对话框对象,DoDataExchange是一个虚成员函数,对话框要实现数据交换必须覆盖这个函数:

void CMFCTest2Dlg::DoDataExchange(CDataExchange* pDX)

{

    CDialog::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CMFCTest2Dlg)

    DDX_Text(pDX, IDC_ENTER, m_Enter);

    //}}AFX_DATA_MAP

}

       DDX_Text是类向导自动生成的,实现如下:

void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, CString& value)

{

    //根据nIDC取得对话框控件

    HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);

    //从控件取得数据赋给Value

if (pDX->m_bSaveAndValidate)

    {

        int nLen = ::GetWindowTextLength(hWndCtrl);

        ::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen), nLen+1);

        value.ReleaseBuffer();

    }

    //将值赋给控件

    else

    {

        AfxSetWindowText(hWndCtrl, value);

    }

}

       DDX_Text仅仅是帮我们调用API,最后将值赋给类型变量, DDX_Text有很多重载形式,使得数据变量可以是IntShort等其他类型。

 

       数据交换的另一种形式是控件与控件类,比如有一个CButtonm_OKIDOK关联,CDialog::OnInitDialog会调用UpdateData(FALSE),进而执行流程到DoDataExchange

void CMFCTest2Dlg::DoDataExchange(CDataExchange* pDX)

{

    CDialog::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CMFCTest2Dlg)

    DDX_Control(pDX, IDOK, m_OK);

    //}}AFX_DATA_MAP

}

       看看DDX_Control做了什么:

void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl)

{

    //只子类化一次

    if (rControl.m_hWnd == NULL)    // not subclassed yet

    {

        HWND hWndCtrl = pDX->PrepareCtrl(nIDC);

        rControl.SubclassWindow(hWndCtrl);

    }

}

       DDX_Control将控件句柄与控件类关联起来,并且只需关联一次,实现关联的方法是子类化hWndCtrl CWnd::SubclassWindow。这里的子类化其实做了两件事情,一件是通过Attach将控件句柄与控件类映射起来,另一件是通过SetWindowLong将窗口过程替换成AfxWndProc,使得控件也可以进行消息映射。

       关联以后,m_OK就代表IDOK,以后直接操作m_OK即可。

 

       控件关联给我们带来一种非常好的应用,我们在对话框资源上放一个Button的时候,只能处理ClickDbClick两个事件,如果我们想处理MouseMove消息要怎么做,只能继承CButton写一个派生类,然后在派生类里面处理MouseMove消息,但这样做就不能在资源编辑器上可视操作按钮了,我们必须手动创建按钮类,写代码控制它的位置,非常地麻烦。

       其实使用数据交换就可以一举两得,让按钮派生类与对话框资源上的按钮关联起来,我们既能扩展按钮的消息处理,又能可视化设计按钮。

       具体是这样做的:

1.         在对话框资源上放一个按钮IDOK

2.         创建一个按钮类派生自CButton,并处理MouseMove消息:

BEGIN_MESSAGE_MAP(CMyButton, CButton)

    //{{AFX_MSG_MAP(CMyButton)

    ON_WM_MOUSEMOVE()

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()

void CMyButton::OnMouseMove(UINT nFlags, CPoint point)

{

    MessageBox("Hello");

    CButton::OnMouseMove(nFlags, point);

}

3.         利用类向导,将IDOK与一个按钮类关联起来:

class CMFCTest2Dlg : public CDialog

{

    ... ...

    CButton m_OK;

    CString m_Enter;

    ... ...

};

4.         CButton设为CMyButton,完毕。

 

对话框的应用广泛就在于此,RAD其实还是起决定因素的。

 

发表于 @ 2007年12月10日 10:12:00|评论(loading...)|编辑

新一篇: MFC-最简单的MFC程序 | 旧一篇: MFC-窗口封装

评论

#linzhengqun 发表于2007-12-10 15:13:29  IP: 219.131.196.*
最后第4步:将CButton设为CMyButton
其实是没有必要的,直接在类向导就可以选择CMyButton。
希望不要误导了初学者。

#wzh19831221 发表于2007-12-11 20:03:46  IP: unknown, 202.98.*
尽管有失误,还是非常感谢!
#linzhengqun 发表于2007-12-12 08:50:02  IP: 219.131.196.*
学习MFC不久,所以在工具应用上难免有不熟的地方。请见谅。
发表评论  


当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
Csdn Blog version 3.1a
Copyright © linzhenqun