这几天打算封装 libvlc 实现一个简单的播放器操作类,用 QT 写 UI 测试程序的时候,发现播放进度的显示控件 QSlider 在处理鼠标点击时,并不能直接定位到鼠标按下的位置。为解决这一问题,我在网上看了几篇博文提供的解决办法,但实现的效果并不理想,主要的问题是:鼠标点击定位时,出现位置偏差。鉴于这,我提供了如下的解决办法。
1. 为 QSlider 控件设置事件过滤
在 QSlider 控件父窗口初始化的时候设置(比如我的代码中就在 Widget 构造函数中设置):
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
......
ui->hSlider_duration->installEventFilter(this);
......
ui->hSlider_volume->installEventFilter(this);
......
}
2. 重载 eventFilter() 接口
对 QSlider 控件的父级窗口重载 eventFilter() 接口,然后针对 鼠标左键的按下事件 进行过滤判断操作:
bool Widget::eventFilter(QObject * watched, QEvent * event)
{
if ((event->type() == QEvent::MouseButtonPress) &&
((watched == ui->hSlider_duration) || (watched == ui->hSlider_volume)))
{
on_slider_mouseLButtonPress(watched, event);
}
return QWidget::eventFilter(watched, event);
}
3. 计算点击定位的 value
void Widget::on_slider_mouseLButtonPress(QObject * slider, QEvent * event)
{
do
{
//======================================
// 只处理 鼠标左键 的按下事件
QSlider * sliderCtrl = static_cast< QSlider * >(slider);
QMouseEvent * mouseEvent = static_cast< QMouseEvent * >(event );
if (Qt::LeftButton != mouseEvent->button())
{
break;
}
//======================================
// 确定控件操作的基本参数
int cxctl = 0; // 滑块宽度
int cxwnd = 0; // 滑槽长度
int mxpos = 0; // 鼠标按下的位置
if (Qt::Horizontal == sliderCtrl->orientation())
{
// 水平样式的 slider
cxctl = sliderCtrl->minimumSizeHint().width();
cxwnd = sliderCtrl->width();
if (sliderCtrl->invertedAppearance())
mxpos = cxwnd - mouseEvent->x();
else
mxpos = mouseEvent->x();
}
else
{
// 垂直样式的 slider
cxctl = sliderCtrl->minimumSizeHint().height();
cxwnd = sliderCtrl->height();
if (sliderCtrl->invertedAppearance())
mxpos = mouseEvent->y();
else
mxpos = cxwnd - mouseEvent->y();
}
if (cxwnd <= cxctl)
{
break;
}
//======================================
// 计算结果,并设置新计算得到的 value 值
int value = sliderCtrl->minimum() +
(int)((sliderCtrl->maximum() - sliderCtrl->minimum()) *
((mxpos - cxctl / 2.0) / (cxwnd - cxctl)));
if (sliderCtrl->value() == value)
{
break;
}
sliderCtrl->setValue(value);
//======================================
} while (0);
}
4. 头文件中 Widget 类的接口声明如下:
class Widget : public QWidget
{
......
// overrides
protected:
virtual bool eventFilter(QObject * watched, QEvent * event);
// inner invoking
protected:
void on_slider_mouseLButtonPress(QObject * slider, QEvent * event);
......
};
另外,我的 libvlc 播放器封装类快完成了,到时在另外一篇文章中介绍。