Qt 视频窗口的鼠标操作,使用透明窗口覆盖视频窗口,可在透明窗口上使用鼠标做类似区域截屏操作。

使用Qt控件(例如QWidget或QLabel)做视频播放,当需要在视频上画框或者画点线做标记时,一般无法直接在播放的控件上画出。在正在播放的视频窗口,画一个小于视频窗口的区域,然后截取该区域保存至图片,是一个很常见的抓拍需求。

这个时候的思路是在正在播放视频的窗口叠加一层窗口,将该叠加窗口设置为透明,设置一些基本窗口属性,重写其paintEvent()事件。当鼠标进入视频窗口后,显示这个透明窗口,然后在透明窗口的paintEvent()中根据需要的大小画截图框即可。如下图所示:

接着重写鼠标按下事件pressEvent()事件,在该事件中做需要的动作。

本文给出叠加透明窗口的一个基本思路和demo实现,以及记录下需要注意的事项。demo示例程序使用 Qt5.8.0,msvc版。demo界面如下图所示(鼠标进入后会显示在截图框最中央,且变成十字,截图无法展示):

主窗体

示例程序中命名为 FormMainWidget,声明在FormMainWidget.h,继承QWidget类,没什么好说的。

视频窗口

命名为FormVideoDialog,继承QLabel。因为要获取其各种事件,故在主窗体FormMainWidget中将该类提升为FormVideoDialog。

透明窗口

命名为FormTransparentDialog类,是FormVideoDialog的类成员。

1、透明窗口FormTransparentDialog不能和FormVideoDialog是父子窗口关系,否则FormTransparentDialog将正常显示;

2、透明窗口FormTransparentDialog在初始化时要加入下述三句代码: 

setWindowFlags(Qt::FramelessWindowHint | Qt::SubWindow | Qt::WindowStaysOnTopHint);// 设置无边框、子窗口
setAttribute(Qt::WA_TranslucentBackground, true);       // 设置为透明窗口
setMouseTracking(true);                                 // 设置鼠标移动事件生效

3、如果透明窗口显示,主窗口FormMainWidget在移动时需要重写moveEvent()事件,并将该事件通知到FormVideoDialog和FormTransparentDialog(本程序是以信号槽的形式通知到FormTransparentDialog),否则FormTransparentDialog不会跟着主窗体的移动而移动。当然可以选择鼠标离开FormTransparentDialog时让FormTransparentDialog隐藏。

以下是FormTransparentDialog的paintEvent,在该事件中画截图框,最关键的部分是AdjustPaintArea()函数,该函数计算框的位置,和边界判断,具体看代码:

void FormTransparentDialog::paintEvent(QPaintEvent* event)
{
    QPainter painter(this);
    painter.fillRect(rect(), m_transparentColor);
    painter.setPen(QPen(Qt::red, m_iLineWidth, Qt::SolidLine, Qt::RoundCap));

    GetAreaDialogSize();

    int iPaintLeft = 0, iPaintTop = 0;
    int iPaintWidth = m_iAreaDialogWidth, iPaintHeight = m_iAreaDialogHeight;
    QPoint mousePoint = mapFromGlobal(QCursor::pos());
    AdjustPaintArea(iPaintLeft, iPaintTop, mousePoint);
    painter.drawRect(QRect(iPaintLeft, iPaintTop, iPaintWidth, iPaintHeight));
}
void FormTransparentDialog::GetAreaDialogSize()
{
    m_iAreaDialogWidth = FormMainWidget::GetMainWidget()->GetAreaDialogWidth();
    m_iAreaDialogWidth = m_iAreaDialogWidth > 0 ? m_iAreaDialogWidth : 300;
    m_iAreaDialogHeight = FormMainWidget::GetMainWidget()->GetAreaDialogHeight();
    m_iAreaDialogHeight = m_iAreaDialogHeight > 0 ? m_iAreaDialogHeight : 200;
}
void FormTransparentDialog::AdjustPaintArea(int& iPaintLeft, int& iPaintTop, const QPoint& mousePoint)
{
    CalculateAreaLeftTop(iPaintLeft, iPaintTop, mousePoint);
}
void FormTransparentDialog::CalculateAreaLeftTop(int& iPaintLeft, int& iPaintTop, const QPoint& mousePoint)
{
    if (mousePoint.x() < (m_iAreaDialogWidth + 2 * m_iLineWidth) / 2)
    {
        iPaintLeft = 0;
        CalculateAreaTop(iPaintTop, mousePoint);
    }
    else if (mousePoint.x() > size().width() - (m_iAreaDialogWidth + 2 * m_iLineWidth) / 2)
    {
        iPaintLeft = size().width() - (m_iAreaDialogWidth + 2 * m_iLineWidth);
        CalculateAreaTop(iPaintTop, mousePoint);
    }
    else
    {
        iPaintLeft = mousePoint.x() - (m_iAreaDialogWidth + 2 * m_iLineWidth) / 2;
        CalculateAreaTop(iPaintTop, mousePoint);
    }
}
void FormTransparentDialog::CalculateAreaTop(int& iPaintTop, const QPoint& mousePoint)
{
    if (mousePoint.y() < (m_iAreaDialogHeight + 2 * m_iLineWidth) / 2)
    {
        iPaintTop = 0;
    }
    else if (mousePoint.y() > size().height() - (m_iAreaDialogHeight + 2 * m_iLineWidth) / 2)
    {
        iPaintTop = size().height() - (m_iAreaDialogHeight + 2 * m_iLineWidth);
    }
    else
    {
        iPaintTop = mousePoint.y() - (m_iAreaDialogHeight + 2 * m_iLineWidth) / 2;
    }
}

demo的代码资源链接: https://download.csdn.net/download/explorer114/11097452

猜你喜欢

转载自blog.csdn.net/explorer114/article/details/89097642