搞嵌入式系统开发的,往往都是真全栈开发者。从硬件到驱动到操作系统到应用以及功能界面,是哪里需要搞哪里。这不,最近需要开发一个基于QT的界面功能,涉及到控件布局。因为不熟悉,走了一些弯路。这里将相关调试记录下来,方便以后参考。
多说一点。早些年不喜欢做UI,觉得体现不了水平,后来工作中涉及到相关开发后,发现界面也不是那么容易的。首先逻辑思维是第一关。业务代码不像系统代码那样,经过长时间的沉淀,功能需求都比较清晰。往往是各种需求一个接一个,前面这样设计了,后面又要因为新的功能,打破之前的流程,最终导致面条式的代码,揉在一起。因此,在最开始功能框架的设计时,好的抽象能力就显得特别特别重要,而且也是能力的一大考验。像QT的信号槽机制,Android的Activity组件机制,都是这类的典型代表。
其次,很多时候,界面不是独立的,往往都要嵌入到现成的框架中。比如QT也罢,Android也罢,早期的MFC也罢,都需要开发者对所依赖的框架有比较好的掌握。这样才能对各种控件的特性和结合有比较好的掌握,才能高效的写出高性能、稳定的界面应用来。笔者之前曾经做过一个Android下的视频会议应用。这个应用,有多个视频窗口,每个视频窗口里又独立的包含多个功能,还包括一些动态参量的刷新,比如音量。另外还嵌入了地图,地图上又可以浮动视频窗。按照Android的标准组件,一个嵌套一个的方法来设计,最终跑起来,发现能明显感觉到切换过程。打开Android自带的优化工具,可以看到分析出来的组件树十分的庞杂。这时候的优化,就看对Android自身界面设计思想的理解程度了。
回到主题。主要是这样一个需求:提供一个浮动框,里面展示设备状态,并添加几个控制按钮,根据状态实现一些快捷操作。
最开始考虑使用GridLayout做大的布局。将整体分为多行多列。逻辑上如下图:
完成后,根据布局要求,有几个小的调整地方。就是这几个调整地方,花了不少时间。
1 状态展示部分是三列的,按钮只有两个,想让按钮平分整个宽度,也就是一个按钮占用一个半列。如下图所示:
可以直接在GridLayout里嵌QHBoxLayout。QHBoxLayout是水平布局框,控件会在布局中一个一个从左到右排列。示例代码如下:
<layout class="QHBoxLayout" name="control">
<property name="leftMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<item row="0" column="0" rowspan="2">
<widget class="QPushButton" name="test1">
<property name="text">
<string> 测试1</string>
</property>
</widget>
</item>
<item row="0" column="1" rowspan="2">
<widget class="QPushButton" name="test2">
<property name="text">
<string> 测试2</string>
</property>
</widget>
</item>
</layout>
其中,我们将colspan=”3”,这样控件水平占据三个控件格宽度(上一级的GridLayout),但实际只布局了两个。
2 解决了宽度问题后发现按钮相比状态控件,显得过小。这就导致按钮不容易被点击触摸到。于是就衍生一个新需求,即如何调整按钮的高度。
这就需要借助rowstretch和rowspan两个属性了。第一个是放在上一级,也就是父一级的布局中的,第二个是放在当前子布局中的。
第一个属性说明了伸缩因子。值越大,对应item(从0开始)控件的可调整范围就越大。第二个是说在行方向上,占据几个单位大小。这里设定为2,结合伸缩因子,就可以把嵌入的按钮缩放到更大的范围。示例代码如下:
<layout class="QGridLayout" name="gridLayout" rowstretch="5,3,3,3,8" columnstretch="1,20,20"></layout>
...
<item row="4" column="0" colspan="3" rowspan="2">
<layout class="QHBoxLayout" name="control">
<property name="leftMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<item row="0" column="0" rowspan="2">
<widget class="QPushButton" name="test1">
<property name="text">
<string> 测试1</string>
</property>
</widget>
</item>
<item row="0" column="1" rowspan="2">
<widget class="QPushButton" name="test2">
<property name="text">
<string> 测试2</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
补充一点,控件布局是可用嵌套的,比如QGridLayout可用在某一个子项中嵌套一个新的QGridLayout,这样就可以实现更加复杂的布局。