I had the exact same problem. I thought about using the QxtSpanSlider, and although they have beautiful code, they don't keep their code up to date anymore. So, I decided to make my own. I haven't spent that much time on this, so there are kludges and probably bugs. However, it should be at a point to where you can copy/paste it into your project. I hope it'll point you in the right direction.
*note, before you use this, here is a list of all of the problems I've found and am currently working on:
- The second handle isn't nearly as sensitive as the first handle, resulting in slight agitation for the user.
- Some of the values are hard coded and as a result the slider isn't as dynamic as it could be.
- The second handle doesn't handle (haa...) negative values yet.
Here's a good solution:
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();
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…