Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSliders linked together
Forum Update on Monday, May 27th 2025

QSliders linked together

Scheduled Pinned Locked Moved Unsolved General and Desktop
qslidermousemove
6 Posts 3 Posters 1.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • MasterBLBM Offline
    MasterBLBM Offline
    MasterBLB
    wrote on last edited by
    #1

    Hey fellow Qt devs

    The goal I wish to archive is 2 QSliders whose with values changes simultaneously if I added Qt::ControlModifier to mouse interaction with either of them. So far I got this:

    StepSlider::StepSlider(QWidget *parent)
    : QSlider(parent)
    {
        setSingleStep(5);
        setPageStep(5);
    
        QObject::connect(this, &QSlider::valueChanged, this, [this](int value)
        {
            const int step = 5;
            int offset = value % step;
            if( offset != 0)
                this->setValue(value - offset);
        });
    }
    
    void StepSlider::setMirroredSlider(QSlider *slider)
    {
        mirroredSlider = slider;
    }
    
    void StepSlider::mousePressEvent(QMouseEvent *event)
    {
        qDebug() << objectName() << " press pos: " << event->pos().x() << " ," << event->pos().y();
        if (event->modifiers() == Qt::ControlModifier)
        {
            QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonRelease, QPointF(), Qt::MiddleButton, 0, 0);
            *e = *event;
            e->setModifiers(Qt::NoModifier);
            qApp->postEvent(mirroredSlider, e);
        }
        QSlider::mousePressEvent(event);
    }
    
    void StepSlider::wheelEvent(QWheelEvent *event)
    {
        if (event->modifiers() == Qt::ControlModifier)
        {
            QWheelEvent *e = new QWheelEvent(QPointF(), 0, 0, 0);
            *e = *event;
            e->setModifiers(Qt::NoModifier);
            qApp->postEvent(mirroredSlider, e);
        }
        QSlider::wheelEvent(event);
    }
    
    void StepSlider::mouseMoveEvent(QMouseEvent *event)
    {
        //ten przypadek działa jedynie wtedy kiedy wartości slidera są identyczne
        //oznacza to, że mousePos().x() musi mu się zgadzać, inaczej coś się pieprzy
        //rozwiązanie - obliczyć pos dla 2 slidera tak, jakby wskaźnik myszy był nad nim
        //co może się przydać
        //int QStyle::sliderPositionFromValue(min, max, val, space, upsideDown);
        //QRect QStyle::subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const
    //    QStyleOptionSlider opt;
    //    initStyleOption(&opt);
    //    opt.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle;
    //    QRect handleRect =style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
        int posFromValue = QStyle::sliderPositionFromValue(mirroredSlider->minimum(), mirroredSlider->maximum(), mirroredSlider->value(), mirroredSlider->width());
        qDebug() << mirroredSlider->objectName() << " value:" << posFromValue;
        if (event->modifiers() == Qt::ControlModifier)
        {
            QMouseEvent *e = new QMouseEvent(event->type(), QPointF(posFromValue + 1, event->y()), event->button(), event->buttons(), Qt::NoModifier);
            //QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonRelease, QPointF(), Qt::MiddleButton, 0, 0);
            //*e = *event;
            e->setModifiers(Qt::NoModifier);
            qApp->postEvent(mirroredSlider, e);
        }
        QSlider::mouseMoveEvent(event);
    }
    

    I got the effect by posing appropriate event to other QSlider, just without keyboard modifier. Wheel and click (and hold) a mouse button works excellent, but there is an issue with mouse move - it works only when handles of sliders have the same position (case *e = *event, QMouseEvent created with default values, currently commented out). I'm certain that is because there is check in QSlider implementation like if (mouseClikPos() != handlePos) doNothing; , so my solution was to change mouseEvent.pos().x() to the position of the handle of 2nd slider. I calculated it using QSliderPositionFromValue() as you see, then I checked with qDebugs if the result is plausible - it is, though it seems it counts left edge of the handle.
    But this does not work :/
    Looks like operation *e = *event copied other vital data, but I have no idea what I could be missing. Could you help mates?

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      Why not just connect each slider valueChanged signal to the other setValue slot ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      2
      • MasterBLBM Offline
        MasterBLBM Offline
        MasterBLB
        wrote on last edited by
        #3

        Hey,

        Because each slider can have different value, and what I want to simultaneously increase/decrease it by common step (5). Ex:
        Slider 1 - 20 , max 100
        Slider 2 - 50, max 100
        I started increasing slider 1 using mouse wheel + ctrl modifier, after 1st spin:
        Slider 1 - 25
        Slider 2 - 55
        and so on till slider 2 reaches max, since then only slider 1 keeps increasing.

        I don't insist with mouseevent-based solution, made it only because I though it'll be quick and easy.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Then QSlider::actionTriggered might be what you are looking for.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          1
          • Kent-DorfmanK Offline
            Kent-DorfmanK Offline
            Kent-Dorfman
            wrote on last edited by Kent-Dorfman
            #5

            I got to thinking about this last night and it is as SGaist initially recommended, but with a custom slot for each slider. Also, depending upon the complexity of the slot, you may or may not also need a guard sentinel in each slot to keep from recursively calling the slots.

            This is a working python example:

            //your code h# -*- coding: utf-8 -*-
            
            # Form implementation generated from reading ui file 'Sliders.ui'
            #
            # Created by: PyQt5 UI code generator 5.10.1
            #
            # WARNING! All changes made in this file will be lost!
            
            from PyQt5 import QtCore, QtGui, QtWidgets
            
            class Ui_Sliders(object):
                def setupUi(self, Sliders):
                    Sliders.setObjectName("Sliders")
                    Sliders.resize(259, 203)
                    self.verticalLayout = QtWidgets.QVBoxLayout(Sliders)
                    self.verticalLayout.setObjectName("verticalLayout")
                    self.Slider1 = QtWidgets.QSlider(Sliders)
                    self.Slider1.setMinimumSize(QtCore.QSize(241, 16))
                    self.Slider1.setOrientation(QtCore.Qt.Horizontal)
                    self.Slider1.setObjectName("Slider1")
                    self.verticalLayout.addWidget(self.Slider1)
                    self.Slider2 = QtWidgets.QSlider(Sliders)
                    self.Slider2.setMinimumSize(QtCore.QSize(241, 16))
                    self.Slider2.setOrientation(QtCore.Qt.Horizontal)
                    self.Slider2.setObjectName("Slider2")
                    self.verticalLayout.addWidget(self.Slider2)
                    spacerItem = QtWidgets.QSpacerItem(20, 108, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
                    self.verticalLayout.addItem(spacerItem)
                    self.buttonBox = QtWidgets.QDialogButtonBox(Sliders)
                    self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
                    self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
                    self.buttonBox.setObjectName("buttonBox")
                    self.verticalLayout.addWidget(self.buttonBox)
            
                    self.retranslateUi(Sliders)
                    self.buttonBox.accepted.connect(Sliders.accept)
                    self.buttonBox.rejected.connect(Sliders.reject)
                    QtCore.QMetaObject.connectSlotsByName(Sliders)
            
                def retranslateUi(self, Sliders):
                    _translate = QtCore.QCoreApplication.translate
                    Sliders.setWindowTitle(_translate("Sliders", "Dialog"))
            
                def Slider1SetValue(self, _v):
                    self.Slider1.setValue(99 - _v)
            
                def Slider2SetValue(self, _v):
                    self.Slider2.setValue(99 - _v)
            
            # ==============================================================================
            if __name__ == "__main__":
                import sys
                app = QtWidgets.QApplication(sys.argv)
                Sliders = QtWidgets.QDialog()
                ui = Ui_Sliders()
                ui.setupUi(Sliders)
                ui.Slider1.setValue(99)
                ui.Slider2.setValue(0)
                ui.Slider1.valueChanged.connect(ui.Slider2SetValue)
                ui.Slider2.valueChanged.connect(ui.Slider1SetValue)
                Sliders.show()
                sys.exit(app.exec_())
            
            
            1 Reply Last reply
            0
            • MasterBLBM Offline
              MasterBLBM Offline
              MasterBLB
              wrote on last edited by MasterBLB
              #6

              Thanks for trying @Kent-Dorfman , but I don't know Python so the example is useless for me.

              @SGaist
              ActionTriggered seems to work better:

              void StepSlider::mouseMoveEvent(QMouseEvent *event)
              {
                  int valueBefore = value();
                  QSlider::mouseMoveEvent(event);
                  int valueDelta = value() - valueBefore;
                  if (event->modifiers() == Qt::ControlModifier && valueDelta != 0)
                  {
                      mirroredSlider->triggerAction(valueDelta > 0 ? QAbstractSlider::SliderSingleStepAdd : QAbstractSlider::SliderSingleStepSub);
                  }
                  qDebug() << objectName() << " value delta:" << valueDelta;
              }
              

              though in some situations mirroredSlider is not incremented/decremented properly - but that may be related to my sliders in the testbed project doesn't have properly set stuff to allow change values only by stepSize = 5

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved