4、地面站 UI 布局设计:从零搭一个看得过去的界面

做地面站,说白了就是给无人机造一个驾驶舱。你想想看,飞手盯着屏幕,要同时看高度、速度、地图、电池电量……信息一多,布局就特别容易乱。我早期做过一个原型,把所有控件堆在一个窗口里,结果自己调试时都找不到按钮在哪。嗯,那体验,别提多糟了。

今天我们就来聊聊,怎么用 Qt 的布局系统,搭一个既专业又清爽的地面站主界面。我会把我在几个项目里踩过的坑、总结的经验,一并倒出来。

4.1 布局三剑客:QVBoxLayout / QHBoxLayout / QGridLayout

Qt 的布局管理器,说白了就是帮你自动排控件的。你不需要手动算坐标,窗口缩放时它们会自动调整。我个人习惯,先把大框架定下来,再往里填细节。

4.1.1 QVBoxLayout:垂直堆叠

适合放从上到下的信息流。比如左侧的飞行数据面板,高度、速度、GPS 状态,一条条往下排。

QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(altitudeLabel);
vLayout->addWidget(speedLabel);
vLayout->addWidget(gpsStatusLabel);
vLayout->addStretch(); // 弹簧,把控件顶到上面
setLayout(vLayout);
我的小技巧: 记得加 addStretch(),不然控件会挤在一起。我曾经忘了加,结果窗口拉大时,三个标签贴在天花板上,下面空一大片,特别丑。

4.1.2 QHBoxLayout:水平排列

适合放并排的控件。比如地图和视频流,左右分屏。

QHBoxLayout *hLayout = new QHBoxLayout;
hLayout->addWidget(mapWidget, 2);   // 地图占2份
hLayout->addWidget(videoWidget, 1); // 视频占1份
hLayout->setSpacing(5);             // 控件间距5像素

这里有个坑:拉伸因子(那个数字 2 和 1)决定了控件在窗口缩放时的比例。我建议地图给大一点,毕竟飞手主要看地图。

4.1.3 QGridLayout:网格布局

适合做仪表盘。比如把姿态仪、罗盘、电池状态排成 2x2 的格子。

QGridLayout *grid = new QGridLayout;
grid->addWidget(attitudeIndicator, 0, 0); // 第0行第0列
grid->addWidget(compass, 0, 1);           // 第0行第1列
grid->addWidget(batteryWidget, 1, 0);     // 第1行第0列
grid->addWidget(radioWidget, 1, 1);       // 第1行第1列
注意: 网格布局的控件会默认填满格子。如果你想让某个控件居中,记得设置对齐方式:grid->setAlignment(compass, Qt::AlignCenter);

4.2 多标签页:用 QTabWidget 管理信息层级

地面站的信息太多了,全堆在一个页面里,飞手会疯掉。QTabWidget 就是用来做分页的。我一般分三个标签页:飞行数据、地图、设置。

QTabWidget *tabWidget = new QTabWidget;
tabWidget->addTab(flightDataPage, "飞行数据");
tabWidget->addTab(mapPage, "地图");
tabWidget->addTab(settingsPage, "设置");
tabWidget->setCurrentIndex(0); // 默认显示第一个标签

你想想看,飞手在飞行中主要看「飞行数据」和「地图」,设置一般在地面调好就不动了。所以我把前两个标签放在前面,第三个放后面。

经验之谈: 我曾经在项目里加了 7 个标签页,结果用户反馈说切换太麻烦。后来我合并成 3 个,把不常用的功能塞进「设置」里的二级菜单。记住:标签页不要超过 5 个,否则就是设计失败。

4.3 可停靠面板:QDockWidget 的灵活用法

QDockWidget 是 Qt 里最灵活的东西。它可以让用户把面板拖来拖去,停靠在主窗口的上下左右。我特别喜欢这个功能,因为不同飞手有不同习惯——有人喜欢把日志面板放右边,有人喜欢放下面。

QDockWidget *dock = new QDockWidget("日志", this);
dock->setWidget(logWidget);
dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
addDockWidget(Qt::RightDockWidgetArea, dock);

这里要注意:setAllowedAreas 限制了面板能停靠的位置。我一般只允许左右停靠,因为上下停靠会压缩地图的高度,影响视野。

避坑指南: 我曾经允许了所有方向,结果用户把面板拖到了底部,地图被压成一条缝。后来我改成只允许左右,世界清净了。

4.4 设计一个简洁的主界面原型

好了,理论说完了,我们来拼一个实际的原型。下面是我常用的布局方案:

// 主窗口
QMainWindow *mainWindow = new QMainWindow;

// 中央区域:用 QTabWidget 放地图和飞行数据
QTabWidget *centerTabs = new QTabWidget;
centerTabs->addTab(mapWidget, "地图");
centerTabs->addTab(flightDataWidget, "飞行数据");
mainWindow->setCentralWidget(centerTabs);

// 左侧:可停靠的仪表盘
QDockWidget *instrumentDock = new QDockWidget("仪表盘", mainWindow);
instrumentDock->setWidget(instrumentPanel);
instrumentDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
mainWindow->addDockWidget(Qt::LeftDockWidgetArea, instrumentDock);

// 右侧:可停靠的日志面板
QDockWidget *logDock = new QDockWidget("日志", mainWindow);
logDock->setWidget(logWidget);
logDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
mainWindow->addDockWidget(Qt::RightDockWidgetArea, logDock);

这个原型的好处是:

  • 中央区域是核心,地图和飞行数据一键切换
  • 左侧仪表盘显示姿态、高度、速度等实时数据
  • 右侧日志显示串口输出、错误信息
  • 所有面板都可以拖拽,用户自己调整
核心原则: 地面站的 UI 设计,不是炫技,是让飞手在紧张飞行时能一眼找到关键信息。所以,少即是多。能用一个按钮解决的,绝不用两个。

4.5 本章知识体系图

下面我用一张 SVG 图,把今天讲的布局逻辑串起来。你可以把它当作设计时的参考框架。

QMainWindow 主窗口 QDockWidget 仪表盘 姿态仪 高度 速度 GPS状态 电池 QTabWidget 中央区域 地图 飞行数据 设置 🗺️ 地图区域 (卫星图/航点) 无人机 QDockWidget 日志面板 [INFO] 连接成功 [WARN] 信号弱 [ERROR] 丢包 [INFO] 航点上传 ← 可拖拽停靠 → ← 标签页切换 → ← 可拖拽停靠 →

这张图展示了一个典型的地面站布局:左右可停靠面板 + 中央标签页。你可以在实际项目中,根据需求调整面板数量和位置。

4.6 小结

今天的内容,说白了就是三件事:

  1. 用布局管理器(QVBoxLayout / QHBoxLayout / QGridLayout)把控件排整齐
  2. 用 QTabWidget 把信息分页,避免界面爆炸
  3. 用 QDockWidget 给用户自由,让面板可拖拽

我个人觉得,地面站的 UI 设计,70% 的功夫在布局,30% 在美化。先把布局搞顺了,后面加样式表(QSS)才事半功倍。嗯,下一节我们会聊怎么用 QSS 给地面站「化妆」,让它看起来更专业。

最后提醒: 代码写完后,记得在不同分辨率下测试一下。我曾经在 1920x1080 的屏幕上调好的布局,换到 1366x768 的笔记本上就乱成一团。Qt 的布局系统虽然智能,但拉伸因子和最小尺寸还是要手动设好的。

可可精品资料库