我在VS2008下做的。
步骤如下:
1)添加一个IDD_DIALOGBAR模板类型的对话框,使用class wizard产生类时,选择基类为CDialog,因为没有CdialogBar
2)把新建的类中的CDialog都改为CDialogBar,特别注意的是:该类构造函数的成员初值列的初始值为
3)给类添加三个成员变量
4)给类重载成员函数:两个create和CBRS_SIZE_DYNAMIC 的响应函数CalcDynamicLayout()。
之所以有两个Create函数,是因为该类的基类就有两个版本的Create函数。
这里需要说明的是:关键就是这个CalcDynamicLayout()函数,因为虽然MFC提供了CBRS_SIZE_DYNAMIC样式,但是默认情况下并没有调用相关的大小响应函数,所以要重载该函数使之生效,而也正是为了配合该重载函数,才添加了以上三个成员变量。
当然,相应的要在该类定义中添加这三个函数的声明。
这样,就可以让该dialog在浮动的时候改变大小了,但是不能同时改变宽和高,所以你无法看到一般的斜着的箭头。
可以看到,上述的dialog Bar的创建是把该类对象作为CMainframe的成员变量,这样dialogBar的生存期就等同于Mainframe。这和非模态对话框非常类似,MSDN上面也说DialogBar和modeless dialog类似。因为对话框有其相关的资源,不能随便释放,所以这里的dialog Bar对象不能是一个局部变量,其解决方法就是:
1)将之放入一个生存期较长的类中或者(上述所用的方法)
2)为之申请一个堆内存
后者在非模态对话框中似乎用的更常见:
而在后者情况下,因为申请了堆内存,所以当不再使用该类对象(无论是Modeless dialog还是用create创建的dialog bar)都需要释放其内存。而释放的最好方式莫过于让该类自身销毁之。这就提示我们重载PostNcDestroy()函数达到该目的。因为PostNcDestroy()是该类调用的最后一个函数。销毁一个窗口(该dialog自然也是继承自CWnd的)的一般过程就是WM_CLOSE消息调用DestroyWindow(),然后发出WM_NCDESTORY消息调用OnNcDestroy()函数,在该函数中调用PostNcDestroy()虚函数。所以释放内存的最好时机就是在该窗口按照规矩销毁了一切后,最后把这些申请的资源从内存中释放掉。从这个方面讲,用delete myClassObj的方式直接释放资源的方式是不好的,因为没有正常的去销毁对话框(销毁对话框和释放资源是不同的),这种方式具体的坏处我还没有细究,我试了一下似乎还没发现异常,应该是还没触发到相关异常。无论如何,还是建议重载PostNcDestroy()函数,在其最后delete this。
还需要说明的是,在上述两种方法创建dialogbar或Modeless dialog中,在不需要手动销毁dialog情况下,直接将之放入别的类中即可(第一种方式),这样就免得自己再去到堆里面申请内存然后重载PostNcDestroy()函数什么的,让他和程序一起结束得了。但是如果在程序运行过程中需要手动销毁之,比如对于dialogbar,我想在原来的dialog bar的地方将之销毁再新建一个dialog bar,那么第一种方式就有点不好搞了,因为不方便确定怎么销毁该dialog对象,直接调用其析构函数?那么下次产生一个新的dialog怎么产生呢?产生的就将是一个局部对象变量了,要么就只能模仿第二种方式申请堆内存了。所以在这种情况下,还是用第二种方法合适些:只需要在要销毁的时候调用该dialog的DestroyWindow()即可,因为正如前所述,它会一步一步调用PostNcDestroy()函数,而你,难道还没有在其最后添加上delete this;吗?
最后,需要注意的是:销毁掉该对话框后,还是有一个影子留在窗口里面,那是因为没有重绘新的客户区的缘故。而直接使之响应WM_PAINT时无效的,因为它重绘的客户区似乎还是以前的大小。所以我用了一个折中的欺骗用户的手法:使得窗口宽度增减1个像素。需要指明的是,我使用MoveWindow()使之重绘该窗口似乎也无效,具体的参见以下代码及其注释:
参考文献:http://kbalertz.com/143255/Resizable-Dialog.aspx