2018.02.12更新
优化了游标的控件窗口属性,游标不再受任何组件的范围限制;优化了游标出现的位置;优化了鼠标点击得到的值,四舍五入得到。
2018.02.22更新
使用自定义信号sig_triggeredToValue,控件被触发时发射此信号,传递出滑块变化后的值,不再使用sliderMoved()信号。避免了键盘控制滑块移动不能产生sliderMoved()信号的问题。
2018.04.10更新
重写了控件的setVisible(), setEnable(), setDisable()方法,保证在控件不可见或无效状态下,不显示游标。Qt自带的QSlider控件提供了一个滑块控制,但是鼠标点击时,只能步进,使用起来很不方便。
另外,没有能够方便的区分出用户触发和setValue()两种情况导致的值变化的信号。
所以本人继承QSlider,写了QtSliderEasyClick控件。本控件可以点哪到哪,同时自定义了信号sig_triggeredToValue,用于表示滑块被触发时导致的值变化,可以区分出用户触发导致的值变化,另外还增加了游标显示鼠标位置对应的值,效果如图(鼠标位置在游标68下面,截屏不显示鼠标哈):
废话不多说,上核心代码,完整工程链接:https://gitee.com/pplxlee/QtSliderEasyClick
#include "qtslidereasyclick.h"
#include <QCursor>
QtSliderEasyClick::QtSliderEasyClick(QWidget *parent) :
QSlider(parent),
triggered_(false)
{
// 连接触发导致的值改变时的相关信号槽
connect(this, &QtSliderEasyClick::actionTriggered, this, &QtSliderEasyClick::__slot_actionTriggered);
connect(this, &QtSliderEasyClick::valueChanged, this, &QtSliderEasyClick::__slot_valueChanged);
label_ = new QLabel(this);
// 使其显示的位置不受父控件限制,也不回有窗口框架和任务栏任务,也不会获得焦点
label_->setWindowFlags(Qt::FramelessWindowHint|Qt::Tool);
label_->setFocusPolicy(Qt::NoFocus);
label_->setAttribute(Qt::WA_ShowWithoutActivating,true);
// 设置标签字体大小
QFont font;
font.setPointSize(11);
label_->setFont(font);
// 允许在鼠标不点击时跟踪鼠标位置
setMouseTracking(true);
// 保证点击游标时,不会产生中间值,而是一次性跳跃到点击处
this->setPageStep(0);
}
QtSliderEasyClick::~QtSliderEasyClick()
{
}
void QtSliderEasyClick::setVisible(bool visible)
{
QSlider::setVisible(visible);
// 保证设置不可见后,label_不可见
if(!visible)
{
label_->hide();
}
}
void QtSliderEasyClick::setDisabled(bool disabled)
{
QSlider::setDisabled(disabled);
// 保证设置无效后,label_不可见
if(disabled)
{
label_->hide();
}
}
void QtSliderEasyClick::setEnabled(bool enabled)
{
QSlider::setEnabled(enabled);
// 保证设置无效后,label_不可见
if(!enabled)
{
label_->hide();
}
}
void QtSliderEasyClick::__slot_actionTriggered(int)
{
// 滑块空间被触发时,触发状态为真
triggered_ = true;
}
void QtSliderEasyClick::__slot_valueChanged(int value)
{
// 触发状态为真时,发射触发值信号,并还原触发状态
if(triggered_)
{
sig_triggeredToValue(value);
triggered_ = false;
}
}
void QtSliderEasyClick::mousePressEvent(QMouseEvent *ev)
{
// 注意应先调用父类的鼠标点击处理事件,否则无法拖动
QSlider::mousePressEvent(ev);
// 根据鼠标位置计算值并设置值
int value = __calcuValueFromPos(ev->pos());
setValue(value);
}
void QtSliderEasyClick::mouseMoveEvent(QMouseEvent *ev)
{
QSlider::mouseMoveEvent(ev);
if(!this->isEnabled())
{
return;
}
int posValue = __calcuValueFromPos(ev->pos());
label_->setText(valueToText(posValue));
label_->adjustSize();
// 获取算本控件在屏幕中的位置
QPoint this_pos = this->mapToGlobal(QPoint(0,0));
// 计算得到标签位置范围
int min_pos_x_lable = this_pos.x();
int max_pos_x_lable = this_pos.x() + this->width() - label_->width();
int pos_y_lable = this_pos.y() - label_->height() - 5;
// 根据鼠标位置和标签范围,计算新的标签位置
int pos_x_label = QCursor::pos().x() - (label_->width()>>1);
pos_x_label = (pos_x_label<min_pos_x_lable)?min_pos_x_lable:pos_x_label;
pos_x_label = (pos_x_label>max_pos_x_lable)?max_pos_x_lable:pos_x_label;
// 移动标签到计算得到的位置
label_->move(pos_x_label, pos_y_lable);
}
void QtSliderEasyClick::enterEvent(QEvent *ev)
{
QSlider::enterEvent(ev);
if(!this->isEnabled())
{
return;
}
label_->show();
}
void QtSliderEasyClick::leaveEvent(QEvent *ev)
{
QSlider::leaveEvent(ev);
label_->hide();
}
QString QtSliderEasyClick::valueToText(int value)
{
return QString::number(value);
}
int QtSliderEasyClick::__calcuValueFromPos(const QPoint &pos)
{
// 使用四舍五入
int value = qRound((maximum() - minimum()) * pos.x() / (double)this->width() + minimum());
// 限制返回值在取值范围内
value = (value > maximum())?maximum():value;
return (value<minimum())?minimum():value;
}