QT SpinBox 浮点数千分位显示,选择某一位进行步进

该组件继承 QDoubleSpinBox,显示数据以空格作为千分位分隔符,每三位一个空格。同时支持对任意位进行步进。
目前未支持组合键shift多选。

.h

#ifndef SEPARATOR3DOUBLESPINBOX_H
#define SEPARATOR3DOUBLESPINBOX_H

#include <QDoubleSpinBox>
#include <QLineEdit>
#include <QWidget>
#include <QKeyEvent>
#include <QString>

/*
class Separator3LineEdit : public QLineEdit{
    Q_OBJECT
    Separator3LineEdit(QWidget *parent = nullptr);
    ~Separator3LineEdit();
};
*/
class Separator3DoubleSpinBox : public QDoubleSpinBox
{
    Q_OBJECT
public:
    Separator3DoubleSpinBox(QWidget *parent = nullptr);
    ~Separator3DoubleSpinBox();

    QValidator::State validate(QString &input, int &pos) const;
    QString textFromValue(double value) const;
    double valueFromText(const QString &text) const;
signals:
    void valueStep(double value);   // 参数步进信号
protected:
    // void valueChanged(const QString &);
    void keyPressEvent(QKeyEvent *event);
private:
    QLineEdit *linEditor;
};


class Separator3LinEdit : public QLineEdit
{
    Q_OBJECT
public:
    Separator3LinEdit(QWidget *parent = nullptr);
    ~Separator3LinEdit();

protected:
    void mousePressEvent(QMouseEvent *event);
private:
};

#endif // SEPARATOR3DOUBLESPINBOX_H

.cpp

#include "separator3doublespinbox.h"

#include <qspinbox.h>

#include <qlineedit.h>
#include <qlocale.h>
#include <qvalidator.h>
#include <qdebug.h>

#include <algorithm>
#include <cmath>
#include <float.h>


Separator3DoubleSpinBox::Separator3DoubleSpinBox(QWidget *parent): QDoubleSpinBox(parent)
{
    linEditor = new Separator3LinEdit(this);
    setLineEdit(linEditor);
}

Separator3DoubleSpinBox::~Separator3DoubleSpinBox(){

}

void Separator3DoubleSpinBox::keyPressEvent(QKeyEvent *event){
    if ( !hasFocus() )
    {
        return;
    }
    int key = event->key();
    QString str = this->text();
    int pos = 0, posPt = 0, subPt = 0, epow = 0, mark = 0, cursorStep = 0;
    double step = 0;
    double tempv = 0;
    pos = this->lineEdit()->cursorPosition();
    qDebug() << str << " " << pos;

    switch ( key )
    {
    case Qt::Key_Left:
        mark = event->modifiers() == Qt::ShiftModifier? 1:0;
        if(mark){
            if(pos > 0 && (str[pos - 1] == ' ' || str[pos - 1] == '.')){    // 防止越界
                this->lineEdit()->cursorBackward(mark, 1);
            }
            this->lineEdit()->cursorBackward(mark, 1);
        }
        else {
            this->lineEdit()->cursorBackward(mark, 1);
            pos -= pos>1? 1:0;              // 防止越界
            if(pos > 0 && (str[pos - 1] == ' ' || str[pos - 1] == '.')){    // 防止越界
                this->lineEdit()->cursorBackward(mark, 1);
            }
        }
        return;
    case Qt::Key_Right:
        mark = event->modifiers() == Qt::ShiftModifier? 1:0;
        cursorStep = mark ? 2:1;
        this->lineEdit()->cursorForward(mark, 1);
        pos += pos <= str.length() ? 1:0;
        if(str[pos - 1] == ' ' || str[pos - 1] == '.'){
            this->lineEdit()->cursorForward(mark, 1);
        }
        return;
    // 重写控制步进方式 stepby,但是不能 shift 步进
    case Qt::Key_Up:
    case Qt::Key_Down:
        posPt = str.indexOf('.');
        subPt = posPt - pos;
        epow = subPt >= 0? subPt - subPt/4 : subPt - (subPt + 1)/4 + 1;
        step = key == Qt::Key_Up?pow(10, epow):-pow(10, epow);

        tempv = this->value() + step;
        this->setValue(tempv);

        // 应对参数整数部分进位退位,重定位光标
        str = this->textFromValue(this->value());
        posPt = str.indexOf('.');
        pos = posPt - subPt;
        this->lineEdit()->setCursorPosition(pos);

        emit(valueStep(step));
        return;
    case Qt::Key_Enter:     // 右回车
    case Qt::Key_Return:    // 左回车
        this->clearFocus();
        this->setFocus();
        this->selectAll();
        emit(valueStep(step));
        return;

    default:
        break;
    }

    QDoubleSpinBox::keyPressEvent(event);
}


QString Separator3DoubleSpinBox::textFromValue(double value) const{
    QString str = locale().toString(value, 'f', this->decimals());
    if (!this->isGroupSeparatorShown() && qAbs(value) >= 1000.0)
        str.remove(locale().groupSeparator());

    QString str1 = str.section('.',0,0);
    QString str2 = str.section('.',1,1);
    int i = 0;

    for (i = str1.length()-3; i > 3 ; i -= 3)
        str1.insert( i, " ");
    if(i>0 && str1[i-1]!='-'){      // 符号不插入分隔符
        str1.insert( i, " ");
    }

    for (i = 3 ; i < str2.length(); i += 3)
    {
        str2.insert( i, " ");
        ++i;
    }

    str = str1 + "." + str2;

    return str;
}



double Separator3DoubleSpinBox::valueFromText(const QString &text) const
{
    QString copy = text;
    copy.remove(QRegExp("\\s"));
    double res = QDoubleSpinBox::valueFromText(copy);
    return res;
}

// 任意输入都会触发对lineedit中的字符串进行合法检查。屏蔽空格分隔符
QValidator::State Separator3DoubleSpinBox::validate(QString &input, int &pos) const{
    QString copy = input;
    if (copy.indexOf("  ")>=0){  // 不允许出现连续空格分隔符
        input.remove(copy.indexOf("  "), 1);
        pos += pos > copy.indexOf("  ")? -1:0;
        // return QValidator::State::Invalid;
    }
    copy.remove(QRegExp("\\s"));    //屏蔽空格
    QValidator::State res = QDoubleSpinBox::validate(copy, pos);
    return res;
}


Separator3LinEdit::Separator3LinEdit(QWidget *parent): QLineEdit(parent){

}

Separator3LinEdit::~Separator3LinEdit(){

}


void Separator3LinEdit::mousePressEvent(QMouseEvent *event){
    //获得当前鼠标位置
    int cursor_pos = this->cursorPositionAt(event->pos()), mark = 0;
    QString str = this->text();
    qDebug()<<str << " " << cursor_pos;
    QLineEdit::mousePressEvent(event);

    if (event->modifiers() == Qt::ShiftModifier){
        mark = 1;
    }
    if(cursor_pos > 0 && (str[cursor_pos - 1] == ' ' || str[cursor_pos - 1] == '.')){    // 防止越界
        if(!mark){
            this->cursorBackward(0, 1);
        }
    }
}


  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值