MFC动态窗口布局

[原文发表地址]MFC Dynamic Dialog Layout

[原文发表时间]2015/04/29 星期三 10:00PM

在MFC程序运行时,能够智能调整窗口的大小,以及他们的内容是MFC功能常见的需求之一(另外,谢谢你们的反馈,请继续)。

一种方法是拦截父窗口的WM_SIZE消息, 相应地重新计算子窗口的大小和位置。这个方法是有用的,但却是极容易出错的——请想象一下,在你的程序中为你每一个窗口里的每一个控件做这样的操作是多恐怖的事情。这样的做的话也会向你的应用程序的表示层引入非平凡逻辑,在将来维护起来会比较困难。

在Visual Studio 2015 RC 中,我们引入了一个一致的方法来控制程序运行时窗口布局——我们称它为动态窗口布局。

现在让我们通过一个示例为你们展示这个功能,假如一个窗口里面只有一个单独的按钮(请不要担心,我会展示更多的示例的)

如果想让这个窗口的大小可调,用户可以拉伸拖拽窗口,结果便会像下图所示的那样:

这样做的意义不大。为了使大小可调更加有作用,我们需要为按钮找一个更加适当的位置,并且调整按钮的大小才会更好。一个简单且合理的方法是让按钮依然放置在窗口的右下角。换句话说,当父窗口的大小随着水平方向上X的窗口单元以及垂直方向Y窗口单元调节的时候,我们希望按钮也向右和向下移动同样的量。

我们来试试按这样的方式实现吧。在资源编辑器中打开属性窗口, 点击窗口中的OK按钮。你会看到“动态布局”这个新的属性设置

现在修改“移动类型”的值为“两者”并且设置“移动X“和”移动Y”的值为100(记住,我们希望这个按钮随着主窗口的大小一起向右和向下移动):

我们现在还不打算修改”调整类型”——稍后我会讲解。

现在保存并重新编译程序。运行它并且拖拽窗口,看吧:

现在看起来非常有用,对不对?

让我们来让它更加实用,添加另一个“Cancel”按钮:

我们现在需要实现如何让所有的按钮都随着主窗口调整大小。最简单的方法是让“OK”按钮靠近左下角,让”Cancel“按钮贴近右下角。我们需要将OK按钮动态布局属性的”移动类型=垂直“,”Y方向移动=100“.让”Cancel“按钮的属性设置为”垂直,100,100“(就像上面那个例子对OK按钮的所做的操作那样)。

保存,编译,运行,调整大小:

还不错,对吧?

现在,让我们来试试”调整类型“这个属性。在我下面的示例中,我希望我的按钮的比例能和窗口的比例相协调。我们将会在这做一些算术,为了让它更加简单,我创建了一个新窗口,大小是200*100窗口单元。

没一个按钮的宽度设置为80个窗口单元(按钮的高在这个示例中不是很重要)

我希望按钮能够随着窗口变大和缩小,并且一直保持原始的比例——是80/200 或者是窗口宽度的40%。同时,我希望每个按钮和窗口边缘的空间是固定的。我们姑且称它为Δ:

我如何通过动态布局设置来完成呢?

让我们先从“OK”按钮开始。只要它移动,它会100%垂直移动使它相对于底边的位置固定。我同时希望它的大小可以动态地随着主窗口的调整而变化。按钮占了窗口宽度的40%,这意味着,每一次父窗口的宽度增加100个单元,按钮要相应的增加40个单元。下图是使用动态布局属性来完成这个要求得的:

“Cancel”按钮需要做更多的操作。随着父窗口的增大, 这个按钮将会在垂直方向和水平方向上移动。我想让按钮贴近底部边缘——垂直方向上的移动是容易实现的,让它是100%即可。接下来,我要复制“OK”按钮的“调整X”属性——这很容易理解,这样做是为了让两个按钮保持相同的调整比例,这样的话它们的大小将会一致,不论主窗口的大小如何。

现在,让我们计算一下“移动 X”属性。像我之前说的,我们在这要做一些算数,现在开始吧。当主窗口的宽度以100个单元的增长从200变化到300时,每变化一次,宽度将会相应的增长:80*300/200=120。最初“Cancel”按钮X方向的位置是200-Δ-80 =120-Δ。在主窗口的宽度增加100个单元之后,“Cancel”按钮新的X位置为:300-Δ-120=180-Δ。

听明白了吗?很好。正如我们计算的,“Cancel”按钮的位置从120-Δ变成180-Δ。也就是说幅度是60个单元。这就是我们的结果啦,X的位置变化占整个窗口宽度的60%。

其实还有很多其他的方法来计算, 一张纸巾,信封的背面(特别是对于那些有多个控件组的复杂的布局)算一算就可以了。我曾经开发过一个有用的心智模型就是问问“如果窗口的宽度(高度)每增加100个单元,那么我的控件应该增大或者移动多少。”

这是“Cancel”按钮动态布局属性的所有设置:

这是我们调整窗口大小后的样子,所有的东西都很正常完美:

当然,调整按钮不是那么有意思——但它确实让鼠标点击变得更加容易了。对于没有相关内容的控件,大小的调整变得很容易,例如列表框,树型控件等。

为了让它更有意义,我为窗口添加一个列表框。

我会让按钮的属性保持不变。列表框会水平和垂直的随着主窗口而增大,并且一直会停留在左上角(也是说不会移动):

这试调整过大小后的窗口:

我这里所讲的功能当时是通过程序可以实现的——动态窗口布局APIs已经添加进MFC。另外特别的是,如果你们不是那种点击鼠标的开发人员,你们可以在RC文件中直接编辑动态窗口布局属性。我们会在MSDN上有所记录,当然,为了让这篇博客不那么长,在这就不过多的说明了。

和往常一样,我们非常关心您的评论,这个功能还有一些不完善,您实时的反馈会让我们在RTM版本发布时减少很多疏忽。

下面是博文的示例代码如下所示:

MFC动态窗口布局示例