一、前言
自從做監控系統以來,就一直有打算將這個功能獨立出來一個類,這樣的話很多系統用到此類布局切換,通用這個類就行,而且后期此布局會增加其他異形布局,甚至按照16:9之類的比例生成布局,之前此功能直接寫在功能界面UI類中,不方便拓展,好多個系統用到此功能,一旦增加了64布局、128通道布局等,都需要做對應更改,煩不勝煩,所以務必將此功能徹底剝離出來,為后面的256通道、異形布局、自定義布局打基礎。
通道切換在視頻監控系統中是最基礎的必備功能,一般都會提供1通道、4通道、6通道、8通道、9通道、16通道這幾個通道切換,可能做得比較好的還會提供24通道、32通道、64通道的,這個可能對電腦的配置就有一定要求了,一般來說,超過9個通道實時顯示視頻流,基本上會采用子碼流來顯示,如果都采用主碼流,電腦壓力非常巨大,CPU占用很高,內存也高,不過現在的電腦配置越來越高,基本上四千多塊錢的台式機,配置已經非常好了,顯示個16個通道的實時視頻毫無壓力。
Qt中的布局非常好用,尤其是QGridLayout表格布局,可以指定行列放置控件,而且還可以設置每個控件占用幾行幾列,這樣就可以完美的實現各種通道布局了。比如6通道,可以設置通道1占用兩行兩列,其他通道各站一行一列即可,當切換布局的時候,其他隱藏即可。
二、主要功能
- 將所有通道切換處理全部集中到一個類。
- 通用整數倍數布局切換函數,可方便拓展到100、255通道等。
- 通用異形布局切換函數,可以參考進行自定義異形布局。
- 通道布局切換發出信號通知。
- 可控每種布局切換菜單是否啟用。
- 支持自定義子菜單布局內容。
- 支持設置對應的菜單標識比如默認的通道字樣改成設備。
三、效果圖

四、開源主頁
- 以上作品完整源碼下載都在開源主頁,會持續不斷更新作品數量和質量,歡迎各位關注。
- 本開源項目已經成功升級到V2.0版本,分門別類,圖文並茂,保你爽到爆。
- Qt開源武林秘籍開發經驗,看完學完,20K起薪,沒有找我!
- 國內站點:https://gitee.com/feiyangqingyun/QWidgetDemo
- 國際站點:https://github.com/feiyangqingyun/QWidgetDemo
- 開源秘籍:https://gitee.com/feiyangqingyun/qtkaifajingyan
- 個人主頁:https://qtchina.blog.csdn.net/
- 知乎主頁:https://www.zhihu.com/people/feiyangqingyun/
五、核心代碼
void VideoBox::change_video_normal(int index, int flag)
{
//首先隱藏所有通道
hide_video_all();
int count = 0;
int row = 0;
int column = 0;
//行列數一致的比如 2*2 3*4 4*4 5*5 等可以直接套用通用的公式
//按照這個函數還可以非常容易的拓展出 10*10 16*16=256 通道界面
for (int i = 0; i < videoCount; i++) {
if (i >= index) {
//添加到對應布局並設置可見
gridLayout->addWidget(widgets.at(i), row, column);
widgets.at(i)->setVisible(true);
count++;
column++;
if (column == flag) {
row++;
column = 0;
}
}
if (count == (flag * flag)) {
break;
}
}
}
void VideoBox::change_video_custom(int index, int type)
{
//從開始索引開始往后衍生多少個通道
QList<int> indexs;
for (int i = index; i < (index + type); ++i) {
indexs << i;
}
if (type == 6) {
change_video_6(indexs);
} else if (type == 8) {
change_video_8(indexs);
} else if (type == 13) {
change_video_13(indexs);
}
}
void VideoBox::change_video_6(const QList<int> &indexs)
{
//過濾防止索引越界
if (indexs.count() < 6) {
return;
}
//首先隱藏所有通道
hide_video_all();
//挨個重新添加到布局
gridLayout->addWidget(widgets.at(indexs.at(0)), 0, 0, 2, 2);
gridLayout->addWidget(widgets.at(indexs.at(1)), 0, 2, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(2)), 1, 2, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(3)), 2, 2, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(4)), 2, 1, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(5)), 2, 0, 1, 1);
//設置通道控件可見
for (int i = indexs.first(); i <= indexs.last(); i++) {
widgets.at(i)->setVisible(true);
}
}
void VideoBox::change_video_8(const QList<int> &indexs)
{
//過濾防止索引越界
if (indexs.count() < 8) {
return;
}
//首先隱藏所有通道
hide_video_all();
//挨個重新添加到布局
gridLayout->addWidget(widgets.at(indexs.at(0)), 0, 0, 3, 3);
gridLayout->addWidget(widgets.at(indexs.at(1)), 0, 3, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(2)), 1, 3, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(3)), 2, 3, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(4)), 3, 3, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(5)), 3, 2, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(6)), 3, 1, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(7)), 3, 0, 1, 1);
//設置通道控件可見
for (int i = indexs.first(); i <= indexs.last(); i++) {
widgets.at(i)->setVisible(true);
}
}
void VideoBox::change_video_13(const QList<int> &indexs)
{
//過濾防止索引越界
if (indexs.count() < 13) {
return;
}
//首先隱藏所有通道
hide_video_all();
//挨個重新添加到布局
gridLayout->addWidget(widgets.at(indexs.at(0)), 0, 0, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(1)), 0, 1, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(2)), 0, 2, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(3)), 0, 3, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(4)), 1, 0, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(5)), 2, 0, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(6)), 1, 1, 2, 2);
gridLayout->addWidget(widgets.at(indexs.at(7)), 1, 3, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(8)), 2, 3, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(9)), 3, 0, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(10)), 3, 1, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(11)), 3, 2, 1, 1);
gridLayout->addWidget(widgets.at(indexs.at(12)), 3, 3, 1, 1);
//設置通道控件可見
for (int i = indexs.first(); i <= indexs.last(); i++) {
widgets.at(i)->setVisible(true);
}
}
void VideoBox::change_video_1(int index)
{
//首先隱藏所有通道
hide_video_all();
//添加通道到布局
gridLayout->addWidget(widgets.at(index), 0, 0);
//設置可見
widgets.at(index)->setVisible(true);
}
void VideoBox::change_video_4(int index)
{
change_video_normal(index, 2);
}
void VideoBox::change_video_6(int index)
{
change_video_custom(index, 6);
}
void VideoBox::change_video_8(int index)
{
change_video_custom(index, 8);
}
void VideoBox::change_video_9(int index)
{
change_video_normal(index, 3);
}
void VideoBox::change_video_13(int index)
{
change_video_custom(index, 13);
}
void VideoBox::change_video_16(int index)
{
change_video_normal(index, 4);
}
void VideoBox::change_video_25(int index)
{
change_video_normal(index, 5);
}
void VideoBox::change_video_36(int index)
{
change_video_normal(index, 6);
}
void VideoBox::change_video_64(int index)
{
change_video_normal(index, 8);
}
