一、理论概述(略,百度大把)

二、实现效果




QStandardItemModel设置选中行_c语言


三、实现过程:

方法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控件