一、理论概述(略,百度大把)
二、实现效果
三、实现过程:
方法1:派生与类QSlider实现。
**样式设置(可以用setSytlesheeet在构造函数实现,这里直接写下样式里偷懒一下)
QSlider::groove:horizontal {
border: 1px solid gray;
height: 2px;
left: 8px;
right: 8px;
}
QSlider::handle:horizontal {
border: 1px solid gray;
background:white;
border-radius: 10px;
width: 20px;
height:20px;
margin: -10px;
}
QSlider::add-page:horizontal{
background: rgb(189, 189, 189);
}
QSlider::sub-page:horizontal{
background: rgb(0, 0, 255);
}
具体实现代码如下:
*************************************.h*******************************
#ifndef SCROLLBAR_H
#define SCROLLBAR_H
#include <QWidget>
#include<QSlider>
#define DEF_MIN_RANGE 80
#define DEF_MAX_RANGE 100
class scrollBar
{
Q_OBJECT
public:
scrollBar(QWidget *parent = nullptr);
scrollBar();
addScale(int value);
setupView();
signals:
protected:
paintEvent(QPaintEvent *event) override;
private:
QVector<int> m_scales; //刻度列表
};
#endif // SCROLLBAR_H
*************************************.cpp*******************************
#include "scrollbar.h"
#include<QLabel>
#include<QSlider>
#include<QPainter>
#include<QPen>
#include <QStyleOptionSlider>
#include<QColor>
#include<QBrush>
scrollBar::scrollBar(QWidget *parent) : QSlider(parent)
{
// setupView();
m_scales.push_back(5);
m_scales.push_back(10);
m_scales.push_back(15);
m_scales.push_back(20);
m_scales.push_back(25);
m_scales.push_back(30);
m_scales.push_back(35);
m_scales.push_back(40);
}
scrollBar::~scrollBar()
{
}
setupView()
{
//设置水平还是垂直滑动条,默认为垂直
this->setOrientation(Qt::Horizontal);
// for(int num = 0 ;num<10;num++)
// {
// QLabel *point = new QLabel(this);
// point->setFixedSize(30, 30);
// //穿透属性:如果滑动条与刻度点重合,当你点击滑动条的时候,防止按压到刻度点,所以给刻度点设置穿透属性,你只能点击到滑动条。
// point->setAttribute(Qt::WA_TransparentForMouseEvents, true);
// point->setStyleSheet("background-color: rgb(91, 154, 212);"
// "border-radius: 15px;");
// //point->set
// point->move(30*(num+1)+30*num, 70);
// }
//设置范围
/*
this->setRange(DEF_MIN_RANGE, DEF_MAX_RANGE);
setFocusPolicy(Qt::StrongFocus);
//键盘左右键的步进值
this->setSingleStep(1);
//鼠标点击的步进值
this->setPageStep(5);
for(int num = 0 ;num<10;num++)
{
QLabel *point = new QLabel(this);
point->setFixedSize(30, 30);
//穿透属性:如果滑动条与刻度点重合,当你点击滑动条的时候,防止按压到刻度点,所以给刻度点设置穿透属性,你只能点击到滑动条。
point->setAttribute(Qt::WA_TransparentForMouseEvents, true);
point->setStyleSheet("background-color: rgb(91, 154, 212);"
"border-radius: 15px;");
//point->set
point->move(30*(num+1)+30*num, 70);
}
*/
//this->set ->setTickPosition(QSlider::TicksAbove);
//this->setStyleSheet("background:rgb(20,20,20,90%);");
//add begin
/*
this->setStyleSheet("QScrollBar:horizontal {\
border: 0px solid grey;\
border-radius:10px;\
background: #2c3e50;\
height: 15px;\
margin: 0px 20px 0 20px;\
}\
QScrollBar::handle:horizontal{\
background: #FFFFFF;\
border-radius: 15px;\
min-width:30px;\
}\
QScrollBar::add-page,\
QScrollBar::sub-page{\
background: transparent;\
}\
QScrollBar::add-line:horizontal {\
border: 0px solid grey;\
border-radius:10px;\
background: #2c3e50;\
width: 0px;\
subcontrol-position: right;\
subcontrol-origin: margin;\
}\
QScrollBar::sub-line:horizontal {\
border: 0px solid grey;\
border-radius:10px;\
background: rgb(20,20,20,90%);\
width: 0px;\
subcontrol-position: left;\
subcontrol-origin: margin;\
}\
QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal{\
border: 1px solid grey;\
width: 3px;\
height: 3px;\
background:rgb(20,20,20,90%);\
}\
QScrollBar::add-page:horizontal {\
background:rgba(146,186,255,0.8);\
}\
QScrollBar::sub-page:horizontal {\
background:rgba(22,93,255,1);\
}\
");
//add end
*/
}
void scrollBar::paintEvent(QPaintEvent *event)
{
event);
/* 设置刻度路径 */
QPainterPath path; //刻度路径
QPainterPath textPath; //刻度值的文字路径
QPainterPath shortPath;
pos{
QPointF circlePos;
unsigned char drawType;
};
QVector<pos> scirclePos;
scirclePos.clear();
QStyleOptionSlider option;
&option);
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());
//add begin
path.moveTo(startX, centerY+13);
path.lineTo(startX, centerY + 20);
QString text = QString::number(0);
int textWidth = fontMetrics().width(text);
int textheight = fontMetrics().height();
textPath.addText(startX - textWidth / 2.0, height() - textheight / 2.0, font(), text);
textPath.addText(startX - textWidth / 2.0, height() - textheight / 2.0, font(), text);
float fInterval = eachValueSpan*5.0/5;
//add end
for (int value : m_scales) {
int x = startX + eachValueSpan * (value - minimum());
for(int segment = 0 ;segment<4;segment++)
{
shortPath.moveTo(x-(segment+1)*fInterval,centerY+13) ;
shortPath.lineTo(x-(segment+1)*fInterval,centerY+15);
qDebug("x = %i",(int)(x-(segment+1)*fInterval));
}
/* 添加刻度 */
path.moveTo(x, centerY+13);
path.lineTo(x, centerY + 20);
int tmpValue = this->value();
pos tmpPos;
tmpPos.circlePos.setX(x);
tmpPos.circlePos.setY(centerY+20);
if(value==tmpValue)
{
tmpPos.drawType = 0x01 ;
}else if(value <tmpValue)
{
tmpPos.drawType = 0x02;
}
else
{
tmpPos.drawType = 0 ;
}
scirclePos.push_back(tmpPos);
/* 添加刻度值 */
// QString text = QString::number(value);
// int textWidth = fontMetrics().width(text);
// int textheight = fontMetrics().height();
text = QString::number(value);
textWidth = fontMetrics().width(text);
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.setWidth(1);
painter.setPen(pen);
painter.drawPath(shortPath);
pen.setColor(Qt::black);
pen.setWidth(1);
painter.setPen(pen);
painter.drawPath(textPath);
pen.setWidth(1);
pen.setColor(Qt::blue);
QBrush brush;
brush.setColor(QColor(189, 189, 189,1));
painter.setBrush(Qt::blue);//设置画刷,如果不画实现的直接把Brush设置为setBrush(Qt::NoBrush);
painter.setPen(pen);
//painter.setBrush(brush);
//painter.setPen(pen);
// painter.setBrush(brush);
painter.drawEllipse(startX-5,centerY-3,10,10);
for(int n = 0 ;n<scirclePos.size();n++)
{
pen.setWidth(1);
pen.setColor(Qt::gray);
//brush.setColor(QColor(189, 189, 189,1));
painter.setBrush(Qt::gray);//设置画刷,如果不画实现的直接把Brush设置为setBrush(Qt::NoBrush);
painter.setPen(pen);
if(scirclePos.at(n).drawType == 0x01)
{
continue;
// pen.setWidth(1);
// pen.setColor(Qt::blue);
// //brush.setColor(QColor(189, 189, 189,1));
// painter.setBrush(Qt::blue);//设置画刷,如果不画实现的直接把Brush设置为setBrush(Qt::NoBrush);
// painter.setPen(pen);
}
if(scirclePos.at(n).drawType == 0x02)
{
pen.setWidth(1);
pen.setColor(Qt::blue);
//brush.setColor(QColor(189, 189, 189,1));
painter.setBrush(Qt::blue);//设置画刷,如果不画实现的直接把Brush设置为setBrush(Qt::NoBrush);
painter.setPen(pen);
}
painter.drawEllipse(scirclePos.at(n).circlePos.x()-5,scirclePos.at(n).circlePos.y()-3-20,10,10);
}
}
方法二:利用继承于QScrollBar实现
实现思想:在QPainter中动态生成QLabel,然后通过控件的组合拼装。
*******************.H************************************************
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
MainWindow();
private:
QList<QRect> rectList;
int showSize=20; //页面显示20位
float scale=1;
QPoint m_clickPoint;
bool m_bClick=false;
protected:
paintEvent(QPaintEvent *event);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
*************************************************.cpp************************************************
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QLabel>
#include<QPainter>
MainWindow::MainWindow(QWidget *parent)
parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->resize(800,600);
ui->horizontalScrollBar->move(20,80);
int k=0;
int i_size=(this->width()/showSize);
for(int i=0;i<100;i++) //创建100个数字
{
QRect rect(k,100,0.1,10);
rectList.append(rect);
k=k+i_size;
}
//QLabel充当刻度点
for(int num = 0 ;num<10;num++)
{
QLabel *point = new QLabel(this);
point->setFixedSize(30, 30);
//穿透属性:如果滑动条与刻度点重合,当你点击滑动条的时候,防止按压到刻度点,所以给刻度点设置穿透属性,你只能点击到滑动条。
point->setAttribute(Qt::WA_TransparentForMouseEvents, true);
point->setStyleSheet("background-color: rgb(91, 154, 212);"
"border-radius: 15px;");
point->move(30*(num+1)+30*num, 70);
}
// //QLabel充当刻度点
// QLabel *point1 = new QLabel(this);
// point->setFixedSize(6, 6);
// //穿透属性:如果滑动条与刻度点重合,当你点击滑动条的时候,防止按压到刻度点,所以给刻度点设置穿透属性,你只能点击到滑动条。
// point1->setAttribute(Qt::WA_TransparentForMouseEvents, true);
// point1->setStyleSheet("background-color: rgb(91, 154, 212);"
// "border-radius: 3px;");
// point1->move(100, 100);
// QLabel *point3 = new QLabel(this);
// point3->setFixedSize(QSize(25,25));
// point3->setStyleSheet("background-color: white;"
// "color: black;");
// point3->setAlignment(Qt::AlignCenter);
// point3->setText("1");
// point3->setVisible(true);
// point3->move(150, 150);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
int K=0; //设置值显示的位置
for(int i=0;i<rectList.size();i++)
{
float value = qRound(showSize+(i-showSize)*scale);
if(value<0||value>100) //100和0分别为最大值和最小值
{
continue ;
}
painter.drawRect(rectList[K]);
QString strValue = tr("%1").arg(value);
int fontWidth = fontMetrics().width(strValue)/2;
painter.drawText(QPointF(rectList[K].x()-fontWidth,125/*7+15*/),strValue);
K++;
// painter.drawRect(rectList[i]);
// QString strValue = tr("%1").arg(value);
// int fontWidth = fontMetrics().width(strValue)/2;
// painter.drawText(QPointF(rectList[i].x()-fontWidth,7+15),strValue);
}
}
备注:首先要在桌面上拖入QScrollBar控件