该组件继承 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);
}
}
}