2012-06-21 121 views
30

當用戶在qslider上的某個地方點擊時,我想讓滑塊跳轉到該位置,而不是步進。這如何實現?QSlider鼠標直接跳轉

+1

見Micka的答案下面,而不是一個簡單的解決方案公認的答案。 –

+0

請注意,滑塊的默認行爲是平臺特定的。例如,在MacOS上,滑塊直接跳到鼠標點擊的位置。 – normanius

回答

20

嗯,我懷疑Qt是否有直接的功能。

嘗試使用自定義小部件。這應該工作!

嘗試以下邏輯

class MySlider : public QSlider 
{ 

protected: 
    void mousePressEvent (QMouseEvent * event) 
    { 
    if (event->button() == Qt::LeftButton) 
    { 
     if (orientation() == Qt::Vertical) 
      setValue(minimum() + ((maximum()-minimum()) * (height()-event->y()))/height()) ; 
     else 
      setValue(minimum() + ((maximum()-minimum()) * event->x())/width()) ; 

     event->accept(); 
    } 
    QSlider::mousePressEvent(event); 
    } 
}; 
+1

對於水平滑塊值將無法正確計算。我建議這樣的變體:'setValue(minimum()+(maximum() - minimum())*(static_cast (event-> x())/ static_cast (width())));' –

+0

感謝您的代碼,但在我的情況下,我需要添加一個「+1」才能工作:「setValue(minimum()+((maximum() - minimum()+ 1)*(height() - event-> y() ))/ height());「 – Alex

0

一個簡單的方法是從QSlider導出並用mousePressEvent(....)重新實現以使用setSliderPosition(int)來設置標記位置。

1

我一直在試圖和網絡搜索這一點,並期待的Qt的更聰明的辦法這樣做,不幸的是有沒有大的幫助(可能是我沒有搜索正確)

以及我已經在Qt的創建者這樣做:

  1. 在報頭添加eventFilter(需要的QObject和QEvent的作爲參數)(布爾返回類型)
  2. 在構造函數中初始化..for例如..如果你的滑塊是HSlider然後 ui-> HSlider-> installEventFilter(this);
  3. 定義:

    a。檢查對象是否是您的滑塊類型:ui->HSlider == Object

    b。檢查鼠標點擊事件是這樣的:QEvent::MouseButtonPress == event->type

    c。如果所有道次以上意味着u必須抓住滑動件鼠標事件做類似:在定義:ui->HSlider->setValue(Qcursor::pos().x() - firstval); return QMainWindow::eventFilter(object, event);

注:fistVal:可通過打印cursur位置0 =滑塊的初始位置被取出(與QCursor::pos().x()幫助)

希望這有助於

16

我需要這也並試圖spyke解決方案,但它缺少兩樣東西:

  • 倒外觀
  • 柄採摘(當鼠標移動到手柄,直接跳轉是沒有必要的)

所以,這裏的審查代碼:

void MySlider::mousePressEvent (QMouseEvent * event) 
{ 
    QStyleOptionSlider opt; 
    initStyleOption(&opt); 
    QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); 

    if (event->button() == Qt::LeftButton && 
     sr.contains(event->pos()) == false) 
    { 
    int newVal; 
    if (orientation() == Qt::Vertical) 
     newVal = minimum() + ((maximum()-minimum()) * (height()-event->y()))/height(); 
    else 
     newVal = minimum() + ((maximum()-minimum()) * event->x())/width(); 

    if (invertedAppearance() == true) 
     setValue(maximum() - newVal); 
    else 
     setValue(newVal); 

    event->accept(); 
    } 
    QSlider::mousePressEvent(event); 
} 
+0

幾乎是優秀的。如果特殊位置已經完成,我只需要移除傳遞給基類的'event'。 –

+0

這應該是正確答案,無需修改即可使用。 – Andrew

6

下面的代碼實際上是一個黑客,但它沒有子類別QSlider工作正常。您需要做的唯一事情就是將QSlider valueChanged信號連接到您的容器。

注1:必須設置一個pageStep> 0在滑塊

注2:它僅適用於一個水平,由左到右滑塊(你應該改變的「sliderPosUnderMouse」計算與垂直方向的工作或倒立的外觀)

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 

    // ... 
    connect(ui->mySlider, SIGNAL(valueChanged(int)), 
      this, SLOT(mySliderValueChanged(int))); 
    // ... 
} 


void MainWindow::mySliderValueChanged(int newPos) 
{ 
    // Make slider to follow the mouse directly and not by pageStep steps 
    Qt::MouseButtons btns = QApplication::mouseButtons(); 
    QPoint localMousePos = ui->mySlider->mapFromGlobal(QCursor::pos()); 
    bool clickOnSlider = (btns & Qt::LeftButton) && 
         (localMousePos.x() >= 0 && localMousePos.y() >= 0 && 
          localMousePos.x() < ui->mySlider->size().width() && 
          localMousePos.y() < ui->mySlider->size().height()); 
    if (clickOnSlider) 
    { 
     // Attention! The following works only for Horizontal, Left-to-right sliders 
     float posRatio = localMousePos.x()/(float)ui->mySlider->size().width(); 
     int sliderRange = ui->mySlider->maximum() - ui->mySlider->minimum(); 
     int sliderPosUnderMouse = ui->mySlider->minimum() + sliderRange * posRatio; 
     if (sliderPosUnderMouse != newPos) 
     { 
      ui->mySlider->setValue(sliderPosUnderMouse); 
      return; 
     } 
    } 
    // ... 
} 
14

Massimo Callegari的答案几乎是正確的,但newVal的計算忽略了滑塊手柄的寬度。當您嘗試在滑塊末尾附近單擊時出現此問題。

以下代碼修復此爲水平滑塊

double halfHandleWidth = (0.5 * sr.width()) + 0.5; // Correct rounding 
int adaptedPosX = event->x(); 
if (adaptedPosX < halfHandleWidth) 
     adaptedPosX = halfHandleWidth; 
if (adaptedPosX > width() - halfHandleWidth) 
     adaptedPosX = width() - halfHandleWidth; 
// get new dimensions accounting for slider handle width 
double newWidth = (width() - halfHandleWidth) - halfHandleWidth; 
double normalizedPosition = (adaptedPosX - halfHandleWidth)/newWidth ; 

newVal = minimum() + ((maximum()-minimum()) * normalizedPosition); 
+0

缺少分號,不得不做6個字符編輯所以增加了另一個註釋 – Chance

14

我發現QSlider源代碼中的一些Qt樣式的功能:QStyle::SH_Slider_AbsoluteSetButtons

你必須創建一個新的將QStyle它可以是一個很煩人的,或者你使用ProxyStyle作爲http://www.qtcentre.org/threads/9208-QSlider-step-customize?p=49035#post49035

顯示用戶JPN我添加了另一個構造和固定一個錯字,但所用的其餘部分原始的源代碼。

#include <QProxyStyle> 

class MyStyle : public QProxyStyle 
{ 
public: 
    using QProxyStyle::QProxyStyle; 

    int styleHint(QStyle::StyleHint hint, const QStyleOption* option = 0, const QWidget* widget = 0, QStyleHintReturn* returnData = 0) const 
    { 
     if (hint == QStyle::SH_Slider_AbsoluteSetButtons) 
      return (Qt::LeftButton | Qt::MidButton | Qt::RightButton); 
     return QProxyStyle::styleHint(hint, option, widget, returnData); 
    } 
}; 

現在你可以設置中的滑動構造的滑蓋風格(如果你的滑塊從QSlider派生):

setStyle(new MyStyle(this->style())); 

還是應該以這種方式工作,如果它是一個標準的QSlider:

standardSlider.setStyle(new MyStyle(standardSlider->style())); 

使您在使用該元素的原有風格,但如果QStyle::SH_Slider_AbsoluteSetButtons「屬性」是問你回來,只要你想)

也許你必須在滑塊刪除時銷燬這些代理風格,尚未經過測試。

+4

這應該是被接受的答案。 – maxschlepzig

+1

是的,這是正確的答案。 – ens

+1

也希望能夠欣賞這個答案。 QSliders已經在macOS中以這種方式表現出來了,所以我認爲必須有比QSlider子類化更優雅的解決方案才能在Windows中獲得相同的行爲。有意義的是,這樣的解決方案涉及使用QStyle/QProxyStyle。 – GuyGizmo

6

下面是使用Python QStyle.sliderValueFromPosition()一個簡單的實現:基於周邊的意見

class JumpSlider(QtGui.QSlider): 

    def mousePressEvent(self, ev): 
     """ Jump to click position """ 
     self.setValue(QtGui.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), ev.x(), self.width())) 

    def mouseMoveEvent(self, ev): 
     """ Jump to pointer position while moving """ 
     self.setValue(QtGui.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), ev.x(), self.width())) 
+0

這是要走的路!它的工作原理很簡單,而且與操作系統無關。 – zephyr

2

我的最終實現:

class ClickableSlider : public QSlider { 
public: 
    ClickableSlider(QWidget *parent = 0) : QSlider(parent) {} 

protected: 
    void ClickableSlider::mousePressEvent(QMouseEvent *event) { 
     QStyleOptionSlider opt; 
     initStyleOption(&opt); 
     QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); 

     if (event->button() == Qt::LeftButton && 
      !sr.contains(event->pos())) { 
     int newVal; 
     if (orientation() == Qt::Vertical) { 
      double halfHandleHeight = (0.5 * sr.height()) + 0.5; 
      int adaptedPosY = height() - event->y(); 
      if (adaptedPosY < halfHandleHeight) 
       adaptedPosY = halfHandleHeight; 
      if (adaptedPosY > height() - halfHandleHeight) 
       adaptedPosY = height() - halfHandleHeight; 
      double newHeight = (height() - halfHandleHeight) - halfHandleHeight; 
      double normalizedPosition = (adaptedPosY - halfHandleHeight)/newHeight ; 

      newVal = minimum() + (maximum()-minimum()) * normalizedPosition; 
     } else { 
      double halfHandleWidth = (0.5 * sr.width()) + 0.5; 
      int adaptedPosX = event->x(); 
      if (adaptedPosX < halfHandleWidth) 
        adaptedPosX = halfHandleWidth; 
      if (adaptedPosX > width() - halfHandleWidth) 
        adaptedPosX = width() - halfHandleWidth; 
      double newWidth = (width() - halfHandleWidth) - halfHandleWidth; 
      double normalizedPosition = (adaptedPosX - halfHandleWidth)/newWidth ; 

      newVal = minimum() + ((maximum()-minimum()) * normalizedPosition); 
     } 

     if (invertedAppearance()) 
      setValue(maximum() - newVal); 
     else 
      setValue(newVal); 

     event->accept(); 
     } else { 
     QSlider::mousePressEvent(event); 
     } 
    } 
}; 
0

我也遇到了這個問題。我的解決方案如下所示。

slider->installEventFilter(this); 
---  
bool MyDialog::eventFilter(QObject *object, QEvent *event) 
    { 
     if (object == slider && slider->isEnabled()) 
     { 
      if (event->type() == QEvent::MouseButtonPress) 
      { 
       auto mevent = static_cast<QMouseEvent *>(event); 
       qreal value = slider->minimum() + (slider->maximum() - slider->minimum()) * mevent->localPos().x()/slider->width(); 
       if (mevent->button() == Qt::LeftButton) 
       { 
        slider->setValue(qRound(value)); 
       } 
       event->accept(); 
       return true; 
      } 
      if (event->type() == QEvent::MouseMove) 
      { 
       auto mevent = static_cast<QMouseEvent *>(event); 
       qreal value = slider->minimum() + (slider->maximum() - slider->minimum()) * mevent->localPos().x()/slider->width(); 
       if (mevent->buttons() & Qt::LeftButton) 
       { 
        slider->setValue(qRound(value)); 
       } 
       event->accept(); 
       return true; 
      } 
      if (event->type() == QEvent::MouseButtonDblClick) 
      { 
       event->accept(); 
       return true; 
      } 
     } 
     return QDialog::eventFilter(object, event); 
    } 

您也可以重寫這些QSlider的事件處理程序。

  • QSlider::mousePressedEvent
  • QSlider::mouseMoveEvent
  • QSlider::mouseDoubleClickEvent