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

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