在Lazarus下的Free Pascal编程教程——布局方法对比、修改已经完成的布局

0.前言

我想通过编写一个完整的游戏程序方式引导读者体验程序设计的全过程。我将采用多种方式编写具有相同效果的应用程序,并通过不同方式形成的代码和实现方法的对比来理解程序开发更深层的知识。

了解我编写教程的思路,请参阅体现我最初想法的那篇文章中的“1.编程计划”和“2.已经编写完成的文章(目录)”:

学习编程从游戏开始——编程计划(目录) - lexyao - 博客园

我已经在下面这篇文章中介绍了使用LCL和FCL组件构建一个项目(pTetris)的过程,后续的使用Lazarus的文章中使用的例子都是以向这个项目添加新功能的方式表述的:

在Lazarus下的Free Pascal编程教程——用向导创建一个使用LCL和FCL组件的项目(pTetris) - lexyao - 博客园

这是一篇专题文章,我们将通过向已经完成布局的界面添加新的组件这个话题进一步探讨各种布局方法的优缺点,讲述灵活运行布局方法的问题。

俄罗斯方块游戏中显示方块的区域有两个:一个是方块移动和堆积的区域,一个是提示下一组方块样式的区域。我们将改变下一组方块提示区的设计思路,提供更多的提示,而这种修改将涉及到向已经完成布局的界面中添加新的组件的问题。

在这篇文章里,我主要讲述以下几个方面的内容:

  1. 在程序设计中要灵活运用各种布局方法
  2. 使用坐标Top、Left定位布局的优缺点
  3. 使用组件对齐属性Align布局的优缺点
  4. 使用锚点属性Anchors布局的优缺点
  5. 使用布局组件TFlowPanel布局的优缺点
  6. 向pTetris项目主窗口添加方块提示区容器组件pnNext
  7. 结束语

 

1.在程序设计中要灵活运用各种布局方法

在组件的下方和右侧添加组件直接添加就行了,而在组件的上方和左侧添加新的组件就会导致其他组件位置的变化,从而使得添加组件的操作变得复杂了许多。
在上方和左侧添加组件的道理是一样的,下面的讨论将以在左侧添加组件的方法为题展开。
布局的方法很多,但没有办法说哪一个更好,只能说哪一个更适合。其实,没有一种布局方法是万能的,每一种方法都有优缺点。在程序设计的界面布局中,通常都是多种布局方法结合使用,各取所长,取长补短,利用灵活的组合达到布局的目的。总之就是一个原则:怎么省事就怎么做。
对于复杂的布局,通常离不开容器组件。将多个组件放入一个容器组件中,在布局的时候只考虑容器就行了,不必在考虑容器内的组件。经过容器组件的层层包装,复杂的问题就简单化了。
对于使用布局组件或者组件的布局属性无法做到的布局,使用编写代码的方式调整也是一种常用的手段。其实,所有的布局都是通过编写代码实现的,只是编写代码的人不同罢了。对于布局组件和组件的布局属性来说,是通过组件设计者编写的代码进行布局的,我们使用的时候只看到组件,而没有看到代码。就像我们买了一辆汽车,只知道开车,却不知道汽车内部是怎么做的。
如果觉得有必要,也可以看一看组件的布局属性是怎么实现的,这对我们会有帮助。当我们编写组件或者使用没有窗体设计器的编程环境的时候,只能使用代码来布局,那时这些布局组件的实现方法就有了参考价值。
在这里先把我对这几种布局方法优缺点的认识总结如下:

  • 使用Top、Left坐标定位最灵活,完成任意布局需求,缺点是需要计算位置,不能自动调整
  • 使用Align用于靠边停放、占据客户区等方式最为合适,操作简单,缺点是自身尺寸随容器变化,不受自身控制。其实这个缺点也是它的优点
  • 使用Anchors通过设定锚点进行对齐、对中、对接时最方便,可灵活使用,借助容器的嵌套可实现更好的效果,缺点是设置锚点比较繁琐,组件数量大时需要借助容器嵌套
  • 使用TFlowPanel可以自动排列,对齐对接排列时自动完成,缺点是组件增多时容易失控,需要通过多重嵌套来达到布局效果

为了便于描述、比较各种布局方法的优缺点,我们以以下几个题目的解决方法来评价,当然这样做也可能有片面性,就算是抛砖引玉吧。

  • 将容器内的组件横向排列
    • 保持不同的间距
    • 垂直方向不同的对齐方式
    • 在中间、左边插入一个组件
  • 容器AutoSize打开和关闭情况下上述操作的差别
  • 方法不能实现时可以选用的其他方法

2.使用坐标Top、Left定位布局的优缺点

使用组件的Top、Left属性以容器客户区坐标系确定组件在容器客户区中的位置,可以进行任何形式的排列,包括其他方式无法做到的组件重叠。
当容器的AutoSize=false时,组件位置相当于不设定参照组件的锚定。组件与启用了锚点的一侧与容器的边缘的距离是固定的:

  • 相对于容器上边和左侧的距离就是组件的Top、Left属性值。
  • 如果右侧和下边启用了锚点,则于容器边缘的差值总是保持设计时设定的距离。
  • 当相对的两边都启用了锚点,则组件会随着容器的变化被实时拉伸。

与通过BorderSpacing设置边界空白留出的距离不同,按坐标留出的空白区可以放置其他组件。也就是说组件与锚定的边缘之间存在组件不影响组件与被锚定的边缘之间的关系,这是其他方式所不具备的。
当容器的AutoSize=true时,

  • 与容器边缘最近的组件与容器客户区边缘的距离自动调整为0,而同意容器内组件的相对位置不会发生变化。
  • 容器内有拉伸效果的组件将会随着容器的变化而被压缩。
  • 每个组件至少启用两个方向的锚点,如果所有组件都没有启用锚点,容器的大小将调整为0。

在容器中插入新的组件,可以按坐标放在任何位置,包括与其他组件重叠。如果不希望组件重叠,则需要移动插入组件右侧和下方的组件的位置。
当AutoSize=true时,要想把新添加的组件放在所有组件的左侧,可以通过设置新添加组件的Left为负数将新添加的组件移动到最左边。设置Left为负数后,容器会自动将新添加的组件的Left值调整为客户区左边的坐标值,而容器中的其他组件全部自动向右移动,组件之间的相对距离不变。利用这一特性可以实现容器内组件的全体平移。

使用坐标定位布局的缺点是需要计算确定组件的位置,设计时确定的组件大小不能自动适应运行时可能出现的变化。如果运行期出现需要调整的情况,只能通过使用代码计算组件新的坐标位置的办法来调整。

3.使用组件对齐属性Align布局的优缺点

当组件需要停靠在容器边缘或者铺满客户区剩余空间的时候,Align是最好的布局方法。
组件停靠到容器的一侧时,它的尺寸会随着容器自动调整而不能通过设置属性值来改变。利用这一特性可以实现组件的等宽或等高整齐排列。
设置了停靠的组件可能会与没有设置停靠的组件重叠。

4.使用锚点属Anchors性布局的优缺点

使用锚点属性可以确定组件间的相互关系,当组件大小发生变化时会自动调整,这种调整会保持组件之间的相对关系不变。
通过设置描点可以布置出复杂的布局,而且能够随着容器变化而自动调整,但组件数量很大时设置锚点的工作量会增大。使用容器将组件分组可以取得更好的布局效果。
当AutoSize=true时,组件之间的锚定关系需要从上到下、从左到右依次设置,否则可能出现不可控的问题。

5.使用布局组件TFlowPanel布局的优缺点

使用TFlowPanel组件作为容器布局最大的好处是组件会按着容器的设置自动调整,但组件数量增大时会发生失控的情况。
通过容器的多层嵌套组合可以形成复杂的布局。使用TFlowPanel组成的布局具有自动调整能力,合理使用TFlowPanel可以减少布局的工作量。
使用TFlowPanel布局的缺点是有时会出现不可控的情况。

6.向pTetris项目主窗口添加方块提示区容器组件pnNext

pTetris主窗口的布局主要是使用TPanel组件多层嵌套和Anchors设定锚点来实现的。添加新的组件也要使用这一个特点。
关于方块提示区的布局问题,我们提出如下要求:

  • 方块提示区放置在pnScreen内部的最左边,高度与方块移动区pnBox相同
  • 可以提示多组即将进入方块移动区的方块
  • 实现方法是在pnScreen中添加一个跟pnBox一样的面板pnNext,在pnNext中放置一个cxGrid组件grdNext,用来显示即将进入移动区的方块队列

按着这些要求,添加pnNex组件的操作步骤如下:

  • 向pnScreen添加一个TPanel组件,将Name属性改为pnNext
  • 设置pnNext左侧锚点对齐pnScreen左边,顶部锚点对中pnScreen左边
  • 设置trcStart组件左侧锚点对接pnNext,顶部锚点对中pnNext右边(对中pnScreen左边的效果相同)

由于pnNext的高度和宽度使用放在它内部的grdNext调整,所以设计时可以不用考虑它的大小,只要调整到能看得见就行了。为了布局中调整pnScreen的宽度其他相关的组件,还是需要将pnNext的宽度设置为接近运行时宽度的数值。在这里设置pnNext的宽度为5个方块的宽度,也就是5x17=85。
由于添加了pnNext,pnScreen组件原来的宽度不够了,需要增加宽度值。
这样添加pnNext组件的操作就算是完成了。由于布局组件的作用,让添加组件的操作变得简单了。
添加grdNext组件的操作将在另一篇文章中描述:

在Lazarus下的Free Pascal编程教程——向窗体动态添加组件 - lexyao - 博客园

7.结束语

布局是一项考验智慧和美感的工作,仁者见仁智者见智。灵活运用布局属性和容器嵌套是布局中常用的方法。在布局时根据需要使用合适的方法,通常是多种方法的组合,而不是单选某一个特定的方法。

posted @   lexyao  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示