WTL对话框与自定义控件

使用WTL建立一个对话框应用程序。这篇文章我想解释一下对话框程序,对话框控件,以及自定义控件。前面曾经说过,WTL距离操作系统内核很近。从一个CEdit类的代码应该能感受到这一点。
template 
class CEditT : public TBase
{
public:
// Constructors
	CEditT(HWND hWnd = NULL) : TBase(hWnd)
	{ }

	CEditT< TBase >& operator =(HWND hWnd)
	{
		m_hWnd = hWnd;
		return *this;
	}

	HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
			DWORD dwStyle = 0, DWORD dwExStyle = 0,
			ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
	{
		return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
	}

// Attributes
	static LPCTSTR GetWndClassName()
	{
		return _T("EDIT");
	}

	BOOL CanUndo() const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L);
	}

	int GetLineCount() const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L);
	}



       回想一下,一个简单的Win32windows应用程序是如何建立一个窗口的,你大致就可以想象出来。EDIT控件是一个已经注册过的特殊窗口,因为没有任何代码掩盖,显然它就在windows操作系统内部。其实不必太关心它具体在哪个dll里面,因为它已经调入内存了。

     这个Edit控件的二进制代码显然是在内存中的。WTL给出了调用那些代码的方法,就是通过发送消息。毕竟你是看不到Edit源代码,所以这种调用方式很容易想象。

     对于一个对话框程序,我想说的是,我们在对话框上放置几个控件,就算不编写任何代码,这些控件还是会显示出来,这说明了那些控件在对话框内部已经被建立了,不管有没有一个实体变量指向它。理解这一点非常重要。


WTL对话框与自定义控件_第1张图片


对话框上面我们放置了5个控件,两个label就不说了。编辑框控件: IDC_EDIT1,弹出列表框控件: IDC_COMBO1, 还有一个 Picture Control 控件: IDC_MYCTRL

对于编辑框控件,我们不定义任何实体变量指向它。对于弹出列表框控件,我们将定义一个CComboBox 变量指向它,而图形控件,我们将拓展这个控件的功能,建立一个简单的自定义控件,并定义一个变量指向它。对于图形控件,它的类型设置成了Owner Draw,也就是自绘。


// MainDlg.h : interface of the CMainDlg class
//
/////////////////////////////////////////////////////////////////////////////

#pragma once

#include "testctrl.h"

class CMainDlg : public CDialogImpl, public CUpdateUI,
		public CMessageFilter, public CIdleHandler
{
private:
	CComboBox m_combo;
	CPicLooker  m_myCtrl;
public:
	enum { IDD = IDD_MAINDLG };


testctrl.h 是我们定义一个自定义控件,它实际上市对  CStatic控件进行了扩展。以后我们也会讲从零如何建立一个windows控件。如果够用,从一个现有的控件扩展总是简单的多。编程,达到目的是最重要的,是否最佳方法,经常倒不那么重要。记得前些年,看到经常有人嘲笑印度软件人员编程序使用数组,那没多少道理。其实数组用好,用的不出问题,并不是很容易。


#pragma once

#include "stdafx.h"

class CPicLooker : public CWindowImpl,
					public COwnerDraw
{
public:
	CPicLooker(void)
	{
	}
	~CPicLooker()
	{
	}
    BEGIN_MSG_MAP(CPicLooker)
		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
		CHAIN_MSG_MAP_ALT( COwnerDraw,1)
		DEFAULT_REFLECTION_HANDLER()
    END_MSG_MAP()

public:
	LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		return 1;
	}
	void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct  )
	{
		CDCHandle dc = lpDrawItemStruct->hDC;
		RECT& rcItem = lpDrawItemStruct->rcItem;
		dc.FillRect( &rcItem, 21);
		dc.MoveTo( rcItem.left, rcItem.top);
		dc.LineTo(rcItem.right, rcItem.bottom);
	}
};

在 LRESULT OnInitDialog 初始化函数里面,我们增加了一些东西,是的软件看上去有点人工痕迹。在自动产生的代码最后,return 语句之前, 添加如下代码。


		this->GetDlgItem(IDC_EDIT1).SetWindowText(_T("编辑缺省值"));
		m_combo = this->GetDlgItem(IDC_COMBO1);
		m_combo.AddString(_T("选择A"));
		m_combo.AddString(_T("选择B"));
		m_combo.AddString(_T("选择C"));
		m_combo.AddString(_T("选择D"));
		m_combo.AddString(_T("选择E"));
		m_combo.AddString(_T("选择F"));
		m_combo.AddString(_T("选择G"));

		// 设置对话框的缺省值
		m_combo.SetCurSel(2);
		m_myCtrl.SubclassWindow(this->GetDlgItem(IDC_MYCTRL));


        对于编辑框,我们使用了 GetDlgITem来获得窗口,然后设置窗口的文字,也就是编辑框的缺省文本。这是基本窗口的功能,想要编辑框的文字初始化为选中状态,这就要使用CEdit的功能了,因此这种情况下必须建立一个CEdit变量关联到编辑框。然后再设置。至于CComboBox对像,上面显示了关联方法。而对于我们的自定义变量,没有采用


m_combo = this->GetDlgItem(IDC_COMBO1);
这样的方式,而是采用了子类化方法。
m_myCtrl.SubclassWindow(this->GetDlgItem(IDC_MYCTRL));


具体的内含就是要windows执行子类的消息循环, 否则消息循环仍然在原来的CStatic里面,就无法执行我们自定义类的代码了。当你添加完这些之后,运行程序,编辑框和弹出列表框会运行的很好,但是我们的自定义控件没有工作。我们的自定义控件实际使用了windows的消息反射机制。这里暂时不解释那么多了,只需要添加一行代码。


	BEGIN_MSG_MAP(CMainDlg)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
		COMMAND_ID_HANDLER(IDOK, OnOK)
		COMMAND_ID_HANDLER(IDCANCEL, OnCancel)




		// 添加消息反射
		REFLECT_NOTIFICATIONS()
	END_MSG_MAP()




这下就妥了。如果编译正确运行程序后,你会看到这样的界面。



WTL对话框与自定义控件_第2张图片




总结一下吧。 这篇文章,我是希望能对对话框控件和windows关系能有一个较为深入的了解。知道对话框根据模板建立了内部所有的东西,在InitDialog里面,其实所有的一切都已经建立好了。等着你去关联和使用它们,你可以选择不同的方法使用它们。这里我们没有用到DDX,其实我基本上不太实用DDX数据交换,我觉得那东西意义不大。





你可能感兴趣的:(Wtl)