diff --git a/README.md b/README.md index 1782df8..391acfa 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ | 27 | emailtool | 邮件发送工具 | | 28 | ntpclient | NTP服务器时间同步 | | 29 | lunarcalendarwidget | 农历控件 | +| 30 | videowidget | 通用视频控件 | ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/snap/lightbutton.gif) ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/snap/movewidget.gif) @@ -59,4 +60,5 @@ ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/snap/mouseline.gif) ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/snap/emailtool.gif) ![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/snap/ntpclient.gif) -![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/snap/lunarcalendarwidget.gif) \ No newline at end of file +![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/snap/lunarcalendarwidget.gif) +![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/snap/videowidget.gif) \ No newline at end of file diff --git a/snap/videowidget.gif b/snap/videowidget.gif new file mode 100644 index 0000000..be5609f Binary files /dev/null and b/snap/videowidget.gif differ diff --git a/videowidget/frmvideowidget.cpp b/videowidget/frmvideowidget.cpp new file mode 100644 index 0000000..f4fc519 --- /dev/null +++ b/videowidget/frmvideowidget.cpp @@ -0,0 +1,35 @@ +#pragma execution_character_set("utf-8") + +#include "frmvideowidget.h" +#include "ui_frmvideowidget.h" + +frmVideoWidget::frmVideoWidget(QWidget *parent) : QWidget(parent), ui(new Ui::frmVideoWidget) +{ + ui->setupUi(this); + this->initForm(); +} + +frmVideoWidget::~frmVideoWidget() +{ + delete ui; +} + +void frmVideoWidget::initForm() +{ + ui->videoWidget1->setFlowEnable(true); + ui->videoWidget2->setFlowEnable(true); + ui->videoWidget3->setFlowEnable(true); + ui->videoWidget4->setFlowEnable(true); + + connect(ui->videoWidget1, SIGNAL(btnClicked(QString)), this, SLOT(btnClicked(QString))); + connect(ui->videoWidget2, SIGNAL(btnClicked(QString)), this, SLOT(btnClicked(QString))); + connect(ui->videoWidget3, SIGNAL(btnClicked(QString)), this, SLOT(btnClicked(QString))); + connect(ui->videoWidget4, SIGNAL(btnClicked(QString)), this, SLOT(btnClicked(QString))); +} + +void frmVideoWidget::btnClicked(const QString &objName) +{ + VideoWidget *videoWidget = (VideoWidget *)sender(); + QString str = QString("当前单击了控件 %1 的按钮 %2").arg(videoWidget->objectName()).arg(objName); + ui->label->setText(str); +} diff --git a/videowidget/frmvideowidget.h b/videowidget/frmvideowidget.h new file mode 100644 index 0000000..c12a88a --- /dev/null +++ b/videowidget/frmvideowidget.h @@ -0,0 +1,26 @@ +#ifndef FRMVIDEOWIDGET_H +#define FRMVIDEOWIDGET_H + +#include + +namespace Ui { +class frmVideoWidget; +} + +class frmVideoWidget : public QWidget +{ + Q_OBJECT + +public: + explicit frmVideoWidget(QWidget *parent = 0); + ~frmVideoWidget(); + +private: + Ui::frmVideoWidget *ui; + +private slots: + void initForm(); + void btnClicked(const QString &objName); +}; + +#endif // FRMVIDEOWIDGET_H diff --git a/videowidget/frmvideowidget.ui b/videowidget/frmvideowidget.ui new file mode 100644 index 0000000..014ea15 --- /dev/null +++ b/videowidget/frmvideowidget.ui @@ -0,0 +1,85 @@ + + + frmVideoWidget + + + + 0 + 0 + 500 + 300 + + + + Form + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + QFrame::Box + + + QFrame::Sunken + + + + + + Qt::AlignCenter + + + + + + + + VideoWidget + QWidget +
videowidget.h
+ 1 +
+
+ + +
diff --git a/videowidget/main.cpp b/videowidget/main.cpp new file mode 100644 index 0000000..8b7d649 --- /dev/null +++ b/videowidget/main.cpp @@ -0,0 +1,32 @@ +#pragma execution_character_set("utf-8") + +#include "frmvideowidget.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.setFont(QFont("Microsoft Yahei", 9)); + +#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmVideoWidget w; + w.setWindowTitle("视频监控控件"); + w.resize(800, 600); + w.show(); + + return a.exec(); +} diff --git a/videowidget/videowidget.cpp b/videowidget/videowidget.cpp new file mode 100644 index 0000000..039fc13 --- /dev/null +++ b/videowidget/videowidget.cpp @@ -0,0 +1,788 @@ +#pragma execution_character_set("utf-8") + +#include "videowidget.h" +#include "qfontdatabase.h" +#include "qpushbutton.h" +#include "qtreewidget.h" +#include "qlayout.h" +#include "qtimer.h" +#include "qdir.h" +#include "qpainter.h" +#include "qevent.h" +#include "qmimedata.h" +#include "qurl.h" +#include "qdebug.h" + +VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) +{ + //设置强焦点 + setFocusPolicy(Qt::StrongFocus); + //设置支持拖放 + setAcceptDrops(true); + + timerCheck = new QTimer(this); + timerCheck->setInterval(10 * 1000); + connect(timerCheck, SIGNAL(timeout()), this, SLOT(checkVideo())); + + image = QImage(); + + //顶部工具栏,默认隐藏,鼠标移入显示移除隐藏 + flowPanel = new QWidget(this); + flowPanel->setObjectName("flowPanel"); + flowPanel->setVisible(false); + + //用布局顶住,左侧弹簧 + QHBoxLayout *layout = new QHBoxLayout; + layout->setSpacing(2); + layout->setMargin(0); + layout->addStretch(); + flowPanel->setLayout(layout); + + //按钮集合名称,如果需要新增按钮则在这里增加即可 + QList btns; + btns << "btnFlowVideo" << "btnFlowSnap" << "btnFlowSound" << "btnFlowAlarm" << "btnFlowClose"; + + //有多种办法来设置图片,qt内置的图标+自定义的图标+图形字体 + //既可以设置图标形式,也可以直接图形字体设置文本 +#if 0 + QList icons; + icons << QApplication::style()->standardIcon(QStyle::SP_ComputerIcon); + icons << QApplication::style()->standardIcon(QStyle::SP_FileIcon); + icons << QApplication::style()->standardIcon(QStyle::SP_DirIcon); + icons << QApplication::style()->standardIcon(QStyle::SP_DialogOkButton); + icons << QApplication::style()->standardIcon(QStyle::SP_DialogCancelButton); +#else + QList chars; + chars << 0xe68d << 0xe672 << 0xe674 << 0xea36 << 0xe74c; + + //判断图形字体是否存在,不存在则加入 + QFont iconFont; + QFontDatabase fontDb; + if (!fontDb.families().contains("iconfont")) { + int fontId = fontDb.addApplicationFont(":/image/iconfont.ttf"); + QStringList fontName = fontDb.applicationFontFamilies(fontId); + if (fontName.count() == 0) { + qDebug() << "load iconfont.ttf error"; + } + } + + if (fontDb.families().contains("iconfont")) { + iconFont = QFont("iconfont"); + iconFont.setPixelSize(17); +#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0)) + iconFont.setHintingPreference(QFont::PreferNoHinting); +#endif + } +#endif + + //循环添加顶部按钮 + for (int i = 0; i < btns.count(); i++) { + QPushButton *btn = new QPushButton; + //绑定按钮单击事件,用来发出信号通知 + connect(btn, SIGNAL(clicked(bool)), this, SLOT(btnClicked())); + //设置标识,用来区别按钮 + btn->setObjectName(btns.at(i)); + //设置固定宽度 + btn->setFixedWidth(20); + //设置拉伸策略使得填充 + btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + //设置焦点策略为无焦点,避免单击后焦点跑到按钮上 + btn->setFocusPolicy(Qt::NoFocus); + +#if 0 + //设置图标大小和图标 + btn->setIconSize(QSize(16, 16)); + btn->setIcon(icons.at(i)); +#else + btn->setFont(iconFont); + btn->setText(chars.at(i)); +#endif + + //将按钮加到布局中 + layout->addWidget(btn); + } + + copyImage = false; + checkLive = true; + drawImage = true; + fillImage = true; + + flowEnable = false; + flowBgColor = "#000000"; + flowPressColor = "#5EC7D9"; + + timeout = 20; + borderWidth = 5; + borderColor = "#000000"; + focusColor = "#22A3A9"; + bgText = "实时视频"; + bgImage = QImage(); + + osd1Visible = false; + osd1FontSize = 12; + osd1Text = "时间"; + osd1Color = "#FF0000"; + osd1Image = QImage(); + osd1Format = OSDFormat_DateTime; + osd1Position = OSDPosition_Right_Top; + + osd2Visible = false; + osd2FontSize = 12; + osd2Text = "通道名称"; + osd2Color = "#FF0000"; + osd2Image = QImage(); + osd2Format = OSDFormat_Text; + osd2Position = OSDPosition_Left_Bottom; + + this->initFlowStyle(); +} + +VideoWidget::~VideoWidget() +{ + if (timerCheck->isActive()) { + timerCheck->stop(); + } + + close(); +} + +void VideoWidget::resizeEvent(QResizeEvent *) +{ + //重新设置顶部工具栏的位置和宽高,可以自行设置顶部显示或者底部显示 + int height = 20; + flowPanel->setGeometry(borderWidth, borderWidth, this->width() - (borderWidth * 2), height); + //flowPanel->setGeometry(borderWidth, this->height() - height - borderWidth, this->width() - (borderWidth * 2), height); +} + +void VideoWidget::enterEvent(QEvent *) +{ + //这里还可以增加一个判断,是否获取了焦点的才需要显示 + //if (this->hasFocus()) {} + if (flowEnable) { + flowPanel->setVisible(true); + } +} + +void VideoWidget::leaveEvent(QEvent *) +{ + if (flowEnable) { + flowPanel->setVisible(false); + } +} + +void VideoWidget::dropEvent(QDropEvent *event) +{ + //拖放完毕鼠标松开的时候执行 + //判断拖放进来的类型,取出文件,进行播放 + if(event->mimeData()->hasUrls()) { + QString url = event->mimeData()->urls().first().toLocalFile(); + this->close(); + this->setUrl(url); + this->open(); + emit fileDrag(url); + } else if (event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist")) { + QTreeWidget *treeWidget = (QTreeWidget *)event->source(); + if (treeWidget != 0) { + QString url = treeWidget->currentItem()->data(0, Qt::UserRole).toString(); + this->close(); + this->setUrl(url); + this->open(); + emit fileDrag(url); + } + } +} + +void VideoWidget::dragEnterEvent(QDragEnterEvent *event) +{ + //拖曳进来的时候先判断下类型,非法类型则不处理 + if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist")) { + event->setDropAction(Qt::CopyAction); + event->accept(); + } else if(event->mimeData()->hasFormat("text/uri-list")) { + event->setDropAction(Qt::LinkAction); + event->accept(); + } else { + event->ignore(); + } +} + +void VideoWidget::paintEvent(QPaintEvent *) +{ + //如果不需要绘制 + if (!drawImage) { + return; + } + + //qDebug() << TIMEMS << "paintEvent" << objectName(); + QPainter painter(this); + painter.setRenderHints(QPainter::Antialiasing); + + //绘制边框 + drawBorder(&painter); + + if (!image.isNull()) { + //绘制背景图片 + drawImg(&painter, image); + + //绘制标签1 + if (osd1Visible) { + drawOSD(&painter, osd1FontSize, osd1Text, osd1Color, osd1Image, osd1Format, osd1Position); + } + + //绘制标签2 + if (osd2Visible) { + drawOSD(&painter, osd2FontSize, osd2Text, osd2Color, osd2Image, osd2Format, osd2Position); + } + } else { + //绘制背景 + drawBg(&painter); + } +} + +void VideoWidget::drawBorder(QPainter *painter) +{ + painter->save(); + QPen pen; + pen.setWidth(borderWidth); + pen.setColor(hasFocus() ? focusColor : borderColor); + painter->setPen(pen); + painter->drawRect(rect()); + painter->restore(); +} + +void VideoWidget::drawBg(QPainter *painter) +{ + painter->save(); + + //背景图片为空则绘制文字,否则绘制背景图片 + if (bgImage.isNull()) { + painter->setPen(palette().foreground().color()); + painter->drawText(rect(), Qt::AlignCenter, bgText); + } else { + //居中绘制 + int pixX = rect().center().x() - bgImage.width() / 2; + int pixY = rect().center().y() - bgImage.height() / 2; + QPoint point(pixX, pixY); + painter->drawImage(point, bgImage); + } + + painter->restore(); +} + +void VideoWidget::drawImg(QPainter *painter, QImage img) +{ + painter->save(); + + int offset = borderWidth * 1 + 0; + if (fillImage) { + QRect rect(offset / 2, offset / 2, width() - offset, height() - offset); + painter->drawImage(rect, img); + } else { + //按照比例自动居中绘制 + img = img.scaled(width() - offset, height() - offset, Qt::KeepAspectRatio); + int pixX = rect().center().x() - img.width() / 2; + int pixY = rect().center().y() - img.height() / 2; + QPoint point(pixX, pixY); + painter->drawImage(point, img); + } + + painter->restore(); +} + +void VideoWidget::drawOSD(QPainter *painter, + int osdFontSize, + const QString &osdText, + const QColor &osdColor, + const QImage &osdImage, + const VideoWidget::OSDFormat &osdFormat, + const VideoWidget::OSDPosition &osdPosition) +{ + painter->save(); + + //标签位置尽量偏移多一点避免遮挡 + QRect osdRect(rect().x() + (borderWidth * 2), rect().y() + (borderWidth * 2), width() - (borderWidth * 5), height() - (borderWidth * 5)); + int flag = Qt::AlignLeft | Qt::AlignTop; + QPoint point = QPoint(osdRect.x(), osdRect.y()); + + if (osdPosition == OSDPosition_Left_Top) { + flag = Qt::AlignLeft | Qt::AlignTop; + point = QPoint(osdRect.x(), osdRect.y()); + } else if (osdPosition == OSDPosition_Left_Bottom) { + flag = Qt::AlignLeft | Qt::AlignBottom; + point = QPoint(osdRect.x(), osdRect.height() - osdImage.height()); + } else if (osdPosition == OSDPosition_Right_Top) { + flag = Qt::AlignRight | Qt::AlignTop; + point = QPoint(osdRect.width() - osdImage.width(), osdRect.y()); + } else if (osdPosition == OSDPosition_Right_Bottom) { + flag = Qt::AlignRight | Qt::AlignBottom; + point = QPoint(osdRect.width() - osdImage.width(), osdRect.height() - osdImage.height()); + } + + if (osdFormat == OSDFormat_Image) { + painter->drawImage(point, osdImage); + } else { + QDateTime now = QDateTime::currentDateTime(); + QString text = osdText; + if (osdFormat == OSDFormat_Date) { + text = now.toString("yyyy-MM-dd"); + } else if (osdFormat == OSDFormat_Time) { + text = now.toString("HH:mm:ss"); + } else if (osdFormat == OSDFormat_DateTime) { + text = now.toString("yyyy-MM-dd HH:mm:ss"); + } + + //设置颜色及字号 + QFont font; + font.setPixelSize(osdFontSize); + painter->setPen(osdColor); + painter->setFont(font); + + painter->drawText(osdRect, flag, text); + } + + painter->restore(); +} + +QImage VideoWidget::getImage() const +{ + return this->image; +} + +QDateTime VideoWidget::getLastTime() const +{ + return QDateTime::currentDateTime(); +} + +QString VideoWidget::getUrl() const +{ + return this->property("url").toString(); +} + +bool VideoWidget::getCopyImage() const +{ + return this->copyImage; +} + +bool VideoWidget::getCheckLive() const +{ + return this->checkLive; +} + +bool VideoWidget::getDrawImage() const +{ + return this->drawImage; +} + +bool VideoWidget::getFillImage() const +{ + return this->fillImage; +} + +bool VideoWidget::getFlowEnable() const +{ + return this->flowEnable; +} + +QColor VideoWidget::getFlowBgColor() const +{ + return this->flowBgColor; +} + +QColor VideoWidget::getFlowPressColor() const +{ + return this->flowPressColor; +} + +int VideoWidget::getTimeout() const +{ + return this->timeout; +} + +int VideoWidget::getBorderWidth() const +{ + return this->borderWidth; +} + +QColor VideoWidget::getBorderColor() const +{ + return this->borderColor; +} + +QColor VideoWidget::getFocusColor() const +{ + return this->focusColor; +} + +QString VideoWidget::getBgText() const +{ + return this->bgText; +} + +QImage VideoWidget::getBgImage() const +{ + return this->bgImage; +} + +bool VideoWidget::getOSD1Visible() const +{ + return this->osd1Visible; +} + +int VideoWidget::getOSD1FontSize() const +{ + return this->osd1FontSize; +} + +QString VideoWidget::getOSD1Text() const +{ + return this->osd1Text; +} + +QColor VideoWidget::getOSD1Color() const +{ + return this->osd1Color; +} + +QImage VideoWidget::getOSD1Image() const +{ + return this->osd1Image; +} + +VideoWidget::OSDFormat VideoWidget::getOSD1Format() const +{ + return this->osd1Format; +} + +VideoWidget::OSDPosition VideoWidget::getOSD1Position() const +{ + return this->osd1Position; +} + +bool VideoWidget::getOSD2Visible() const +{ + return this->osd2Visible; +} + +int VideoWidget::getOSD2FontSize() const +{ + return this->osd2FontSize; +} + +QString VideoWidget::getOSD2Text() const +{ + return this->osd2Text; +} + +QColor VideoWidget::getOSD2Color() const +{ + return this->osd2Color; +} + +QImage VideoWidget::getOSD2Image() const +{ + return this->osd2Image; +} + +VideoWidget::OSDFormat VideoWidget::getOSD2Format() const +{ + return this->osd2Format; +} + +VideoWidget::OSDPosition VideoWidget::getOSD2Position() const +{ + return this->osd2Position; +} + +QSize VideoWidget::sizeHint() const +{ + return QSize(500, 350); +} + +QSize VideoWidget::minimumSizeHint() const +{ + return QSize(50, 35); +} + +void VideoWidget::initFlowStyle() +{ + //设置样式以便区分,可以自行更改样式,也可以不用样式 + QStringList qss; + QString rgba = QString("rgba(%1,%2,%3,150)").arg(flowBgColor.red()).arg(flowBgColor.green()).arg(flowBgColor.blue()); + qss.append(QString("#flowPanel{background:%1;border:none;}").arg(rgba)); + qss.append(QString("QPushButton{border:none;padding:0px;background:rgba(0,0,0,0);}")); + qss.append(QString("QPushButton:pressed{color:%1;}").arg(flowPressColor.name())); + flowPanel->setStyleSheet(qss.join("")); +} + +void VideoWidget::updateImage(const QImage &image) +{ + //拷贝图片有个好处,当处理器比较差的时候,图片不会产生断层,缺点是占用时间 + //默认QImage类型是浅拷贝,可能正在绘制的时候,那边已经更改了图片的上部分数据 + this->image = copyImage ? image.copy() : image; + this->update(); +} + +void VideoWidget::checkVideo() +{ + QDateTime now = QDateTime::currentDateTime(); + QDateTime lastTime = now; + int sec = lastTime.secsTo(now); + if (sec >= timeout) { + restart(); + } +} + +void VideoWidget::btnClicked() +{ + QPushButton *btn = (QPushButton *)sender(); + emit btnClicked(btn->objectName()); +} + +void VideoWidget::setInterval(int interval) +{ + +} + +void VideoWidget::setSleepTime(int sleepTime) +{ + +} + +void VideoWidget::setCheckTime(int checkTime) +{ + +} + +void VideoWidget::setCheckConn(bool checkConn) +{ + +} + +void VideoWidget::setUrl(const QString &url) +{ + this->setProperty("url", url); +} + +void VideoWidget::setHardware(const QString &hardware) +{ + +} + +void VideoWidget::setSaveFile(bool saveFile) +{ + +} + +void VideoWidget::setSaveInterval(int saveInterval) +{ + +} + +void VideoWidget::setSavePath(const QString &savePath) +{ + //如果目录不存在则新建 + QDir dir(savePath); + if (!dir.exists()) { + dir.mkdir(savePath); + } + + +} + +void VideoWidget::setFileName(const QString &fileName) +{ + +} + +void VideoWidget::setCopyImage(bool copyImage) +{ + this->copyImage = copyImage; +} + +void VideoWidget::setCheckLive(bool checkLive) +{ + this->checkLive = checkLive; +} + +void VideoWidget::setDrawImage(bool drawImage) +{ + this->drawImage = drawImage; +} + +void VideoWidget::setFillImage(bool fillImage) +{ + this->fillImage = fillImage; +} + +void VideoWidget::setFlowEnable(bool flowEnable) +{ + this->flowEnable = flowEnable; +} + +void VideoWidget::setFlowBgColor(const QColor &flowBgColor) +{ + if (this->flowBgColor != flowBgColor) { + this->flowBgColor = flowBgColor; + this->initFlowStyle(); + } +} + +void VideoWidget::setFlowPressColor(const QColor &flowPressColor) +{ + if (this->flowPressColor != flowPressColor) { + this->flowPressColor = flowPressColor; + this->initFlowStyle(); + } +} + +void VideoWidget::setTimeout(int timeout) +{ + this->timeout = timeout; +} + +void VideoWidget::setBorderWidth(int borderWidth) +{ + this->borderWidth = borderWidth; +} + +void VideoWidget::setBorderColor(const QColor &borderColor) +{ + this->borderColor = borderColor; +} + +void VideoWidget::setFocusColor(const QColor &focusColor) +{ + this->focusColor = focusColor; +} + +void VideoWidget::setBgText(const QString &bgText) +{ + this->bgText = bgText; +} + +void VideoWidget::setBgImage(const QImage &bgImage) +{ + this->bgImage = bgImage; +} + +void VideoWidget::setOSD1Visible(bool osdVisible) +{ + this->osd1Visible = osdVisible; +} + +void VideoWidget::setOSD1FontSize(int osdFontSize) +{ + this->osd1FontSize = osdFontSize; +} + +void VideoWidget::setOSD1Text(const QString &osdText) +{ + this->osd1Text = osdText; +} + +void VideoWidget::setOSD1Color(const QColor &osdColor) +{ + this->osd1Color = osdColor; +} + +void VideoWidget::setOSD1Image(const QImage &osdImage) +{ + this->osd1Image = osdImage; +} + +void VideoWidget::setOSD1Format(const VideoWidget::OSDFormat &osdFormat) +{ + this->osd1Format = osdFormat; +} + +void VideoWidget::setOSD1Position(const VideoWidget::OSDPosition &osdPosition) +{ + this->osd1Position = osdPosition; +} + +void VideoWidget::setOSD2Visible(bool osdVisible) +{ + this->osd2Visible = osdVisible; +} + +void VideoWidget::setOSD2FontSize(int osdFontSize) +{ + this->osd2FontSize = osdFontSize; +} + +void VideoWidget::setOSD2Text(const QString &osdText) +{ + this->osd2Text = osdText; +} + +void VideoWidget::setOSD2Color(const QColor &osdColor) +{ + this->osd2Color = osdColor; +} + +void VideoWidget::setOSD2Image(const QImage &osdImage) +{ + this->osd2Image = osdImage; +} + +void VideoWidget::setOSD2Format(const VideoWidget::OSDFormat &osdFormat) +{ + this->osd2Format = osdFormat; +} + +void VideoWidget::setOSD2Position(const VideoWidget::OSDPosition &osdPosition) +{ + this->osd2Position = osdPosition; +} + +void VideoWidget::open() +{ + //qDebug() << TIMEMS << "open video" << objectName(); + clear(); + + //如果是图片则只显示图片就行 + image = QImage(this->property("url").toString()); + if (!image.isNull()) { + this->update(); + return; + } + + + + if (checkLive) { + timerCheck->start(); + } +} + +void VideoWidget::pause() +{ + +} + +void VideoWidget::next() +{ + +} + +void VideoWidget::close() +{ + if (checkLive) { + timerCheck->stop(); + } + + QTimer::singleShot(1, this, SLOT(clear())); +} + +void VideoWidget::restart() +{ + //qDebug() << TIMEMS << "restart video" << objectName(); + close(); + QTimer::singleShot(10, this, SLOT(open())); +} + +void VideoWidget::clear() +{ + image = QImage(); + this->update(); +} + diff --git a/videowidget/videowidget.h b/videowidget/videowidget.h new file mode 100644 index 0000000..e7296dd --- /dev/null +++ b/videowidget/videowidget.h @@ -0,0 +1,314 @@ +#ifndef VIDEOWIDGET_H +#define VIDEOWIDGET_H + +/** + * 通用视频播放控件 作者:feiyangqingyun(QQ:517216493) 2018-5-1 + * 1:可设置边框大小 + * 2:可设置边框颜色 + * 3:可设置两路OSD标签 + * 4:可设置是否绘制OSD标签 + * 5:可设置标签文本或图片 + * 6:可设置OSD位置 左上角+左下角+右上角+右下角 + * 7:可设置OSD风格 文本+日期+时间+日期时间+图片 + * 8:自定义半透明悬浮窗体,一排按钮 + * 9:悬浮按钮可自定义设置,包括背景颜色+按下颜色 + * 10:发送信号通知单击了哪个悬浮按钮 + * 11:能够识别拖进来的文件,通知url + * 12:提供open close pause等接口 + */ + +#include +#include + +class QTimer; + +#ifdef quc +#if (QT_VERSION < QT_VERSION_CHECK(5,7,0)) +#include +#else +#include +#endif + +class QDESIGNER_WIDGET_EXPORT VideoWidget : public QWidget +#else +class VideoWidget : public QWidget +#endif + +{ + Q_OBJECT + Q_ENUMS(OSDFormat) + Q_ENUMS(OSDPosition) + + Q_PROPERTY(bool copyImage READ getCopyImage WRITE setCopyImage) + Q_PROPERTY(bool checkLive READ getCheckLive WRITE setCheckLive) + Q_PROPERTY(bool drawImage READ getDrawImage WRITE setDrawImage) + Q_PROPERTY(bool fillImage READ getFillImage WRITE setFillImage) + + Q_PROPERTY(bool flowEnable READ getFlowEnable WRITE setFlowEnable) + Q_PROPERTY(QColor flowBgColor READ getFlowBgColor WRITE setFlowBgColor) + Q_PROPERTY(QColor flowPressColor READ getFlowPressColor WRITE setFlowPressColor) + + Q_PROPERTY(int timeout READ getTimeout WRITE setTimeout) + Q_PROPERTY(int borderWidth READ getBorderWidth WRITE setBorderWidth) + Q_PROPERTY(QColor borderColor READ getBorderColor WRITE setBorderColor) + Q_PROPERTY(QColor focusColor READ getFocusColor WRITE setFocusColor) + Q_PROPERTY(QString bgText READ getBgText WRITE setBgText) + Q_PROPERTY(QImage bgImage READ getBgImage WRITE setBgImage) + + Q_PROPERTY(bool osd1Visible READ getOSD1Visible WRITE setOSD1Visible) + Q_PROPERTY(int osd1FontSize READ getOSD1FontSize WRITE setOSD1FontSize) + Q_PROPERTY(QString osd1Text READ getOSD1Text WRITE setOSD1Text) + Q_PROPERTY(QColor osd1Color READ getOSD1Color WRITE setOSD1Color) + Q_PROPERTY(QImage osd1Image READ getOSD1Image WRITE setOSD1Image) + Q_PROPERTY(OSDFormat osd1Format READ getOSD1Format WRITE setOSD1Format) + Q_PROPERTY(OSDPosition osd1Position READ getOSD1Position WRITE setOSD1Position) + + Q_PROPERTY(bool osd2Visible READ getOSD2Visible WRITE setOSD2Visible) + Q_PROPERTY(int osd2FontSize READ getOSD2FontSize WRITE setOSD2FontSize) + Q_PROPERTY(QString osd2Text READ getOSD2Text WRITE setOSD2Text) + Q_PROPERTY(QColor osd2Color READ getOSD2Color WRITE setOSD2Color) + Q_PROPERTY(QImage osd2Image READ getOSD2Image WRITE setOSD2Image) + Q_PROPERTY(OSDFormat osd2Format READ getOSD2Format WRITE setOSD2Format) + Q_PROPERTY(OSDPosition osd2Position READ getOSD2Position WRITE setOSD2Position) + +public: + //标签格式 + enum OSDFormat { + OSDFormat_Text = 0, //文本 + OSDFormat_Date = 1, //日期 + OSDFormat_Time = 2, //时间 + OSDFormat_DateTime = 3, //日期时间 + OSDFormat_Image = 4 //图片 + }; + + //标签位置 + enum OSDPosition { + OSDPosition_Left_Top = 0, //左上角 + OSDPosition_Left_Bottom = 1, //左下角 + OSDPosition_Right_Top = 2, //右上角 + OSDPosition_Right_Bottom = 3 //右下角 + }; + + explicit VideoWidget(QWidget *parent = 0); + ~VideoWidget(); + +protected: + void resizeEvent(QResizeEvent *); + void enterEvent(QEvent *); + void leaveEvent(QEvent *); + void dropEvent(QDropEvent *event); + void dragEnterEvent(QDragEnterEvent *event); + void paintEvent(QPaintEvent *); + void drawBorder(QPainter *painter); + void drawBg(QPainter *painter); + void drawImg(QPainter *painter, QImage img); + void drawOSD(QPainter *painter, + int osdFontSize, + const QString &osdText, + const QColor &osdColor, + const QImage &osdImage, + const OSDFormat &osdFormat, + const OSDPosition &osdPosition); + +private: + QTimer *timerCheck; //定时器检查设备是否在线 + QImage image; //要显示的图片 + QWidget *flowPanel; //悬浮条面板 + + bool copyImage; //是否拷贝图片 + bool checkLive; //检测是否活着 + bool drawImage; //是否绘制图片 + bool fillImage; //自动拉伸填充 + + bool flowEnable; //是否显示悬浮条 + QColor flowBgColor; //悬浮条背景颜色 + QColor flowPressColor; //悬浮条按下颜色 + + int timeout; //超时时间 + int borderWidth; //边框宽度 + QColor borderColor; //边框颜色 + QColor focusColor; //有焦点边框颜色 + QString bgText; //默认无图像显示文字 + QImage bgImage; //默认无图像背景图片 + + bool osd1Visible; //显示标签1 + int osd1FontSize; //标签1字号 + QString osd1Text; //标签1文本 + QColor osd1Color; //标签1颜色 + QImage osd1Image; //标签1图片 + OSDFormat osd1Format; //标签1文本格式 + OSDPosition osd1Position; //标签1位置 + + bool osd2Visible; //显示标签2 + int osd2FontSize; //标签2字号 + QString osd2Text; //标签2文本 + QColor osd2Color; //标签2颜色 + QImage osd2Image; //标签2图片 + OSDFormat osd2Format; //标签2文本格式 + OSDPosition osd2Position; //标签2位置 + +public: + QImage getImage() const; + QDateTime getLastTime() const; + QString getUrl() const; + + bool getCopyImage() const; + bool getCheckLive() const; + bool getDrawImage() const; + bool getFillImage() const; + + bool getFlowEnable() const; + QColor getFlowBgColor() const; + QColor getFlowPressColor() const; + + int getTimeout() const; + int getBorderWidth() const; + QColor getBorderColor() const; + QColor getFocusColor() const; + QString getBgText() const; + QImage getBgImage() const; + + bool getOSD1Visible() const; + int getOSD1FontSize() const; + QString getOSD1Text() const; + QColor getOSD1Color() const; + QImage getOSD1Image() const; + OSDFormat getOSD1Format() const; + OSDPosition getOSD1Position() const; + + bool getOSD2Visible() const; + int getOSD2FontSize() const; + QString getOSD2Text() const; + QColor getOSD2Color() const; + QImage getOSD2Image() const; + OSDFormat getOSD2Format() const; + OSDPosition getOSD2Position() const; + + QSize sizeHint() const; + QSize minimumSizeHint() const; + +private slots: + //初始化悬浮条样式 + void initFlowStyle(); + //接收图像并绘制 + void updateImage(const QImage &image); + //校验设备 + void checkVideo(); + //处理按钮单击 + void btnClicked(); + +signals: + //播放成功 + void receivePlayOk(); + //播放失败 + void receivePlayError(); + //播放结束 + void receivePlayFinsh(); + + //收到图片信号 + void receiveImage(const QImage &image); + + //接收到拖曳文件 + void fileDrag(const QString &url); + + //工具栏单击 + void btnClicked(const QString &objName); + +public slots: + //设置显示间隔 + void setInterval(int interval); + //设置休眠时间 + void setSleepTime(int sleepTime); + //设置检测连接超时 + void setCheckTime(int checkTime); + //设置是否检测连接 + void setCheckConn(bool checkConn); + //设置视频流地址 + void setUrl(const QString &url); + //设置硬件解码器名称 + void setHardware(const QString &hardware); + + //设置是否保存文件 + void setSaveFile(bool saveFile); + //设置保存间隔 + void setSaveInterval(int saveInterval); + //设置保存文件夹 + void setSavePath(const QString &savePath); + //设置保存文件名称 + void setFileName(const QString &fileName); + + //设置是否拷贝图片 + void setCopyImage(bool copyImage); + //设置是否检测活着 + void setCheckLive(bool checkLive); + //设置是否实时绘制图片 + void setDrawImage(bool drawImage); + //设置是否拉伸填充 + void setFillImage(bool fillImage); + + //设置是否启用悬浮条 + void setFlowEnable(bool flowEnable); + //设置悬浮条背景颜色 + void setFlowBgColor(const QColor &flowBgColor); + //设置悬浮条按下颜色 + void setFlowPressColor(const QColor &flowPressColor); + + //设置超时时间 + void setTimeout(int timeout); + //设置边框宽度 + void setBorderWidth(int borderWidth); + //设置边框颜色 + void setBorderColor(const QColor &borderColor); + //设置有焦点边框颜色 + void setFocusColor(const QColor &focusColor); + //设置无图像文字 + void setBgText(const QString &bgText); + //设置无图像背景图 + void setBgImage(const QImage &bgImage); + + //设置标签1是否可见 + void setOSD1Visible(bool osdVisible); + //设置标签1文字字号 + void setOSD1FontSize(int osdFontSize); + //设置标签1文本 + void setOSD1Text(const QString &osdText); + //设置标签1文字颜色 + void setOSD1Color(const QColor &osdColor); + //设置标签1图片 + void setOSD1Image(const QImage &osdImage); + //设置标签1格式 + void setOSD1Format(const OSDFormat &osdFormat); + //设置标签1位置 + void setOSD1Position(const OSDPosition &osdPosition); + + //设置标签2是否可见 + void setOSD2Visible(bool osdVisible); + //设置标签2文字字号 + void setOSD2FontSize(int osdFontSize); + //设置标签2文本 + void setOSD2Text(const QString &osdText); + //设置标签2文字颜色 + void setOSD2Color(const QColor &osdColor); + //设置标签2图片 + void setOSD2Image(const QImage &osdImage); + //设置标签2格式 + void setOSD2Format(const OSDFormat &osdFormat); + //设置标签2位置 + void setOSD2Position(const OSDPosition &osdPosition); + + //打开设备 + void open(); + //暂停 + void pause(); + //继续 + void next(); + //关闭设备 + void close(); + //重新加载 + void restart(); + //清空 + void clear(); + +}; + +#endif // VIDEOWIDGET_H diff --git a/videowidget/videowidget.pro b/videowidget/videowidget.pro new file mode 100644 index 0000000..832e77b --- /dev/null +++ b/videowidget/videowidget.pro @@ -0,0 +1,23 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2017-01-05T22:11:54 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = videowidget +TEMPLATE = app +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmvideowidget.cpp +SOURCES += videowidget.cpp + +HEADERS += frmvideowidget.h +HEADERS += videowidget.h + +FORMS += frmvideowidget.ui