GUI 編程 —— QT 的 QSlider 鼠標點擊定位問題


這幾天打算封裝 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音頻 數據功能]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM