Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct


    Qt World Summit: Early-Bird Tickets

    Unsolved QSliders linked together

    General and Desktop
    qslider mousemove
    3
    6
    649
    Loading More Posts
    • 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.
    • MasterBLB
      MasterBLB last edited by

      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 Reply Quote 0
      • SGaist
        SGaist Lifetime Qt Champion last edited by

        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 Reply Quote 2
        • MasterBLB
          MasterBLB last edited by

          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 Reply Quote 0
          • SGaist
            SGaist Lifetime Qt Champion last edited by

            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 Reply Quote 1
            • Kent-Dorfman
              Kent-Dorfman last edited by Kent-Dorfman

              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 Reply Quote 0
              • MasterBLB
                MasterBLB last edited by MasterBLB

                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 Reply Quote 0
                • First post
                  Last post