前言
起初我是想在界面上画个图,贯穿在整个视频中,跟水印很类似。本想获取每一帧图片,然后在上面绘制,但是这个效率太慢了,得不偿失;后来,查了查资料,发现这件事情完全可由Qt 控件实现,不必每一帧绘制,使视觉上他们是个整体就可以。
最终,我的界面效果是:将功能按钮(比如 播放、停止按钮)等,排放到视频下方。
效果图
代码和说明
如果直接在显示视频的Widget上直接放置控件,如一个按钮,这样会直接黑屏如下图,添加的按钮都没了。这是因为我将这个界面都给libvlc显示视频了,即控制权在libvlc手中。
所以得想个办法不将功能控件交给libvlc管理:将功能控件设为窗体,他就独立了,然后再将背景设成透明,视觉上就一样了,完美解决了这个问题。
//设置为窗口模式
m_pControlWidget->setWindowFlags(Qt::FramelessWindowHint|Qt::Window);
//设置背景透明
m_pControlWidget->setAttribute(Qt::WA_TranslucentBackground,true);
解决透明处不触发点击信号的问题
设置属性为 Qt::WA_TranslucentBackground,就会有个问题:若m_pControlWidget上的按钮背景图有部分透明的,那么透明处鼠标点击事件将穿过去,将不会触发按钮的点击信号,响应的事件将不会执行。
我解决这一问题,我想到两种方案:
将线型图标改为面型图标,如下图,将非透明区扩大,即扩大点击面积。
将按钮改成不全透明的,透明度改为0.1
QPushButton#stopButton{
border-image: url(:/res/stop.png);
border:none;
background-color:rgba(0,0,0,0.1);
}
使控制面板随界面事件而变化
这里监控了整个界面的事件,包括显示、隐藏等。
bool VideoWidget::event(QEvent *event)
{
switch (event->type()) {
case QEvent::Show:{
showSubWindow();
break;
}
case QEvent::WindowActivate:
case QEvent::Resize:
case QEvent::Move:{
moveSubWindow();
break;
}
case QEvent::Hide:{
hideSubWindow();
break;
}
default:
break;
}
return QWidget::event(event);
}
void VideoWidget::showSubWindow()
{
m_pControlWidget->show();
QTimer::singleShot(50,this,&VideoWidget::moveSubWindow);
}
void VideoWidget::hideSubWindow()
{
m_pControlWidget->hide();
}
void VideoWidget::moveSubWindow()
{
int w=this->width();
int h=this->height();
m_pControlWidget->setFixedWidth(w);
moveSubWindowByPoint(m_pControlWidget,QPoint(0,h-m_pControlWidget->height()));
}
void VideoWidget::moveSubWindowByPoint(QWidget* widget,QPoint pt)
{
int w=width()-widget->width();
int h=height()-widget->height();
//大小合理时显示
if(w>=0 && h>=0)
{
widget->setWindowOpacity(1);
QPoint p=mapToGlobal(QPoint(0,0));
int x=p.x()+pt.x();
int y=p.y()+pt.y();
widget->move(x,y);
widget->raise();
}else{
widget->setWindowOpacity(0);
}
}
结束语
后面有时间,我想给视频增加表情图,不知道能不能实现,等我好消息!