Qt透明窗口鼠标穿透问题及解决办法


问题:

最近写了个项目,需要播放视频并在视频上做标记框去完成一些功能
因为视频播放使用了VLC-qt的库,封装好的窗口控件
没办法直接在该视频窗口上绘图(也许可以?)
出于不想动别人写好的库的想法,想着在视频窗口上加一个透明蒙版-即一个透明窗口,在透明窗口上进行绘图操作

实现:

这个是业务窗口逻辑

void Dialog::on_select_videowindow_clicked()
{
	//获取本窗口中视频窗口的位置,并转换为相对屏幕坐标
    QPoint p = ui->video->mapToGlobal(QPoint(0, 0));
    QSize size = ui->video->size();
	//当没创建新创口界面时,new一个出来
    if(m_screen == NULL)
    {
        m_screen = new Screen(0,p.x(),p.y(),size.width(),size.height());
    }
    else
    {
        //设置回初始状态
        m_screen->init(true);
    }
    m_screen->show();
}

这个是透明蒙版的构造函数

Screen::Screen(QWidget *parent, int x, int y, int w, int h)
    : QWidget(parent),
      m_widthInfoRect(QRectF(0, 0, 0, 0)),
      m_control(NULL)
{
    setWindowFlags(Qt::FramelessWindowHint);//设置无标题栏
    setMouseTracking(true);//捕获鼠标事件

    setAttribute(Qt::WA_QuitOnClose,false);//设置本窗口不关联程序退出
    setAttribute(Qt::WA_TransparentForMouseEvents, false);//设置鼠标不穿透
    setAttribute(Qt::WA_TranslucentBackground, true);//设置窗口透明背景
    setWindowFlag(Qt::WindowStaysOnTopHint);//设置本窗口处在顶层
	//初始化本窗口参数
    init(true);
}

分析:

如上,获取了视频窗口的位置及大小,并将透明窗口覆盖在video窗口上
然后重写了Screen的部分鼠标事件及绘图事件,实现标记功能
但实际操作发现,当鼠标点击透明窗口时无法触发该透明窗口的鼠标事件,即鼠标穿透了,点击到了视频窗口上。
明明已经设置了WA_TransparentForMouseEvents属性为false,但鼠标依然穿透了。
setAttribute(Qt::WA_TransparentForMouseEvents, false)未生效

重新实现:

经过一段时间的研究,将代码修改后
重写paintEvent事件解决了这个问题
如下:

Screen::Screen(QWidget *parent, int x, int y, int w, int h)
    : QWidget(parent),
      m_widthInfoRect(QRectF(0, 0, 0, 0)),
      m_control(NULL)
{
    setWindowFlags(Qt::FramelessWindowHint);//设置无标题栏
    setMouseTracking(true);//捕获鼠标事件
    
    m_pixmap = QPixmap(w,h);
    //全局路径的初始化,一个全屏闭合回路
    m_globalPath.lineTo(m_pixmap.width(), 0);
    m_globalPath.lineTo(m_pixmap.width(), m_pixmap.height());
    m_globalPath.lineTo(0, m_pixmap.height());
    m_globalPath.lineTo(0, 0);

    setAttribute(Qt::WA_QuitOnClose,false);//设置本窗口不关联程序退出
//    setAttribute(Qt::WA_TransparentForMouseEvents, false);//设置鼠标不穿透
    setAttribute(Qt::WA_TranslucentBackground, true);//设置窗口透明背景
    setWindowFlag(Qt::WindowStaysOnTopHint);//设置本窗口处在顶层
	//初始化本窗口参数
    init(true);
}

void Screen::paintEvent(QPaintEvent *e)
{
	//解决鼠标穿透问题
    Q_UNUSED(e);
    QPainter paint(this);
    paint.setPen(Qt::transparent);
    paint.setBrush(QColor(0, 0, 0, 1));
    //关键是这一步  绘制一个全局的路径
    paint.drawPath(m_globalPath);

	//其他绘图事件
}

可以看到透明窗口上再绘制一个透明全屏幕路径后完美的解决了这个问题
发现设不设置Qt::WA_TransparentForMouseEvents这个属性好像没有什么影响,也许默认就是false。

效果如下:
下层为视频,上层红框在透明蒙版上实现

结论:

猜测:就是因为当前窗口上什么都没有只有一个透明背景导致鼠标穿透了,再窗口上再绘制透明图片(即让窗口上有东西)即可解决这个问题。

但具体底层机制不明,还得深入学习下。
不过就目前来讲,应该够用了。

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辣死那个胖子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值