如果准备改进某个现有的控件,那么仅有的一个子控件一般要占据 UserControl 对象的整个可见画面。这可以通过在 UserControl 的 Resize 事件中使用子控件的 Move 方法来实现,如下所示:
Private Sub UserControl_Resize()
picBase.Move 0, 0, ScaleWidth, ScaleHeight
End Property
以上代码假定正在制作一个图片控件的增强版本。PictureBox 控件已经被放到 UserControl 上,其名称是 picBase。
如果要改进的控件具有最小尺寸,或某一个方向上的增加量比较大,例如 ListBox 控件的高度的变化单位可能是一个文本行的高度,那么还需要增加代码来判断 Move 方法是否产生了所需要的结果。
可以依靠被改进的控件处理绘图,包括(在适当的地方)显示缺省按钮的突出显示。
提示 为了能够适应不能随意调整尺寸的子控件,例如文本框和列表框,还必须增加代码来调整 UserControl 对象的尺寸。为了避免递归调用 Resize 事件耗尽栈空间,需要使用静态变量确定 UserControl_Resize 事件过程是否在进行递归的调用。
如果要制作一个控件组合,则 Resize 事件将更加复杂一些,因为多个子控件的尺寸和相对位置都必须进行调整。
如果要制作具有大量子控件的控件,就可能会有最小尺寸问题,控件尺寸小于最小尺寸时是无效的,这是因为,控件的可见尺寸太小了就没有任何用处,或者有的子控件有它自己的强制最小尺寸。
允许控件尺寸小至不合理不会造成真正的危害。许多控件都允许这么做,因为要限定它需要做很多工作,而且在很多情况下必须根据用户的实际需要来产生能够工作并且实用的应用程序。
如果某个事件将控件尺寸调整到小于阈值,导致控件无法正常工作,可以使所有的子控件都成为不可见的,这可以作为强制最小尺寸的一种替代方法。
以下代码提供了强制最小尺寸的简单示例:
Private Sub UserControl_Resize() Dim sngMinH As Single Dim sngMinW As Single '
调整子控件尺寸的代码。'
假定每个子控件都具有其'
最小尺寸,UserControl
的'
最小尺寸将由这些尺寸计算得到。sngMinW = <<Width calculation>>
sngMinH = <<Height calculation>>
If Width < sngMinW Then Width = sngMinW
If Height < sngMinH Then Height = sngMinH
End Sub
请注意,<<伪代码占位符>> 是用来计算控件的最小宽度和高度的。计算在 UserControl 的 ScaleMode 单元中进行。这些计算可能会很复杂,要涉及到几个子控件的宽度和高度。
如果有必要,UserControl 的 Width 和 Height 属性最后设置。
重点 如果有边框的话,UserControl 的 Width 和 Height 属性则会包括边框的厚度。如果 BorderStyle = 1 (Fixed Single),那么可供子控件使用的区域在宽度和高度上都会减少两个像素(不是缇)。如果 BorderStyle 属性可以被用户设置,则需要添加代码检查其当前值。
另一种方法是使用 Size 方法:
If Width > sngMinW Then sngMinW = Width
If Height > sngMinH Then sngMinH = Height
If (sngMinW <> Width) Or (sngMinH <> Height) Then
'
(可选的,设置递归标志。)Size sngMinW, sngMinH
'
(如果设置了,清除递归标志。)End If
这段代码有点复杂,但如果要避免调整控件尺寸时的递归,用它可以简化一些工作,见下面的讨论。
重点 UserControl 的 Width 和 Height 属性通常是以缇为单位的,而与 ScaleMode 的设置值无关。如果设置 ScaleMode 为缇以外的其它值,可以用 ScaleX 和 ScaleY 方法把最小尺寸转化为缇。
以上示例未包含处理递归的代码,递归实际上被允许了。例如,如果试着把控件的高度和宽度都调整到最小值以下,则 Resize 事件将重置 Width 属性,这将立即导致产生第二个 Resize。
第二个 Resize 事件将检查并重置高度值,然后返回,这是在第一个 Resize 事件检查高度值之前,而高度值已被重置为最小值。显然,这会使调试工作有点混乱。
即使在使用 Size 方法时,第二个 Resize 也会发生,并重复所有的计算。在调整控件尺寸时,设置一个标志即可避免上述情况。Resize 事件应该检查该标志,当标志为 True 时跳过所有的处理。
在处理最小尺寸的简单情况下,递归标志不是必需的,但在更加复杂的场合实际上它是必需的。
例如,如果在 Align 属性为 True 的控件中使用如上代码,使它能与它所在的窗体对齐,如“使控件与窗体边框对齐”中所述,那么无穷递归的错误将会发生,直到栈空间耗尽并发生错误。
重点 在 Resize 事件过程中总需要有错误处理。这里的错误不能由容器来处理,控件部件会因此失败,最终导致使用控件的应用程序失败。
详细信息 关于控件创建模型的详细内容,请参阅本章前面的“创建 ActiveX 控件的三种方式”。