QSlider鼠标直接跳转

Vih*_*rma 36 qt qslider

当用户点击qslider上的某个地方时,我想让滑块跳到那个位置,而不是踩踏.如何实施?

Mic*_*cka 26

在所有版本的@spyke @Massimo Callegari和@Ben(滑块位置对于整个区域都不正确)出现问题后,我在QSlider源代码中找到了一些Qt Style功能:QStyle::SH_Slider_AbsoluteSetButtons.

您必须创建一个非常烦人的新QStyle,或者ProxyStylehttp://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);
    }
};
Run Code Online (Sandbox Code Playgroud)

现在,您可以在滑块构造函数中设置滑块的样式(如果滑块是从QSlider派生的):

setStyle(new MyStyle(this->style()));
Run Code Online (Sandbox Code Playgroud)

或者它应该以这种方式工作,如果它是一个标准的QSlider:

standardSlider.setStyle(new MyStyle(standardSlider->style()));
Run Code Online (Sandbox Code Playgroud)

所以你使用该元素的原始样式,但如果要求QStyle::SH_Slider_AbsoluteSetButtons"属性",你可以根据需要返回;)

也许你必须在滑块删除时销毁这些代理方式,尚未测试.

  • 不幸的是,样式表不适用于自定义样式 (3认同)
  • 是的,这是正确的答案。 (2认同)
  • 也附和欣赏这个答案。QSlider 已经在 macOS 中以这种方式运行,所以我认为必须有一个比子类化 QSlider 更优雅的解决方案来在 Windows 中获得相同的行为。这样的解决方案涉及使用 QStyle / QProxyStyle 是有道理的。 (2认同)
  • 我的编译器不允许我使用“QProxyStyle”构造函数,因为某些构造函数是隐藏的,因此我需要像这样显式定义它:“MyStyle(QStyle* style = nullptr) : QProxyStyle(style) {}” (2认同)

Sca*_*ode 22

好吧,我怀疑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);
  }
};
Run Code Online (Sandbox Code Playgroud)


Mas*_*ari 19

我也需要这个并尝试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);
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*Ben 15

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);
Run Code Online (Sandbox Code Playgroud)


小智 9

这是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()))
Run Code Online (Sandbox Code Playgroud)

  • 这是要走的路!它有效、简单并且独立于操作系统。 (3认同)

Fiv*_*kis 6

下面的代码实际上是一个hack,但它没有子类化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;
        }
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)