前言
本人在做一个视频监控项目时,遇到了透明窗口无法透明的问题,特记录下解决过程。
更新:经测试,本文提到的方法用于多分屏复杂的视频播放窗口时有问题。
目录
一、需求
在视频播放界面上,叠加一个透明窗口,实现拉框局部放大功能。
本来以为这个很简单,直接给窗口加一个透明设置项就行,但最终发现,在未播放视频时,窗口确实是透明的,但是当开始播放视频后,窗口就不透明了,特此记录下本人最终的解决办法。
先看下效果图:
二、关键代码
2.1、透明窗口设置
2.1.1、构造函数中调用以下代码
setAttribute(Qt::WA_TranslucentBackground, true);
setWindowFlags(Qt::SplashScreen|Qt::FramelessWindowHint);
第一行,使透明背景生效,透明背景在paintEvent中设置;
第二行,Qt::SplashScreen,启动画面,原本使用的Qt::ToolTip标签,但是这个会导致窗口一直置顶,所以换成了Qt::SplashScreen。Qt::FramelessWindowHint让窗口无边框,窗口如果是其它控件的子控件,这句也可以不要;
2.1.2、重载paintEvent事件
void DigitalZoom::paintEvent(QPaintEvent *event){
QPainter painter(this);
painter.fillRect(this->rect(), QColor(0, 0, 0, 1));
}
2.2、视频播放窗口设置
2.2.1、调用透明窗口
mainWidget::mainWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::mainWidget)
{
ui->setupUi(this);
m_digitalZoomWidget = new DigitalZoom(this);
m_digitalZoomWidget->show();
}
2.2.2、透明窗口位置及大小自适应视频窗口
使用Qt::SplashScreen后,透明窗口的位置和大小就和其父窗口没有关系了,需要对位置进行转换,我这里因为透明窗口的父类是视频播放窗口,所以在视频播放窗口类中重载了moveEvent和resizeEvent事件。
void mainWidget::resizeEvent(QResizeEvent *event)
{
m_digitalZoomWidget->resize(width(),height());
}
void mainWidget::moveEvent(QMoveEvent *event)
{
m_digitalZoomWidget->move(geometry().x(),geometry().y());
}
2.2.3、坐标转换
本人因为需要实现数字放大功能,所以需要转换拉框坐标,这里就不列出了。
三、所有源码
3.1、透明窗口
digitalzoom.h
#ifndef DIGITALZOOM_H
#define DIGITALZOOM_H
#include <QWidget>
class DigitalZoom : public QWidget
{
Q_OBJECT
public:
explicit DigitalZoom(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
signals:
public slots:
private:
QPoint m_startPoint; /* 鼠标按下位置 */
QPoint m_endPoint; /* 鼠标移动后的位置 */
bool m_bIsLeftMousePressMove = false; /* 鼠标左键按下移动标志 */
};
#endif // DIGITALZOOM_H
digitalzoom.cpp
#include "digitalzoom.h"
#include <QPainter>
#include <QPaintEvent>
#include <QLabel>
DigitalZoom::DigitalZoom(QWidget *parent) : QWidget(parent)
{
setAttribute(Qt::WA_TranslucentBackground, true);
setWindowFlags(Qt::SplashScreen|Qt::FramelessWindowHint);
QLabel* upLab = new QLabel("我是透明窗口上的不透明控件",this);
upLab->setStyleSheet("color:red");
}
void DigitalZoom::paintEvent(QPaintEvent *event){
QPainter painter(this);
if(m_bIsLeftMousePressMove){
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(QColor(0, 160, 230), 5));
painter.drawRect(event->rect());
}else{
painter.fillRect(this->rect(), QColor(0, 0, 0, 1));
}
}
void DigitalZoom::mousePressEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton)
{
m_startPoint = event->pos();
}
QWidget::mousePressEvent(event);
}
void DigitalZoom::mouseMoveEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton){
m_endPoint = event->pos();
m_bIsLeftMousePressMove = true;
update(QRect(m_startPoint,m_endPoint));
}
}
void DigitalZoom::mouseReleaseEvent(QMouseEvent *event)
{
if(m_bIsLeftMousePressMove){
m_bIsLeftMousePressMove = false;
}
update();
}
3.2、视频播放窗口
mainWidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
#include "digitalzoom.h"
namespace Ui {
class mainWidget;
}
class mainWidget : public QWidget
{
Q_OBJECT
public:
explicit mainWidget(QWidget *parent = nullptr);
~mainWidget();
protected:
void resizeEvent(QResizeEvent *event) override;
void moveEvent(QMoveEvent *event) override;
private:
Ui::mainWidget *ui;
DigitalZoom* m_digitalZoomWidget;
};
#endif // MAINWIDGET_H
mainWidget.cpp
#include "mainwidget.h"
#include "ui_mainwidget.h"
mainWidget::mainWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::mainWidget)
{
ui->setupUi(this);
/* play video start */
//此处测试在当前窗口上通过winId()获取窗口句柄来播放视频
/* play video stop */
m_digitalZoomWidget = new DigitalZoom(this);
m_digitalZoomWidget->show();
}
mainWidget::~mainWidget()
{
delete ui;
}
void mainWidget::resizeEvent(QResizeEvent *event)
{
m_digitalZoomWidget->resize(width(),height());
}
void mainWidget::moveEvent(QMoveEvent *event)
{
m_digitalZoomWidget->move(geometry().x(),geometry().y());
}
mainWidget.ui
默认生成,未作任何修改。