年底奉献-QT编写视频监管平台

admin 2022年10月2日07:34:40评论34 views字数 8932阅读29分46秒阅读模式

忙忙碌碌又是一年,算算自己毕业四年半,一直在现在这家公司做研发外加总经理助理,研发起初用的VB.NET,而后全面转为C#,最后又全面转为QT,都是由于项目需要,算下来自己搞QT编程也已经四年了,2010年开始接触QT并编写一些公司需要的辅助工具,其实搞程序的,我感觉绝大部分都是出于本身兴趣爱好,然后持之以恒的钻研,不断成长和进步。

项目需求:某区下面有几百所学校,每个学校都有若干台NVR或者DVR,每台NVR和DVR都挂接着N个IPC(摄像机)(包括网络摄像机和模拟摄像机),现在需要对所有学校的监控进行查看以及回放和轮询,能够对指定学校进行视频监控,对所有学校的视重点部位视频进行查看轮询,可自定义轮询时间等。

开发过程:本着尽量追求简洁的要求,最终编写了如上图的主界面。没有采用QT自带的界面,而是重写了界面,自定义无边框拖动,自由换肤,全部采用QSS控制,从官网http://qt-project.org/doc/qt-4.8/stylesheet-examples.html彻底学习了下QSS的规则,整理了一套通用的换肤方案。

PS:这是6年前写的项目,新版在这,不开源 https://www.cnblogs.com/feiyangqingyun/p/10913375.html

整个系统在开始架构的时候,本人都是写在草稿纸上的,包括布局,功能点,需要注意的处理等方面,现在要重新一一仔细写出来,还真不容易,这里就说个大概,然后将其中的部分功能处理用代码描述。

功能点罗列:

1:只限定一个实例处理。

视频监管平台是一个独占视频通道资源的系统,不能运行多个实例在同一台电脑上运行,所以在main函数中就限制了一个实例运行。

QSharedMemory mem("VM");    if (!mem.create(1)) {        myHelper::ShowMessageBoxError("程序已运行,软件将自动关闭!");        return 1;    }

其中VM为自定义的名称,return 1表示退出程序返回1给操作系统。

如果重复运行会弹出如下提示:

年底奉献-QT编写视频监管平台 

2:F1键进入全屏模式,Esc键退出全屏模式。

几乎所有的视频监控系统,主界面都支持全屏显示及esc退出全屏,在QT中我是这样实现的,重写了主界面的keyPressEvent事件,拦截按键消息,判断对应按键,调用全屏及普通模式的方法。

void frmMain::keyPressEvent(QKeyEvent *event){    //空格键进入全屏,esc键退出全屏    switch(event->key()) {    case Qt::Key_F1:        screen_full();        break;    case Qt::Key_Escape:        screen_normal();        break;    default:        QDialog::keyPressEvent(event);        break;    }}
void frmMain::screen_full(){ this->setGeometry(qApp->desktop()->geometry()); this->layout()->setContentsMargins(0, 0, 0, 0); ui->widget_main->layout()->setContentsMargins(0, 0, 0, 0); ui->widget_title->setVisible(false); ui->treeMain->setVisible(false);}
void frmMain::screen_normal(){ this->setGeometry(qApp->desktop()->availableGeometry()); this->layout()->setContentsMargins(1, 1, 1, 1); ui->widget_main->layout()->setContentsMargins(5, 5, 5, 5); ui->widget_title->setVisible(true); ui->treeMain->setVisible(true);}

 3:支持QT4到QT5各个版本编译运行。

QT5与QT4的区别还是让很多搞QT开发的同学着实生气了一把,好端端的把一些方法去除掉了,而且有些头文件重新移到了其他地方,为了兼容QT4与QT5,在项目中就需要增加很多对版本的判断了。

例如头文件的包含:

#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))#include #endif

例如设置UTF-8编码:

static void SetUTF8Code() {#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))        QTextCodec *codec = QTextCodec::codecForName("UTF-8");        QTextCodec::setCodecForLocale(codec);        QTextCodec::setCodecForCStrings(codec);        QTextCodec::setCodecForTr(codec);#endif
}

4:基本常用的数据库处理,添加删除修改操作,表格显示。

本人一直喜欢采用拼接sql字符串来执行SQL语句。觉得这样运行效率很高,而且这种方法通用任何编程语言。

void frmIPC::on_btnAdd_clicked(){    QString IPCID = ui->cboxIPCID->currentText();    QString IPCName = ui->txtIPCName->text();    QString NVRID = ui->cboxNVRID->currentText();    QString NVRName = ui->cboxNVRName->currentText();    QString IPCType = ui->cboxIPCType->currentText();    QString IPCRtspAddrMain = ui->txtIPCRtspAddrMain->text();    QString IPCRtspAddrSub = ui->txtIPCRtspAddrSub->text();    QString IPCUserName = ui->txtIPCUserName->text();    QString IPCUserPwd = ui->txtIPCUserPwd->text();    QString IPCUse = ui->cboxIPCUse->currentText();
if (IPCName == "") { myHelper::ShowMessageBoxError("名称不能为空,请重新填写!"); ui->txtIPCName->setFocus(); return; }
if (NVRName == "") { myHelper::ShowMessageBoxError("NVR名称不能为空,请先添加好NVR!"); return; }
if (IPCRtspAddrMain == "") { myHelper::ShowMessageBoxError("主码流地址不能为空,请重新填写!"); ui->txtIPCRtspAddrMain->setFocus(); return; }
if (IPCRtspAddrSub == "") { myHelper::ShowMessageBoxError("子码流地址不能为空,请重新填写!"); ui->txtIPCRtspAddrSub->setFocus(); return; }
//检测编号是否唯一 if (IsExistIPCID(NVRID, IPCID)) { myHelper::ShowMessageBoxError("编号已经存在,请重新选择!"); return; }
QSqlQuery query; QString sql = "insert into [IPCInfo]("; sql += "[IPCID],[IPCName],[NVRID],[NVRName],"; sql += "[IPCType],[IPCRtspAddrMain],[IPCRtspAddrSub],"; sql += "[IPCUserName],[IPCUserPwd],[IPCUse])"; sql += "values('"; sql += IPCID + "','"; sql += IPCName + "','"; sql += NVRID + "','"; sql += NVRName + "','"; sql += IPCType + "','"; sql += IPCRtspAddrMain + "','"; sql += IPCRtspAddrSub + "','"; sql += IPCUserName + "','"; sql += IPCUserPwd + "','"; sql += IPCUse + "')"; query.exec(sql);
LoadIPCInfo();
ui->cboxIPCID->setCurrentIndex(ui->cboxIPCID->currentIndex() + 1); ui->txtIPCName->setText(QString("摄像机%1").arg(ui->cboxIPCID->currentText()));}
void frmIPC::on_btnDelete_clicked(){ if (ui->tableMain->currentIndex().row() < 0) { myHelper::ShowMessageBoxError("请选择要删除的摄像机!"); return; }
QString tempIPCID = queryModule->record( ui->tableMain->currentIndex().row()) .value(0).toString();
if (myHelper::ShowMessageBoxQuesion("确定要删除摄像机吗?") == 1) { QSqlQuery query; QString sql = "delete from [IPCInfo] where [IPCID]='" + tempIPCID + "'"; query.exec(sql); myHelper::Sleep(100);
//同步删除轮询表中的摄像机信息 sql = "delete from [PollInfo] where [IPCID]='" + tempIPCID + "'"; query.exec(sql); myHelper::Sleep(100);
LoadIPCInfo(); }}
void frmIPC::on_btnUpdate_clicked(){ if (ui->tableMain->currentIndex().row() < 0) { myHelper::ShowMessageBoxError("请选择要修改的摄像机!"); return; }
QString tempIPCID = queryModule->record( ui->tableMain->currentIndex().row()) .value(0).toString();
QString IPCID = ui->cboxIPCID->currentText(); QString IPCName = ui->txtIPCName->text(); QString NVRID = ui->cboxNVRID->currentText(); QString NVRName = ui->cboxNVRName->currentText(); QString IPCType = ui->cboxIPCType->currentText(); QString IPCRtspAddrMain = ui->txtIPCRtspAddrMain->text(); QString IPCRtspAddrSub = ui->txtIPCRtspAddrSub->text(); QString IPCUserName = ui->txtIPCUserName->text(); QString IPCUserPwd = ui->txtIPCUserPwd->text(); QString IPCUse = ui->cboxIPCUse->currentText();
if (IPCID != tempIPCID) { //检测编号是否和已经存在的除自己之外的编号相同 if (IsExistIPCID(NVRID, IPCID)) { myHelper::ShowMessageBoxError("编号已经存在,请重新选择!"); return; } }
QSqlQuery query; QString sql = "update [IPCInfo] set"; sql += " [IPCID]='" + IPCID; sql += "',[IPCName]='" + IPCName; sql += "',[NVRID]='" + NVRID; sql += "',[NVRName]='" + NVRName; sql += "',[IPCType]='" + IPCType; sql += "',[IPCRtspAddrMain]='" + IPCRtspAddrMain; sql += "',[IPCRtspAddrSub]='" + IPCRtspAddrSub; sql += "',[IPCUserName]='" + IPCUserName; sql += "',[IPCUserPwd]='" + IPCUserPwd; sql += "',[IPCUse]='" + IPCUse; sql += "' where [IPCID]='" + tempIPCID + "'"; query.exec(sql); myHelper::Sleep(100);
//同步修改轮询表的信息 sql = "update [PollInfo] set"; sql += " [IPCID]='" + IPCID; sql += "',[IPCName]='" + IPCName; sql += "',[NVRID]='" + NVRID; sql += "',[NVRName]='" + NVRName; sql += "',[IPCRtspAddrMain]='" + IPCRtspAddrMain; sql += "',[IPCRtspAddrSub]='" + IPCRtspAddrSub; sql += "' where [IPCID]='" + tempIPCID + "'"; query.exec(sql); myHelper::Sleep(100);
LoadIPCInfo();
}


5:QTreeView及QTableView数据加载和双击处理。

void frmPollConfig::LoadNVRIPC(){    ui->treeMain->clear();
QSqlQuery queryNVR; QString sqlNVR = "select [NVRID],[NVRName],[NVRIP] from [NVRInfo] where [NVRUse]='启用'"; queryNVR.exec(sqlNVR);
while (queryNVR.next()) { QString tempNVRID = queryNVR.value(0).toString(); QString tempNVRName = queryNVR.value(1).toString(); QString tempNVRIP = queryNVR.value(2).toString();
QTreeWidgetItem *itemNVR = new QTreeWidgetItem (ui->treeMain, QStringList(tempNVRName + "[" + tempNVRIP + "]")); itemNVR->setIcon(0, QIcon(":/image/nvr.png"));
//查询没有添加在轮询表中的摄像机信息 QSqlQuery queryIPC; QString sqlIPC = "select [IPCID],[IPCName],[IPCRtspAddrMain] from [IPCInfo]"; sqlIPC += " where [NVRID]='" + tempNVRID; sqlIPC += "' and [IPCUse]='启用'"; sqlIPC += " order by [IPCID] asc"; queryIPC.exec(sqlIPC);
while (queryIPC.next()) { QString tempIPCID = queryIPC.value(0).toString();
//如果该摄像机已经存在轮询表,则跳过 if (IsExistIPCID(tempIPCID)) { continue; }
QString tempIPCName = queryIPC.value(1).toString(); QString rtspAddr = queryIPC.value(2).toString();
QStringList temp = rtspAddr.split("/"); QString ip = temp[2].split(":")[0];
temp = QStringList(QString(tempIPCName + "[" + ip + "](" + tempIPCID + ")")); QTreeWidgetItem *itemIPC = new QTreeWidgetItem(itemNVR, temp); itemIPC->setIcon(0, QIcon(":/image/ipc_normal.png")); itemNVR->addChild(itemIPC); } } ui->treeMain->expandAll();}

 年底奉献-QT编写视频监管平台

6:16通道画面展示区域处理,自由切换1画面4画面9画面16画面。

void frmMain::show_video_4(){    removelayout();    video_max = false;    int index = 0;
QAction *action = (QAction *)sender(); QString name = action->text(); if (name == "通道1-通道4") { index = 0; myApp::VideoType = "1_4"; } else if (name == "通道5-通道8") { index = 4; myApp::VideoType = "5_8"; } else if (name == "通道9-通道12") { index = 8; myApp::VideoType = "9_12"; } else if (name == "通道13-通道16") { index = 12; myApp::VideoType = "13_16"; }
change_video_4(index); myApp::WriteConfig();}
void frmMain::change_video_4(int index){ for (int i = (index + 0); i < (index + 2); i++) { VideoLay[0]->addWidget(VideoLab[i]); VideoLab[i]->setVisible(true); }
for (int i = (index + 2); i < (index + 4); i++) { VideoLay[1]->addWidget(VideoLab[i]); VideoLab[i]->setVisible(true); }}

年底奉献-QT编写视频监管平台

7:精美开关按钮。

现在流行APP,各种APP上面都带有很精美的开关,参考了360安全卫士以及金山毒霸的开关按钮,用QT也实现了一个,原理很简单,就是贴图。

#include "switchbutton.h"
/* 说明:自定义开关按钮控件实现文件 * 功能:用来控制配置文件的开关设置 * 作者:刘典武 QQ:517216493 * 时间:2013-12-19 检查:2014-1-10 */SwitchButton::SwitchButton(QWidget *parent): QPushButton(parent){ setCursor(QCursor(Qt::PointingHandCursor)); isCheck = false; styleOn = "background-image: url(':/image/btncheckon.png'); border: 0px;"; styleOff = "background-image: url(':/image/btncheckoff.png'); border: 0px;";
setFocusPolicy(Qt::NoFocus); setFixedSize(87, 28); //不允许变化大小 setStyleSheet(styleOff);//设置当前样式 connect(this, SIGNAL(clicked()), this, SLOT(ChangeOnOff()));}
void SwitchButton::ChangeOnOff(){ if (isCheck) { setStyleSheet(styleOff); isCheck = false; } else { setStyleSheet(styleOn); isCheck = true; }}
//设置当前选中状态void SwitchButton::SetCheck(bool isCheck){ if (this->isCheck != isCheck) { this->isCheck = !isCheck; ChangeOnOff(); }}

8:重写过的消息框,错误框,询问框及输入框。

本人不喜欢系统的MessageBox,用QDialog重新布局自定义了一个。只需一句话调用即可。

年底奉献-QT编写视频监管平台 

年底奉献-QT编写视频监管平台 

年底奉献-QT编写视频监管平台 

在win7下运行截图如下:

年底奉献-QT编写视频监管平台在XP下运行截图如下:

年底奉献-QT编写视频监管平台在ubuntu上运行截图:

 年底奉献-QT编写视频监管平台

可执行文件下载:http://pan.baidu.com/s/1hqxhtbA

源码下载:http://pan.baidu.com/s/1mgFWeDU

编译运行后如果提示缺少数据库。将源码下的file文件夹下的配置文件config.txt及VM.db数据库文件复制到bin目录下即可。 

说明:公开的源码去除了视频处理部分及样式部分,其余功能全部保留,并可完整编译运行。欢迎提出建议共同学习进步!


原文始发于微信公众号(汇编语言):年底奉献-QT编写视频监管平台

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月2日07:34:40
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   年底奉献-QT编写视频监管平台https://cn-sec.com/archives/1330203.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息