从零开始的WTL入门教程(2)创建第一个窗口

在开始创建窗口前 有一些必须了解的C/C++特性,即使看不太懂也没有关系先记下

一.C++中的变量。

如果你没有C++基础 那么你需要重新理清C++中的变量和对象关系。
对于变量 它在创建的时候在栈中分配内存。C++中的对象可与基本类型一样直接创建,创建时即分配内存,离开作用域时出栈释放。也可以在堆中创建即创建指针指向new的对象

void founction(){
     
yourClass obj1;
yourClass *obj2 = new class;
}//obj1释放,obj2指针释放 ,*obj2对象内存溢出
二.模板。

WTL是基于模板开发,模板是实现泛型编程的基础。可以将模板看成一种描述方式,用于描述一个类型的对象遵循模板类型对象的类型声明。
举个例子

//一个单纯的类A
class A {
     
void functionA(){
     
}
}

//一个单纯的类B
class B {
     
void functionB(){
     
}
}
//一个单纯的类P
class P {
     
void functionP(){
     
}
}

//准备一个遵循T模板的类C
template<class T>//声明模板
class C:public T{
     
void functionC(){
     

}
}
//自己定义Class D
class D :public C<A>{
     
}
//D就是一个包含 functionC,functionA的类这样的描述指明了D继承于C 而C继承于A同样
//自己定义Class E
class E :public C<B>{
     
}
//E则是包含 functionC,functionB的类

模板可以用于描述一种继承关系,也就可以在使用的时候再去定义一个对象继承于谁

//自定义一个class F
template<class T /* = P */>//声明模板同时注释其类型 
class F :public T{
     
void functionF(){
     
//调用自己继承而来的functionP 继承于F的类必须指定其模板参数为P及P的子类
functionP()
}
//或用于方法
//创建一个R类型的对象并调用其founctionP方法
template <class R /* = P */>
void founctionF2(){
     
R objR;
objR.founctionP();
}

void functionF3(){
     
//调用时必须使用P或P的子类
founctionF2<P>();
}
}

这么做则相当于我们创建一个F类并且指定其继承于T类,并且T必须是一个P的子类因为我们在F中直接使用了P的方法。
模板主要是为了多态服务。极大的增强了代码的可复用性。而且模板的替换是静态的,在编译时就可以发现错误。
但是会造成继承关系不清晰,调试错误难以定位的问题,使用错误会导致问题定位到模板中,因此,不要设计业务十分复杂的模板类。
WTL中模板主要用于声明自定义控件的继承类型 。

三. 虚函数

对于一个类中的函数使用virtual关键字 则这个函数是一个虚函数

virtual void founction(){
     };//虚函数
virtual void founction() = 0;//纯虚函数

虚函数可以视作是一种接口声明。
纯虚函数更多是一种描述性用途,它规定了包含纯虚函数的类为基类 ,不可直接使用只能使用其子类。

回到WTL

在理解以上三点后 就可以开始了解WTL界面搭建的基本工具了。
在Win程序中 一切界面元素皆是CWindow。在WTL中最基本的界面类是CWindowImpl
在正式开始使用前先简单了解一下CWindowImpl
从零开始的WTL入门教程(2)创建第一个窗口_第1张图片

它有三个模板参数 其中 T自定义的类 TBase 是WinAPI中的窗口类 TWinTraits 是设置模板,可以不使用 先无视它。
从它的定义可以看出来两个泛型参数 TBase用于类型传递,T则用于本地调用,让CWindowImpl能够调用到你自定义的类的一些类方法,如果你重写了这些方法。防止子类重写这些方法后调用的仍然是父类的这些方法。
接着向上看
从零开始的WTL入门教程(2)创建第一个窗口_第2张图片
这里给与了Tbase以及TWinTraits 初始值因此如果你不写这两个参数,才不会报错。这个类主要是设置窗口的一些默认属性。可以不用关心他。接下来它又将TBase传递给了CWindowImplRoot。接着向上看。
从零开始的WTL入门教程(2)创建第一个窗口_第3张图片
这样我们就找到了最终的目的地 传递到这里的TBase指定了自定义控件的实际基类。
并且它同时继承于CMessageMap马上就会用到。我们先看一看它。
从零开始的WTL入门教程(2)创建第一个窗口_第4张图片
CMessageMap 中 定义了一个纯虚函数ProcessWindowMessage。也就是这里让我们必须使用CWindowImpl的子类并且必须实现ProcessWindowMessage方法。CMessageMap贴心的提供了一整套宏命令用来实现消息和消息转发。后面用到时会讲。
整理一下:
继承于CWindowImpl的类需要至少传三个参数 其中 T 用于 CWindowImpl 调用。TBase 必须是 CWindow 及它的子类,有默认值CWinodw,实际用途为传递到最后给CWindowImplRoot并被它继承为该自定义类的基类。TWinTraits用于设置样式有默认值。

定义第一个自定义的窗口

从零开始的WTL入门教程(2)创建第一个窗口_第5张图片
此时创建了一个FirstWindow 类,它是一个基本的WTL对象。继承于CWindow
由于CMessageMap中的纯虚函数存在,因此必须添加
宏命令对其做出实现。

BEGIN_MSG_MAP(FirstWindow)
END_MSG_MAP()

这些是自动创建的构造函数和析构函数。如无需要,可以删掉。

	FirstWindow();
	~FirstWindow();
FirstWindow::FirstWindow()
{
     
}

FirstWindow::~FirstWindow()
{
     
}

练习项目中可以将代码全部写在.h文件。

然后使用它

WinMain函数中,Moudle创建后,消息循环开始执行前创建并显示这个窗口
从零开始的WTL入门教程(2)创建第一个窗口_第6张图片

其中CRect是描述位置大小的对象,可以设置上下左右边相对于父控件的位置。
创建了Window对象后需要调用Create方法创建窗口
该方法有以下几个参数

         In_opt_ HWND hWndParent, //父控件的句柄
		_In_ _U_RECT rect = NULL,//指定位置大小
		_In_opt_z_ LPCTSTR szWindowName = NULL,//窗口名称,会显示在左上角系统栏。默认样式可见
		_In_ DWORD dwStyle = 0,//窗口风格类型,属性设置 
		_In_ DWORD dwExStyle = 0,//窗口扩展风格
		_In_ _U_MENUorID MenuOrID = 0U,//资源ID,可以理解为该对象的数字标记,后面使用资源文件的时候会再次用到
		_In_opt_ LPVOID lpCreateParam = NULL//16位机遗留参数。现在用不着

这里我简单解释一下句柄
句柄是是一个结构体表示一个Window资源,也就相当于它的索引,通过句柄可以找到这个资源。也就可以通过句柄发收消息。CWindow对运算符进行了重载。使得CWindow的赋值操作实际只是让另一个CWindow对象的句柄指针指向目标对象的句柄。暂时了解一下就行了。
从零开始的WTL入门教程(2)创建第一个窗口_第7张图片

在Create方法中指定句柄通常用于设置控件位置,也就是说 rect参数设置的控件位置是相对于 hWndParent 的。而指定hWndParent为空的时候,窗口的位置是相对于屏幕的,左上角为0.0点,向右/向下为正轴
此时我们添加的代码创建了一个从屏幕左上角X/Y轴均为以10为起点到500为终点的FirstWindow类型的窗口。执行一下看看
从零开始的WTL入门教程(2)创建第一个窗口_第8张图片
看起来左侧边距似乎是要比顶部多一些,这是因为系统窗口的样式是有边框的,分布在左右下侧,在Win10中为透明样式,大约8像素
窗口缺了一个关闭按钮
可以在创建时dwStyle属性中设置该参数。可以使用 | 按位操作同时设置多个 。然后可以可以使用X按钮关闭窗口。

Window.Create(NULL, rc, "HELLO WORLD",WS_VISIBLE | WS_SYSMENU,NULL,0U,NULL );

从零开始的WTL入门教程(2)创建第一个窗口_第9张图片

但是这并不能关闭程序!
点击X只是隐藏了窗口,程序仍然在主方法中循环,没有任何变量被释放。
从零开始的WTL入门教程(2)创建第一个窗口_第10张图片
我们要在关闭窗口的时候关闭程序,就要用到消息机制。
在WTL窗口中的生命周期方法,界面交互都有对应的消息分发到对应的类中。这些消息的接收转发,都被封装为一系列的宏命令,将其插入到BEGIN_MSG_MAPEND_MSG_MAP之间并实现对应的方法即可接收消息
从零开始的WTL入门教程(2)创建第一个窗口_第11张图片
PostQuitMessage(0) 是WinApi方法,可以结束程序。
MSG_WM_CLOSE(OnClose) 声明了由OnClose方法接收关闭窗口的消息。
可以更改方法名,但是一般使用原头文件中的方法名以便阅读
同理可以推得,如窗口创建,移动,绘制鼠标时间等大量的生命周期/操作相应等系统管理的事件都可以通过这个机制来操作
从零开始的WTL入门教程(2)创建第一个窗口_第12张图片
可以直接去对应的头文件中找到消息和消息参数定义。
但是要注意 调用该方法结束应用前必须删除掉所有你创建的窗口
从零开始的WTL入门教程(2)创建第一个窗口_第13张图片
DestroyWindow() 可以删除当前窗口,也可以填入一个窗口的句柄用于删除指定窗口。
从零开始的WTL入门教程(2)创建第一个窗口_第14张图片
从零开始的WTL入门教程(2)创建第一个窗口_第15张图片
从零开始的WTL入门教程(2)创建第一个窗口_第16张图片

你可能感兴趣的:(WTL/C++)