Ползунок диапазона в Qt (две ручки в QSlider)

Мне нужен выбор диапазона с помощью QSlider. Можно ли получить два дескриптора, если нет, есть ли какой-нибудь фрагмент кода, чтобы с этим справиться?

Ниже изображение, иллюстрирующее то, что мне нужно.

Пример изображения


person Sivam    schedule 28.06.2013    source источник
comment
Это невозможно. Вам нужно будет разработать собственный виджет. Возможно, попробуйте этот: libqxt.bitbucket.org/doc/0.6/qxtspanslider.html   -  person Frank Osterfeld    schedule 28.06.2013
comment
Пожалуйста, предложите мне, как это сделать. Любые фрагменты означают, пожалуйста, сообщение.   -  person Sivam    schedule 28.06.2013
comment
Я не могу найти QxtSpanslider в Qt5.0.1, добавляю ли я какой-либо плагин?   -  person Sivam    schedule 28.06.2013
comment
Вам нужно использовать библиотеку Qxt.   -  person Pavel Strakhov    schedule 28.06.2013
comment
Мне удалось отрезать QxtSpanSlider от qxt и скомпилировать его с Qt 5.3 с минимальными изменениями в коде. Осталось только переписать взаимосвязь QxtSpanSlider и QxtSpanSliderPrivate (в коде это указатели qxt_d и qxt_p)   -  person nayana    schedule 27.10.2014
comment
@otopolsky Я думаю, что хотел бы пойти по твоему пути и отрезать spanSlider, но у меня не получилось. Не могли бы вы опубликовать ответ ниже, объясняющий ваш метод?   -  person dearn44    schedule 03.06.2015
comment
@dearn44 нет, я не могу, потому что вопрос закрыт .. Публикация всего кода будет довольно большой .. пожалуйста, задайте новый вопрос о том, какие будут изменения в ползунке диапазона qxt, и я дам вам различия о том, что следует сделать, и пусть я как-то знаю.. может здесь   -  person nayana    schedule 03.06.2015
comment
@otopolsky готово, перейдите по этой ссылке -install-it-is-th" title="Я хотел бы использовать ползунок диапазона из qxt без необходимости его установки"> stackoverflow.com/questions/30620816/   -  person dearn44    schedule 03.06.2015
comment
Когда мне нужно было сделать что-то подобное, я поместил два ползунка рядом друг с другом и манипулировал их средней точкой (максимум слайдера_1 и минимум слайдера_2), чтобы он всегда был средним из двух значений. Затем я также рассчитал ширину как отношение к общей ширине. На самом деле это выглядит и работает очень плавно, если вы избавитесь от прокладок между двумя ползунками.   -  person Samuel O'Malley    schedule 13.02.2017


Ответы (1)


У меня была точно такая же проблема. Я думал об использовании QxtSpanSlider, и хотя у них красивый код, они больше не обновляют свой код. Итак, я решил сделать свой собственный. Я не тратил на это так много времени, поэтому есть кладжи и, возможно, ошибки. Тем не менее, это должно быть место, где вы можете скопировать/вставить его в свой проект. Я надеюсь, что это укажет вам в правильном направлении.

* обратите внимание, прежде чем использовать это, вот список всех проблем, которые я обнаружил и над которыми сейчас работаю:

  • Вторая ручка не так чувствительна, как первая ручка, что приводит к легкому волнению пользователя.
  • Некоторые значения жестко закодированы, и в результате ползунок не так динамичен, как мог бы быть.
  • Второй дескриптор еще не обрабатывает (ха-ха...) отрицательные значения.

Вот хорошее решение:

SuperSlider.h

#pragma once

#include "qslider.h"
#include "qlabel.h"


/*
*  Super sick nasty awesome double handled slider! 
*
*   @author Steve
*/
class SuperSliderHandle;

class SuperSlider: public QSlider
{
  Q_OBJECT
public:
  /** Constructor */
  SuperSlider(QWidget *parent = 0);

  /** Store the alternate handle for this slider*/
  SuperSliderHandle *alt_handle;

  /** Overridden mouse release event */
  void mouseReleaseEvent(QMouseEvent *event);

  /** Returns the slider value for the alternate handle */
  int alt_value();

  /** Convenience function for setting the value of the alternate handle */
  void alt_setValue(int value);

  /** Resets the alternate handle to the right side of the slider */
  void Reset();

  /** Used to update the position of the alternate handle through the use of an event filter */
  void alt_update();
signals:
  /** Constructor */
  void alt_valueChanged(int);
};

class SuperEventFilter : public QObject
{
public:
  /** Constructor */
  SliderEventFilter(SuperSlider *_grandParent) 
  {grandParent = _grandParent;};

protected:
  /*
  * overloaded functions for object that inherit from this class
  */
  bool eventFilter(QObject* obj, QEvent* event);

private:
  /** Store the SuperSlider that this event filter is used within. */
  SuperSlider *grandParent;
};

class SuperSliderHandle: public QLabel
{
  Q_OBJECT
public:
  /** Constructor */
  SuperSliderHandle(SuperSlider *parent = 0);

  /** An overloaded mousePressevent so that we can start grabbing the cursor and using it's position for the value */
  void mousePressEvent(QMouseEvent *event);

  /** Returns the value of this handle with respect to the slider */
  int value();

  /** Maps mouse coordinates to slider values */
  int mapValue();

  /** Store the parent as a slider so that you don't have to keep casting it  */
  SuperSlider *parent;

  /** Store a bool to determine if the alternate handle has been activated  */
  bool handleActivated;

private:
  /** Store the filter for installation on the qguiapp */
  SliderEventFilter *filter;

  public slots:
    /** Sets the value of the handle with respect to the slider */
    void setValue(double value);
};

SuperSlider.cpp

//Project
#include "SuperSlider.h"

//Qt
#include <QMouseEvent>
#include "qmimedata.h"
#include "qdrag.h"
#include "qwidgetaction.h"
#include "qapplication.h"
#include "qpixmap.h"
#include "qcursor.h"
#include "qguiapplication.h"
#include "qdir.h"
#include <QProxyStyle>

class SliderProxy : public QProxyStyle
{
public:
  int pixelMetric ( PixelMetric metric, const QStyleOption * option = 0, const QWidget * widget = 0 ) const
  {
    switch(metric) {
    case PM_SliderThickness  : return 25;
    case PM_SliderLength     : return 25;
    default                  : return (QProxyStyle::pixelMetric(metric,option,widget));
    }
  }
};

SuperSlider::SuperSlider(QWidget *parent)
  : QSlider(parent)
{
  //styling
  setOrientation(Qt::Horizontal);
  setAcceptDrops(true);
  SliderProxy *aSliderProxy = new SliderProxy();

  //hard coded path to image :/ sorry 
  QString path = QDir::fromNativeSeparators(ImagesPath("handle.png")); 
  setStyleSheet("QSlider::handle { image: url(" + path + "); }");
  setStyle(aSliderProxy);

  //setting up the alternate handle
  alt_handle = new SuperSliderHandle(this);
  addAction(new QWidgetAction(alt_handle));
  alt_handle->move(this->pos().x() + this->width()- alt_handle->width(), this->pos().y() );

}

SuperSliderHandle::SuperSliderHandle(SuperSlider *_parent)
  : QLabel(_parent)
{
  parent = _parent;
  filter = new SliderEventFilter(parent);

  //styling
  setAcceptDrops(true);
  //hard coded path to image :/ sorry 
  QPixmap pix = QPixmap(ImagesPath("handle.png"));
  pix =  pix.scaled(25, 25, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
  setPixmap(pix);
}

int SuperSlider::alt_value()
{
  return alt_handle->value();
}

void SuperSlider::alt_setValue(int value)
{
  alt_handle->setValue(value);
}

void SuperSlider::mouseReleaseEvent(QMouseEvent *mouseEvent)
{
  if (mouseEvent->button() == Qt::LeftButton) 
  {
    alt_handle->show();
    alt_handle->handleActivated = false;
  }
  mouseEvent->accept();
}

void SuperSlider::alt_update()
{
  QPoint posCursor(QCursor::pos());
  QPoint posParent(mapToParent(mapToGlobal(pos())));
  QPoint point(alt_handle->mapToParent(alt_handle->mapFromGlobal(QCursor::pos())).x(),alt_handle->y());
  int horBuffer = (alt_handle->width());
  bool lessThanMax = mapToParent(point).x() < pos().x()+ width() - horBuffer;
  bool greaterThanMin = mapToParent(point).x() > pos().x();
  if(lessThanMax && greaterThanMin)
    alt_handle->move(point);
  emit alt_valueChanged(alt_value());
}

void SuperSliderHandle::mousePressEvent(QMouseEvent *mouseEvent)
{
  qGuiApp->installEventFilter(filter);
  parent->clearFocus();
}

bool SliderEventFilter::eventFilter(QObject* obj, QEvent* event)
{
  switch(event->type())
  {
  case QEvent::MouseButtonRelease:
    qGuiApp->removeEventFilter(this);
    return true;
    break;
  case QEvent::MouseMove:
    grandParent->alt_update();
    return true;
    break;
  default:
    return QObject::eventFilter(obj, event);
  }
  return false;
}

void SuperSliderHandle::setValue(double value)
{
  double width = parent->width(), position = pos().x();
  double range = parent->maximum() - parent->minimum();
  int location = (value - parent->minimum())/range; 
  location = location *width;
  move(y(),location);
}

int SuperSliderHandle::value()
{
  double width = parent->width(), position = pos().x();
  double value = position/width;
  double range = parent->maximum() - parent->minimum();
  return parent->minimum() + (value * range); 
}
void SuperSlider::Reset()
{
  int horBuffer = (alt_handle->width());
  QPoint myPos = mapToGlobal(pos()); 
  QPoint point(myPos.x() + width() - horBuffer, myPos.y()- alt_handle->height());
  point = alt_handle->mapFromParent(point);

  alt_handle->move(point);
  alt_handle->show();
  alt_handle->raise();

}
person AmusingTeebs    schedule 24.09.2014
comment
Для его компиляции SuperEventFilter нужно изменить на SliderEventFilter в заголовке, в определении класса. Не могли бы вы поставить и пример того, как его использовать? Я пытаюсь понять, как это работает. - person cauchy; 23.11.2015
comment
Можете ли вы объяснить, как использовать ваш класс в QT? - person Thomas Williams; 13.05.2017
comment
В вертикальном режиме второй манипулятор перемещается только по горизонтали. - person mucisk; 27.03.2019