## 一、前言说明
监控系统中有很多视频画面需要同时显示,有时候需要同时显示4个画面,也就是2x2的布局,这种整数倍的布局是最容易实现的,搞个表格布局按照行列格式插入对应视频控件即可,还有一种非对称的布局,但是整体拉伸比例也完全一致,比如6个画面同时显示,其中一个画面占用两个行列,然后右侧和底部各放两个视频控件,加上右下角的1个,总共6个画面,这种也是用表格布局,只不过在插入第一个最大显示的画面的时候,需要指定占用的行列数,这种差不多的人稍微动动脑子,也是可以搞定的。
上面的布局情况涵盖了几乎所有的情况,也是见过的所有视频监控系统中最常用的布局,几乎都是按照这个规则来整的,现在又有了新的需求,需要增加异形布局,比如现在有些是拼接的视频画面,不是16:9之类的,是一个很大的长宽比,宽度非常大,可能有三五个摄像头拼接的,但是视频流画面是一个完整的,按照之前的布局就基本上不大适合,可能需要3通道布局,上面放两个视频画面,下面放一个画面占用两列,当然这种依然使用的表格布局来,只不过不是所有通道的拉伸比例一样,底部的大通道是不同的拉伸比例,依次类推,还有专门播放手机视频的竖条的布局比如2x6布局,两行6列,因为手机视频一般是垂直的,所有按照这种比例拉伸更合适。
之前布局是写在视频布局窗体中,后面随着功能越来越多,单独搞了个videobox视频盒子的自定义控件,负责管理各种布局,也可以自行增加异形布局,里面已经写好了各种可能的布局的函数,只要传入对应的参数即可,使用起来非常方便。当前这个视频布局控件是开源的,我看很多人都用的我这个控件。也算是回馈了开源社区。
## 二、效果图
## 三、相关代码
```cpp
#pragma execution_character_set("utf-8")
#include "videobox.h"
#include "qapplication.h"
#include "qevent.h"
#include "qmenu.h"
#include "qaction.h"
#include "qgridlayout.h"
#include "qdebug.h"
VideoBox::VideoBox(QObject *parent) : QObject(parent)
{
isMax = false;
maxCount = 64;
type = 16;
layoutType = "1_16";
menu = NULL;
gridLayout = NULL;
menuFlag = "画面";
actionFlag = "通道";
//通过这里设置好数据/下面只需要循环添加和判断就行/灵活性大大增强/只需要这里改动下就行
//自定义x布局/按照行列数生成/可以通过appendtype函数添加其他类型
//1_2x4表示通道1开始/2x4行列布局画面/相当于通道1-8按照2行4列排列
//9_2x4表示通道9开始/2x4行列布局画面/相当于通道9-16按照2行4列排列
types.insert("x", QStringList() menu = new QMenu((QWidget *)this->parent());
} else {
this->menu = menu;
}
//约定依次是按照顺序控制启用状态
int count = visibles.count();
if (count > 0 && visibles.at(0)) {
addMenu(this->menu, "x");
}
if (count > 1 && visibles.at(1)) {
addMenu(this->menu, "y");
}
if (count > 2 && visibles.at(2)) {
addMenu(this->menu, "4");
}
if (count > 3 && visibles.at(3)) {
addMenu(this->menu, "6");
}
if (count > 4 && visibles.at(4)) {
addMenu(this->menu, "8");
}
if (count > 5 && visibles.at(5)) {
addMenu(this->menu, "9");
}
if (count > 6 && visibles.at(6)) {
addMenu(this->menu, "13");
}
if (count > 7 && visibles.at(7)) {
addMenu(this->menu, "16");
}
if (count > 8 && visibles.at(8)) {
addMenu(this->menu, "25");
}
if (count > 9 && visibles.at(9)) {
addMenu(this->menu, "36");
}
if (count > 10 && visibles.at(10)) {
addMenu(this->menu, "64");
}
}
void VideoBox::show_all()
{
//一般是从配置文件读取到了最后的通道画面类型进行设置
int type = 1;
int index = layoutType.split("_").first().toInt() - 1;
//y开头的布局需要重置索引=0
if (layoutType.startsWith("y")) {
index = 0;
}
QMap::iterator iter = types.begin();
while (iter != types.end()) {
QStringList flags = iter.value();
if (flags.contains(layoutType)) {
type = iter.key().toInt();
change_layout(type, in