Qt自定义滑动条

2023-11-17

最近要用到滑动条,Qt自带的QSlider虽然能满足需求,但是操作起来有很多不舒服的地方,于是在它的基础上改了改,分享给大家使用。

  1. 先放效果图:
    silder

在QSlider的基础上,改变了样式,绘制了刻度,增加了取整功能,只需要微调就能适应各种需求。

  1. 头文件。需要包含下面的东西
#include <QSlider>
#include <QtCore>
#include <QStylePainter>
#include <QStyleOptionSlider>
#include <QMouseEvent>
  1. 声明。需要继承QSlider,并重写两个鼠标事件mousePressEvent和mouseReleaseEvent,使用paintEvent用来绘制刻度线,使用信号发送选中的数值。
class MySlider : public QSlider
{
    Q_OBJECT
public:
    MySlider(QWidget *parent = nullptr);
    ~MySlider();

signals:
    void sliderValue(float);

private:
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *ev);
};
  1. 构造函数。首先在构造函数中配置控件的相关属性,在此宏定义的几个数值:nMin和nMax代表取值范围,nSingleStep代表步长,nTick代表刻度间隔,nWidth和nHeight控制控件的大小。通过设置Orientation为Horizontal,使控件为横向。
#include "myslider.h"

int nMin = 0;
int nMax = 100;
int nSingleStep = 10;
int nTick = 10;     //修改刻度个数改此数值
int nWidth = 200;
int nHeight = 50;

MySlider::MySlider(QWidget *parent):
    QSlider (parent)
{
    setOrientation(Qt::Horizontal);
    setFixedSize(nWidth,nHeight);
    setMinimum(nMin);
    setMaximum(nMax);
    setSingleStep(nSingleStep);
    setTickInterval(nTick);
    setTickPosition(QSlider::TicksAbove);
  1. 设置样式表。QSlider::groove控制背景样式,QSlider::handle控制滑块样式,QSlider::sub-page控制划过区域的样式。需要注意的是,qss和QSlider自带的刻度线并不兼容,使用qss就不能显示自带的刻度线了,但是后文我提供了解决方法。
setStyleSheet("QSlider::groove:horizontal{height:12px; left:0px; right:0px; border:0px; border-radius:6px; background:rgb(242,242,242);}    \
               QSlider::handle:horizontal{width:24px; background:#1644B0; border-radius:12px; margin:-6px 0px;}  \
               QSlider::sub-page:horizontal{background:#4C85FB; border:0px; border-radius:6px;}");
}
  1. 重写鼠标点击事件。之所以要这么做,是因为QSlider的点击效果是一格一格地移动,我希望滑块能直接跳到指定位置,所以需要用到setValue。
void MySlider::mousePressEvent(QMouseEvent * event)
{
    int pointPos = ((double)event->pos().x()) / (this->width() * (nMax - nMin) + nMin);
    if(pointPos != 0){
        if(abs(pointPos - this->value()) > nTick){
            this->setValue(pointPos);
        }
    }
    else{
        QSlider::mousePressEvent(event);
    }
}
  1. 重写鼠标释放事件。因为希望取值可以取几个固定的值,此处限定只能取0, 0.1, 0.2… 1这些值,所以在释放时对当前值四舍五入,然后让滑块移动到相应的位置。最后发出信号传递数值。
void MySlider::mouseReleaseEvent(QMouseEvent *event)
{
    //获取当前点击位置
    int currentX = event->pos().x();

    //获取当前点击的位置占整个Slider的百分比
    float per = currentX *1.0 /this->width();

    //限制边界
    if(per > 1) per = 1;
    else if(per < 0) per = 0;

    //按步长取整
    per = (float)(qRound(per * 100 / nTick) * nTick) / 100;

    //利用算得的百分比得到具体数字
    int value = per*(this->maximum() - this->minimum()) + this->minimum();

    //设定滑动条位置
    this->setValue(value);

    //滑动条移动事件等事件也用到了mousePressEvent,加这句话是为了不对其产生影响,是的Slider能正常相应其他鼠标事件
    QSlider::mousePressEvent(event);

    emit sliderValue(per);
}
  1. 绘制刻度。前文提到了qss和QSlider刻度的冲突,所以这里我们直接使用paintEvent画线。修改宏定义的参数值,刻度的数量也会随之变动。
void MySlider::paintEvent(QPaintEvent *)
{
    QStylePainter p(this);
    QStyleOptionSlider opt;
    initStyleOption(&opt);

    // 获取滑块的大小
    QRect handle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);

    // draw tick marks
    // do this manually because they are very badly behaved with style sheets
    int interval = tickInterval();
    if (interval == 0)
    {
        interval = pageStep();
    }

    if (tickPosition() != NoTicks)
    {
        for (int i = minimum(); i <= maximum(); i += interval)
        {
            int x = round((double)((double)((double)(i - this->minimum()) / (double)(this->maximum() - this->minimum())) * (double)(this->width() - handle.width()) + (double)(handle.width() / 2.0))) - 1;
            int h = 4;
            p.setPen(QColor("#a5a294"));
            if (tickPosition() == TicksBothSides || tickPosition() == TicksAbove)
            {
                int y = this->rect().top();
                p.drawLine(x, y, x, y + h);
            }
            if (tickPosition() == TicksBothSides || tickPosition() == TicksBelow)
            {
                int y = this->rect().bottom();
                p.drawLine(x, y, x, y - h);
            }
    }
        }
    // draw the slider (this is basically copy/pasted from QSlider::paintEvent)
    opt.subControls = QStyle::SC_SliderGroove;
    p.drawComplexControl(QStyle::CC_Slider, opt);
    // draw the slider handle
    opt.subControls = QStyle::SC_SliderHandle;
    p.drawComplexControl(QStyle::CC_Slider, opt);
}
  1. 实际使用。拖动或点击滑动条都会发出信号,传递滑块对应的值。所以在要使用的地方建立信号槽,就可以接收对应滑动条传来的值并加以处理。
		FaceThreshSlider = new MySlider(this);
        connect(FaceThreshSlider, SIGNAL(sliderValue(float)), this, SLOT(setSlideThresh(float)));

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt自定义滑动条 的相关文章

随机推荐

  • VSCode提高代码开发效率插件:(一)差异对比插件

    写代码经常会用到代码对比的功能 以前常用独立的软件Merge Vscode中也有类似功能的插件 之前开发单片机一直用的Keil 但是用Keil编译去掉BroseInformation速度提上来了但是没法函数跳转了 Vscode可以解决这个问
  • 如何在VS 2017运行别人的C语言代码

    如何在VS 2017运行别人的C语言代码 我们在使用VS 2017的时候 只有C 项目没有C项目 如何运行从网上下载的别人的C语言项目代码呢 经过查找资料后 经过如下具体步骤 便能在VS 2017里运行C程序了 目录 如何在VS 2017运
  • ubuntu1804安装python3.8+odoo14

    如题 博主废了不少劲 折腾了一个上午终于搞定了 本次采用环境是ubuntu1804系统的docker容器 并且容器内部已更换阿里源 编辑阿里源 vi etc apt sources list 然后粘贴下面内容 再保存 deb http mi
  • 打印图像模糊问题解决方法

    思路 核心 图像转换 1 修改图像dpi值 2 使用高质量的双三次插值法 3 指定高质量 C Code 如下
  • 期货交易的主要特征(期货交易特征五大特征)

    期货交易的特点有哪些 一 合约标准化 期货交易是通过买卖期货合约进行的 而期货合约是标准化的 期货合约标准化指的是除价格外 期货合约的所有条款都是预先由期货交易所规定好的 具有标准化的特点 二 交易集中化 期货交易必须在期货交易所内进行 期
  • NGINX代理导致 获取不到请求头中的token信息

    原因 NGINX对header有所限制 下划线 不支持 解决方式1 请求头参数不用带下划线参数 解决方式2 在nginx里的nginx conf配置文件中的http部分中添加如下配置 underscores in headers on 默认
  • 生信人的20个R语言习题

    生信人的20个R语言习题 题目原文 http www bio info trainee com 3409 html 参考答案 https www jianshu com p dd4e285665e1 https www jianshu co
  • 多变量处理的LASSO方法

    1 lasso方法 其中 因变量是Y 自变量是X 数据中的变量众多 但如何选择X 就使用了lasso lasso能够对变量进行筛选和对模型的复杂程度进行降低 这里的变量筛选是指不把所有的变量都放入模型中进行拟合 而是有选择的把变量放入模型从
  • Longest Common Substring

    给出两个字符串 找到最长公共子串 并返回其长度 注意事项 子串的字符应该连续的出现在原字符串中 这与子序列有所不同 Lintcode上的一道题目 非常经典 需要找到最长的连续公共子串的长度 因为有两个序列且前后顺序不可以打乱 所以为双序列问
  • ESP8266基础开发(一)---读DHT11温湿度传感器

    注 对于ESP8266开源技术感兴趣的可以加群 我们一起探索交流学习 群号 579932824 群名 ESP8266开源技术交流群 这篇文章的目的是展示如何将DHT11传感器连接到ESP8266并编写一个简单的程序来测量温度和湿度 我们假设
  • 【Git】保姆级教程:如何在 GitHub 上传大文件(≥100M)?(含自己的操作流程)

    文章目录 一 问题导读 二 自己的实际操作流程 2 1 准备工作 2 2 初始化仓库 2 3 安装git lfs 一个仓库里面执行一次就好了 2 4 跟踪一下你要上传 push 的文件或指定文件类型 2 5 添加 gitattributes
  • FPGA开发流程

    流程 设计定义 设计输入 分析和综合 功能仿真 modelsim altera 布局布线 时序仿真 modelsim altera 时序约束 IO分配以及配置文件的生成 配置 烧写FPGA 在线调试 设计定义 二选一多路器 两个输入IO a
  • Amazon SDE实习机会面试经验分享

    我通过大学申请了Amazon SDE实习 在线回合 有一个在线回合 其中包含技术性MCQ和2个编码问题 编码部分非常简单 面试过程中有7 8人入围 第一轮面对面访谈 这一回合持续了一个小时 首先 面试官要求自我介绍 后来有3个编码问题 对包
  • HTML img 强制刷新加载

    img刷新机制为url变化则刷新 当url不变时想要刷新可做如下处理 let url http pic27 nipic com 20130321 9678987 225139671149 2 jpg const time new Date
  • 浏览器默认行为(原生事件)、浏览器中网页渲染顺序

    一 浏览器的原生事件 1 浏览器中存在一些默认行为 比如 文本可复制 图片可 拖拽 这是伪拖拽 实际并没有移动 松开鼠标后 会弹出新的链接 右键会出现菜单 a标签单击会跳转等 2 为什么要阻止默认行为 如某些时候 我们需要写一个a标签 但是
  • docker的联合文件系统(UnionFS)

    docker最大的贡献就是定义了容器镜像的分层的存储格式 docker镜像技术的基础是联合文件系统 UnionFS 其文件系统是分层的 这样既可以充分利用共享层 又可以减少存储空间占用 联合挂载系统的工作原理 读 如果文件在upperdir
  • vue常用标签

    一 内容绑定 1 v text 会替换掉html的内容 eg p p 2 插值表达式占位内容 放在html中 eg p username p 3 v html 可将html内容渲染到页面 v text和 不支持 eg div div con
  • 用于通过声波捕获显示视觉,触觉和音频的全息显示(A volumetric display for visual, tactile and audio presentation using acous)

    Ryuji Hirayama Diego Martinez Plasencia Nobuyuki Masuda Sriram Subramanian 2019年1月31日接收 2019年8月15日收录 2019年11月13日网上公开 摘要
  • java token redis生成算法_java秒杀系列(1)- 秒杀方案总体思路

    前言 首先 要明确一点 高并发场景下系统的瓶颈出现在哪里 其实主要就是数据库 那么就要想办法为数据库做层层防护 减轻数据库的压力 一 简单图示 我用一个比较简单直观的图来表达大概的处理思路 二 生产环境中秒杀抢购的解决方案 1 前端 1 动
  • Qt自定义滑动条

    最近要用到滑动条 Qt自带的QSlider虽然能满足需求 但是操作起来有很多不舒服的地方 于是在它的基础上改了改 分享给大家使用 先放效果图 在QSlider的基础上 改变了样式 绘制了刻度 增加了取整功能 只需要微调就能适应各种需求 头文