关于DELPHI的布局

以下文章载自:【巴蛮子的破新茅屋】http://blog.csdn.net/bamanzi/archive/2006/02/11/596962.aspx

Windows编程的习惯是直接指定控件的座标和大小,而UNIX下面的习惯是在容器里面堆放,用不同的layout manager来控制布局(java,wx等也是这种思想)。这也是为什么Windows程序的对话框一般都不让改变大小(因为这意味着要自己写很多代码逐步调整子控件的位置),而UNIX下一般都可以。Delphi程序原来有Align属性来控制控件对那边靠拢。但如果想要一个控件固定离左边、右边有多远,得用D6开始提供Anchors属性。

所以DELPHI提供3种布局属性:Align, Anchor,和 Constraint。基本能满足布局设计的需要。

这样还是不够的,比如有七八个按钮顺排或者表格式布局,这在D2006里面可以用新增的TFlowPanel和TGridPanel来实现。

 

TFlowPanel和TGridPanel的使用方法:

http://edn.embarcadero.com/article/33421

呵呵,没找到中文说明的,只能看看E文了。里面的DEMO无法DOWN。

其中有一个事情要注意:任何一个控件被放到这两个布局上后,无法调整位置,DELPHI提供了一种方法,就是选择要调整的控件,在属性窗体的最下面会出现和布局有关的属性,进行调整就可以了。TFlowPanel有ControlIndex。TGridPanel有column,row,columnspan,rowspan。

   

评价

DELPHI提供的GridPanel貌似很好,但是使用起来实在不方便。我自己用GridPanel准备画一个人口信息的输入界面,结果画了一会就觉得烦了,根本没办法用。考虑再三,还是自己写一个。

至少提供如下功能:

1.能够在设计状态用鼠标调整行的行的宽度和列的高度。

2.panel的宽度和高度应该随着里面行和列的高度和宽度的变化而变化。而不应该是像GridPanel,宽度和高度不边,而让行和列的值来适应GridPanel。

3.能方便的增加和删除行和列。

4.放入pane中的控件的宽度要随着所在格子的宽度变化而变化。

开发思路:

1.从TCustomGridPanel继承。

2.在设计状态当鼠标移动到网格线上的时候,Cursor变成可crHSplit和crVSplit,(可以通过继承WMSetCursor来实现)

3.设计状态,当在网按住鼠标并移动的时候,修改对应的格子的大小(可以通过继承WMLButtonDown,WMLButtonUp,和WMMouseMove来实现)

4.当Panel上放入一个控件的时候,自动设置到对应格子的宽度(可以通过继承AlignControls来实现)。

5.增加RowCount和ColumnCount属性,可以通过设置这两个属性来设置行和列的总数。

效果:

   

 

 

可惜,这个GIF无法显示鼠标移动到网格中的时候改变鼠标形状的情况。

DELPHI问题

在写这个panel的时候发现一个问题,可能是DELPHI的BUG

ExtCtrls单元第3500行,procedure TCustomGridPanel.AlignControls(AControl: TControl; var Rect: TRect);方法中,代码如下:

AnchorSubset := AControl.Anchors * [akLeft, akRight];

if AnchorSubset = [akLeft] then

NewBounds.Left := CellRect.Left

else if AnchorSubset = [akRight] then

NewBounds.Left := Max(CellRect.Left, CellRect.Right - AControl.Margins.ExplicitWidth)

else

NewBounds.Left := Max(CellRect.Left, CellRect.Left + ((CellRect.Right - CellRect.Left) - AControl.Margins.ControlWidth) div 2);

这个应该是一个明显的BUG,如果Control的Anchors同时设置了akLeft和akRight,则系统就不再处理,也就是前面提到的如果用GridPanel,放到PANEL上的控件无法根据格子的宽度自动调整宽度。

修复方法:增加一个判断就可以:

AnchorSubset := AControl.Anchors * [akLeft, akRight];

//hl add 20090415原来控件没有提供对 Anchors = akLeft, akRight的处理

if AnchorSubset = [akLeft, akRight] then

begin

NewBounds.Left := CellRect.Left;

NewBounds.Right := CellRect.Right;

end

else begin

if AnchorSubset = [akLeft] then

NewBounds.Left := CellRect.Left

else if AnchorSubset = [akRight] then

NewBounds.Left := Max(CellRect.Left, CellRect.Right - AControl.Margins.ExplicitWidth)

else

NewBounds.Left := Max(CellRect.Left, CellRect.Left + ((CellRect.Right - CellRect.Left) - AControl.Margins.ControlWidth) div 2);

NewBounds.Right := NewBounds.Left + Min(CellRect.Right - CellRect.Left, AControl.Margins.ExplicitWidth);

end;

原文地址:https://www.cnblogs.com/barryhong/p/1429073.html