效果
一、样式表设置
QSlider::groove:horizontal {
border: 1px solid gray;
height: 2px;
left: 8px;
right: 8px;
}
QSlider::handle:horizontal {
border: 1px solid gray;
background:white;
border-radius: 5px;
width: 10px;
height: 10px;
margin: -5px;
}
QSlider::add-page:horizontal{
background: rgb(189, 189, 189);
}
QSlider::sub-page:horizontal{
background: rgb(80, 165, 245);
}
二、绘制刻度
QSlider默认设置了样式表后不能显示刻度,所以要自己重写paintEvent来绘制。
用QSlider派生一个自定义控件类。
class Slider : public QSlider
{
Q_OBJECT
public:
explicit Slider(QWidget *parent = nullptr);
~Slider();
void addScale(int value);
private:
Ui::Slider *ui;
QVector<int> m_scales; //刻度列表
protected:
void paintEvent(QPaintEvent *event) override;
};
函数实现。
void Slider::addScale(int value)
{
m_scales << value;
}
void Slider::paintEvent(QPaintEvent *event)
{
QSlider::paintEvent(event); //绘制滑动条
/* 设置刻度路径 */
QPainterPath path; //刻度路径
QPainterPath textPath; //刻度值的文字路径
int length = width();
int centerY = height() / 2.0; //Y方向上的中点
double eachValueSpan = (double)length / (maximum() - minimum());
for (int value : m_scales) {
int x = eachValueSpan * (value - minimum());
/* 添加刻度 */
path.moveTo(x, centerY);
path.lineTo(x, centerY - 4);
/* 添加刻度值 */
QString text = QString::number(value);
int textWidth = fontMetrics().width(text);
int textheight = fontMetrics().height();
textPath.addText(x - textWidth / 2.0, height() - textheight / 2.0, font(), text);
}
/* 绘制路径 */
QPainter painter(this);
QPen pen;
pen.setColor(Qt::gray);
pen.setWidth(2);
painter.setPen(pen);
painter.drawPath(path);
pen.setColor(Qt::black);
pen.setWidth(1);
painter.setPen(pen);
painter.drawPath(textPath);
}
三、偏移问题
使用以上代码后会发现,刻度存在偏移,我们看回第一节样式设置。
QSlider::groove:horizontal {
border: 1px solid gray;
height: 2px;
left: 8px;
right: 8px;
}
...
为了留出空间给圆形滑块,把滑动条中间的沟槽左边和右边都偏移了8px,而绘制刻度的时候没有将它考虑进去,那么怎么在代码中获取到偏移量呢?
Qt的样式绘制都是通过QStyle及其类实现的,查看源码qcommonstyle.cpp。
可以看到,使用subControlRect,传入CC_Slider、SC_SliderHandle、SC_SliderGroove能拿到滑动条各部件的尺寸和位置。
对第二节的代码进行修改。
void Slider::paintEvent(QPaintEvent *event)
{
QSlider::paintEvent(event);
/* 设置刻度路径 */
QPainterPath path; //刻度路径
QPainterPath textPath; //刻度值的文字路径
QStyleOptionSlider option;
initStyleOption(&option);
auto r = style()->proxy()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, this);
int startX = r.x(); //进度条起始位置的x坐标
int centerY = r.y(), length = r.width() - 1;
double eachValueSpan = (double)length / (maximum() - minimum());
for (int value : m_scales) {
int x = startX + eachValueSpan * (value - minimum());
/* 添加刻度 */
path.moveTo(x, centerY);
path.lineTo(x, centerY - 4);
/* 添加刻度值 */
QString text = QString::number(value);
int textWidth = fontMetrics().width(text);
int textheight = fontMetrics().height();
textPath.addText(x - textWidth / 2.0, height() - textheight / 2.0, font(), text);
}
/* 绘制路径 */
QPainter painter(this);
QPen pen;
pen.setColor(Qt::gray);
pen.setWidth(2);
painter.setPen(pen);
painter.drawPath(path);
pen.setColor(Qt::black);
pen.setWidth(1);
painter.setPen(pen);
painter.drawPath(textPath);
}
最终显示正确的刻度。
总结
以后需要自绘控件时,可以参考QCommonStyle的实现。