从零开始的WTL入门教程(7) 创建使用自定义资源控件,使用DDX,自定义DDX

先介绍一个WTL增强数据交换工具 DDX

DDX是一套类似于MSG_MAP的宏命令,其实质就是简化和统一窗口与数据之间相互传值的调用代码。
使用起来比较简单,举个例子。
首先在需要使用DDX的类中继承CWinDataExchange父类
继承
然后使用DDX命令 将要绑定的控件ID和对应类型的变量进行绑定
绑定
当然,要创建ID_TF_FIRST这个资源ID并赋值给之前创建的CEdit;
之后在需要交换数据的地方使用
DoDataExchange(FALSE) 方法就可以将数据从变量传递到控件,或 DoDataExchange(TRUE) 从控件传递到变量了
变量赋值控件

控件赋值变量
DDX
在自定义控件中可以定义自己的DDX宏,这样可以方便的统一输入和输出,便于代码阅读。

使用资源文件设置自定义视图

使用纯代码创建自定义视图很简单,继承就行了。
如果希望不需要通过代码创建只要拖控件的话,则要使用Custom Control控件,并在使用前注册,并使用自定义的窗口类关联。
首先拖一个 Custom Control 类型的资源到对应的视图中 ,然后指定一个资源ID和自定义一个Class名称。
添加控件
然后回到Main函数中注册这个Class
注册
创建一个自定义窗口类并关联资源
关联资源
这样,该资源代表的控件就是你自定义的类对应的控件了,如果需要移动到其他窗口,可以直接在资源文件中操作,只要在使用时将对象与资源做关联就行了。
自定义资源

给自定义的资源视图添加控件

使用资源自定义视图则不需要调用Create方法,也就无法在这里创建子控件了,但是类与资源绑定时会调用SubclassWindow。就可以在这里重写该方法添加创建子控件的操作。

class FirstCustomItem :public CWindowImpl<FirstCustomItem,CWindow>
...
...
	CButton btnL;
	CButton btnR;

	BOOL SubclassWindow(_In_ HWND hWnd) {
            //先调用父类的SubclassWindow
		BOOL result = CWindowImpl::SubclassWindow(hWnd);
		if (result)
		{
			CRect lRect;
			GetClientRect(&lRect);
			lRect.right = lRect.right / 2;
			CRect rRect;
			GetClientRect(&rRect);
			rRect.left = rRect.right / 2;
			btnL.Create(m_hWnd, lRect, "0", WS_VISIBLE | WS_CHILD, 0UL, 0U, NULL);
			btnR.Create(m_hWnd, rRect, "0", WS_VISIBLE | WS_CHILD, 0UL, 1U, NULL);
		}
		return result;
	}
};
...
...

添加自己的DDX

DDX宏本质上也只是方法调用,实际与“给自己的控件添加输入输出接口并手动调用”是一样的。其意义在于可以对一类输入输出统一处理统一声明。因为C++代码往往行数是比较多的。DDX实质上只是让程序更易读。
添加一个自己的类继承CWinDataExchange

template <class T>
class FirstDialogDDX :
	public CWinDataExchange<T>
{
#define DDX_FD_TEXT(nID, var) \
		if(nCtlID == (UINT)-1 || nCtlID == nID) \
		{ \
			if(!ddxFdText(nID, var, sizeof(var), bSaveAndValidate)) \
				return FALSE; \
		}
	void ddxFdText(UINT nID, CString& nValue, BOOL bSave)
	{
//获取句柄
		T* pT = static_cast<T*>(this);
		HWND hWndCtrl = pT->GetDlgItem(nID);
		ATLASSERT(hWndCtrl != NULL);
//发送操作消息
		if (bSave)
		{
			//写入
		}
		else
		{
			//取出
		}
	}
};

如果你对前面分析其他组件的过程有所记忆这里就不再去DDX中分析了,可以自己去看一看。
原理非常简单。
模仿框架自带的DDX添加一个新的宏定义。和对应的调用方法。
bSave就是调用DoDataExchange时填入的参数,根据它判断操作方向。
然后回到自定义的类中添加自定义的消息和消息处理
接下来回到自定义的类中添加消息接收和处理方法

#define WM_WRITE WM_USER + 1
#define WM_HANDLE_POINTER WM_USER + 3
#define WM_READ WM_USER + 2
class FirstCustomItem :public CWindowImpl<FirstCustomItem,CWindow>
{
public:

	BEGIN_MSG_MAP(OnInitDialog)
		MSG_WM_PAINT(OnPaint)
		MSG_WM_SIZE(OnSize);
        MESSAGE_HANDLER(WM_READ, notifactionRead)
	    MESSAGE_HANDLER(WM_WRITE, notifactionWrite)
	
	END_MSG_MAP()

添加消息接收和对应的处理方法

	LRESULT notifactionRead(...) {
		return readData();
	}

	LRESULT notifactionWrite( UINT , LPARAM lparm, WPARAM rparm, BOOL& /*bHandled*/) {
		writeData(lparm);
		return 0;
	}

	BOOL readData() {
	
		CString strL;
		btnL.GetWindowTextA(strL);

		CString strR;
		btnR.GetWindowTextA(strR);

		if (strL == "1" && strR == "1")
		{
			return TRUE;
		}

		return FALSE;
	}
	void writeData(BOOL state) {
	if (state)
	{
		btnL.SetWindowTextA("1");
		btnR.SetWindowTextA("1");
	}
	else
	{
		btnL.SetWindowTextA("0");
		btnR.SetWindowTextA("0");
	}
	
	}

顺便去自定义控件给按钮添加一个事件

	LRESULT OnLClick(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{

		CString btnStr;
		btnL.GetWindowTextA(btnStr);
		if (btnStr == "0")
		{
			btnL.SetWindowTextA("1");
		}
		else
		{
			btnL.SetWindowTextA("0");

		}
		return 0;
	}

	LRESULT OnRClick(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		CString btnStr;
		btnR.GetWindowTextA(btnStr);
		if (btnStr == "0")
		{
			btnR.SetWindowTextA("1");
		}
		else
		{
			btnR.SetWindowTextA("0");

		}

		return 0;
	}

好了 接下来就可以通过DDX将这个自定义控件与一个BOOL值之间做交互了
你应该看出来了 。这个控件 就是一个有两个可点击按钮并能通过DDX输出按钮上数字的&运算后取得的BOOL值的复合控件。
回到使用它的地方 用DDX做绑定

	BEGIN_DDX_MAP(FirstDialog)
		DDX_FD_BOOL(IDC_CUSTOM_FIRST,m_SocketState)
	END_DDX_MAP()
	BOOL m_SocketState = 1;

给对话框的两个按钮添加事件用来重置状态和进行DDX操作


LRESULT FirstDialog::OnBnClickedOk(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	// TODO: 在此添加控件通知处理程序代码
	m_SocketState = 0;
	DoDataExchange(TRUE);
	return 0;
}
LRESULT FirstDialog::OnBnClickedCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	// TODO: 在此添加控件通知处理程序代码
	DoDataExchange(FALSE);
	if (m_SocketState)
	{
		(GetDlgItem(IDC_STATIC)).SetWindowTextA("TRUE");
	}
	else
	{
		(GetDlgItem(IDC_STATIC)).SetWindowTextA("FALSE");
	}
	return 0;
}

看一看做了个什么。
自定义DDX

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值