這幾天打算封裝 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;
}
//======================================
// 計算結果,並設置新計算得到的 position 值
int scpos = sliderCtrl->minimum() +
(int)((sliderCtrl->maximum() - sliderCtrl->minimum()) *
((mxpos - cxctl / 2.0) / (cxwnd - cxctl)));
if (sliderCtrl->sliderPosition() == scpos)
{
break;
}
sliderCtrl->setSliderPosition(scpos);
//======================================
} 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 播放器封裝類也完成了,在另外一篇文章中
libvlc —— 播放器示例程序[C++代碼實現攫取 RGB圖像 和 PCM音頻 數據功能]