📄 qspinbox.cpp
字号:
if (number == max) // needed for INT_MAX break; } return false;}/*! \internal Multi purpose function that parses input, sets state to the appropriate state and returns the value it will be interpreted as.*/QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, QValidator::State &state) const{ if (cachedText == input && !input.isEmpty()) { state = cachedState; QSBDEBUG() << "cachedText was" << "'" << cachedText << "'" << "state was " << state << " and value was " << cachedValue; return cachedValue; } const int max = maximum.toInt(); const int min = minimum.toInt(); QString copy = stripped(input, &pos); QSBDEBUG() << "input" << input << "copy" << copy; state = QValidator::Acceptable; int num = min; if (max != min && (copy.isEmpty() || (min < 0 && copy == QLatin1String("-")) || (min >= 0 && copy == QLatin1String("+")))) { state = QValidator::Intermediate; QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num; } else if (copy.startsWith(QLatin1String("-")) && min >= 0) { state = QValidator::Invalid; // special-case -0 will be interpreted as 0 and thus not be invalid with a range from 0-100 } else { bool ok = false; bool removedThousand = false; num = QLocale().toInt(copy, &ok, 10); if (!ok && copy.contains(thousand) && (max >= 1000 || min <= -1000)) { const int s = copy.size(); copy.remove(thousand); pos = qMax(0, pos - (s - copy.size())); removedThousand = true; num = QLocale().toInt(copy, &ok, 10); } QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num; if (!ok) { state = QValidator::Invalid; } else if (num >= min && num <= max) { state = removedThousand ? QValidator::Intermediate : QValidator::Acceptable; } else if (max == min) { state = QValidator::Invalid; } else { if ((num >= 0 && num > max) || (num < 0 && num < min)) { state = QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; } else { state = isIntermediateValue(copy) ? QValidator::Intermediate : QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to " << (state == QValidator::Intermediate ? "Intermediate" : "Acceptable"); } } } if (state != QValidator::Acceptable) num = max > 0 ? min : max; input = prefix + copy + suffix; cachedText = input; cachedState = state; cachedValue = QVariant((int)num); QSBDEBUG() << "cachedText is set to '" << cachedText << "' state is set to " << state << " and value is set to " << cachedValue; return cachedValue;}// --- QDoubleSpinBoxPrivate ---/*! \internal Constructs a QSpinBoxPrivate object*/QDoubleSpinBoxPrivate::QDoubleSpinBoxPrivate(){ minimum = QVariant(0.0); maximum = QVariant(99.99); value = minimum; singleStep = QVariant(1.0); decimals = 2; type = QVariant::Double; const QString str = QLocale().toString(4567.1); if (str.size() == 6) { delimiter = str.at(4); thousand = QChar((ushort)0); } else if (str.size() == 7) { thousand = str.at(1); delimiter = str.at(5); } Q_ASSERT(!delimiter.isNull());}/*! \internal \reimp*/void QDoubleSpinBoxPrivate::emitSignals(EmitPolicy ep, const QVariant &old){ Q_Q(QDoubleSpinBox); if (ep != NeverEmit) { pendingEmit = false; if (ep == AlwaysEmit || value != old) { emit q->valueChanged(edit->displayText()); emit q->valueChanged(value.toDouble()); } }}bool QDoubleSpinBoxPrivate::isIntermediateValue(const QString &str) const{ QSBDEBUG() << "input is" << str << minimum << maximum; qint64 dec = 1; for (int i=0; i<decimals; ++i) dec *= 10; const QLatin1Char dot('.'); // I know QString::number() uses CLocale so I use dot const QString minstr = QString::number(minimum.toDouble(), 'f', decimals); qint64 min_left = minstr.left(minstr.indexOf(dot)).toLongLong(); qint64 min_right = minstr.mid(minstr.indexOf(dot) + 1).toLongLong(); const QString maxstr = QString::number(maximum.toDouble(), 'f', decimals); qint64 max_left = maxstr.left(maxstr.indexOf(dot)).toLongLong(); qint64 max_right = maxstr.mid(maxstr.indexOf(dot) + 1).toLongLong(); const int dotindex = str.indexOf(delimiter); const bool negative = maximum.toDouble() < 0; qint64 left = 0, right = 0; bool doleft = true; bool doright = true; if (dotindex == -1) { left = str.toLongLong(); doright = false; } else if (dotindex == 0 || (dotindex == 1 && str.at(0) == QLatin1Char('+'))) { if (negative) { QSBDEBUG() << __FILE__ << __LINE__ << "returns false"; return false; } doleft = false; right = str.mid(dotindex + 1).toLongLong(); } else if (dotindex == 1 && str.at(0) == QLatin1Char('-')) { if (!negative) { QSBDEBUG() << __FILE__ << __LINE__ << "returns false"; return false; } doleft = false; right = str.mid(dotindex + 1).toLongLong(); } else { left = str.left(dotindex).toLongLong(); if (dotindex == str.size() - 1) { doright = false; } else { right = str.mid(dotindex + 1).toLongLong(); } } if ((left >= 0 && max_left < 0 && !str.startsWith(QLatin1Char('-'))) || (left < 0 && min_left >= 0)) { QSBDEBUG("returns false 0"); return false; } qint64 match = min_left; if (doleft && !isIntermediateValueHelper(left, min_left, max_left, &match)) { QSBDEBUG() << __FILE__ << __LINE__ << "returns false"; return false; } if (doright) { QSBDEBUG("match %lld min_left %lld max_left %lld", match, min_left, max_left); if (!doleft) { if (min_left == max_left) { const bool ret = isIntermediateValueHelper(qAbs(left), negative ? max_right : min_right, negative ? min_right : max_right); QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret; return ret; } else if (qAbs(max_left - min_left) == 1) { const bool ret = isIntermediateValueHelper(qAbs(left), min_right, negative ? 0 : dec) || isIntermediateValueHelper(qAbs(left), negative ? dec : 0, max_right); QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret; return ret; } else { const bool ret = isIntermediateValueHelper(qAbs(left), 0, dec); QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret; return ret; } } if (match != min_left) { min_right = negative ? dec : 0; } if (match != max_left) { max_right = negative ? 0 : dec; } qint64 tmpl = negative ? max_right : min_right; qint64 tmpr = negative ? min_right : max_right; const bool ret = isIntermediateValueHelper(right, tmpl, tmpr); QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret; return ret; } QSBDEBUG() << __FILE__ << __LINE__ << "returns true"; return true;}/*! \internal \reimp*/QVariant QDoubleSpinBoxPrivate::valueFromText(const QString &f) const{ Q_Q(const QDoubleSpinBox); return QVariant(q->valueFromText(f));}/*! \internal Rounds to a double value that is restricted to decimals. E.g. // decimals = 2 round(5.555) => 5.56 */double QDoubleSpinBoxPrivate::round(double value) const{ const QString strDbl = QString::number(value, 'f', decimals); return strDbl.toDouble();}/*! \internal Multi purpose function that parses input, sets state to the appropriate state and returns the value it will be interpreted as.*/QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, QValidator::State &state) const{ if (cachedText == input && !input.isEmpty()) { state = cachedState; QSBDEBUG() << "cachedText was" << "'" << cachedText << "'" << "state was " << state << " and value was " << cachedValue; return cachedValue; } const double max = maximum.toDouble(); const double min = minimum.toDouble(); QString copy = stripped(input, &pos); QSBDEBUG() << "input" << input << "copy" << copy; int len = copy.size(); double num = min; const bool plus = max >= 0; const bool minus = min <= 0; switch (len) { case 0: state = max != min ? QValidator::Intermediate : QValidator::Invalid; goto end; case 1: if (copy.at(0) == delimiter || (plus && copy.at(0) == QLatin1Char('+')) || (minus && copy.at(0) == QLatin1Char('-'))) { state = QValidator::Intermediate; goto end; } break; case 2: if (copy.at(1) == delimiter && ((plus && copy.at(0) == QLatin1Char('+')) || (minus && copy.at(0) == QLatin1Char('-')))) { state = QValidator::Intermediate; goto end; } break; default: break; } if (copy.at(0) == thousand) { QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; state = QValidator::Invalid; goto end; } else if (len > 1) { const int dec = copy.indexOf(delimiter); if (dec != -1) { if (dec + 1 < copy.size() && copy.at(dec + 1) == delimiter && pos == dec + 1) { copy.remove(dec + 1, 1); // typing a delimiter when you are on the delimiter } // should be treated as typing right arrow if (copy.size() - dec > decimals + 1) { QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; state = QValidator::Invalid; goto end; } for (int i=dec + 1; i<copy.size(); ++i) { if (copy.at(i).isSpace() || copy.at(i) == thousand) { QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; state = QValidator::Invalid; goto end; } } } else { const QChar &last = copy.at(len - 1); const QChar &secondLast = copy.at(len - 2); if ((last == thousand || last.isSpace()) && (secondLast == thousand || secondLast.isSpace())) { state = QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; goto end; } else if (last.isSpace() && (!thousand.isSpace() || secondLast.isSpace())) { state = QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; goto end; } } } { bool ok = false; QLocale loc; num = loc.toDouble(copy, &ok); QSBDEBUG() << __FILE__ << __LINE__ << loc << copy << num << ok; bool notAcceptable = false; if (!ok) { if (thousand.isPrint()) { if (max < 1000 && min > -1000 && copy.contains(thousand)) { state = QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; goto end; } const int len = copy.size(); for (int i=0; i<len- 1; ++i) { if (copy.at(i) == thousand && copy.at(i + 1) == thousand) { QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; state = QValidator::Invalid; goto end; } } const int s = copy.size(); copy.remove(thousand); pos = qMax(0, pos - (s - copy.size())); num = loc.toDouble(copy, &ok); QSBDEBUG() << thousand << num << copy << ok; if (!ok) { state = QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; goto end; } notAcceptable = true; } } if (!ok) { state = QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; } else if (num >= min && num <= max) { state = notAcceptable ? QValidator::Intermediate : QValidator::Acceptable; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to " << (state == QValidator::Intermediate ? "Intermediate" : "Acceptable"); } else if (max == min) { // when max and min is the same the only non-Invalid input is max (or min) state = QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; } else { if ((num >= 0 && num > max) || (num < 0 && num < min)) { state = QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; } else { state = isIntermediateValue(copy) ? QValidator::Intermediate : QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to " << (state == QValidator::Intermediate ? "Intermediate" : "Acceptable"); } } }end: if (state != QValidator::Acceptable) { num = max > 0 ? min : max; } input = prefix + copy + suffix; cachedText = input; cachedState = state; cachedValue = QVariant(num); return QVariant(num);}/* \internal \reimp*/QString QDoubleSpinBoxPrivate::textFromValue(const QVariant &f) const{ Q_Q(const QDoubleSpinBox); return q->textFromValue(f.toDouble());}/*! \fn void QSpinBox::setLineStep(int step) Use setSingleStep() instead.*//*! \fn void QSpinBox::setMaxValue(int value) Use setMaximum() instead.*//*! \fn void QSpinBox::setMinValue(int value) Use setMinimum() instead.*//*! \fn int QSpinBox::maxValue() const Use maximum() instead.*//*! \fn int QSpinBox::minValue() const Use minimum() instead.*//*! \internal Returns whether \a str is a string which value cannot be parsed but still might turn into something valid.*/static bool isIntermediateValueHelper(qint64 num, qint64 min, qint64 max, qint64 *match){ QSBDEBUG("%lld %lld %lld", num, min, max); if (num >= min && num <= max) { if (match) *match = num; QSBDEBUG("returns true 0"); return true; } qint64 tmp = num; int numDigits = 0; int digits[10]; if (tmp == 0) { numDigits = 1; digits[0] = 0; } else { tmp = qAbs(num); for (int i=0; tmp > 0; ++i) { digits[numDigits++] = tmp % 10; tmp /= 10; } } int failures = 0; qint64 number; for (number=max; number>=min; --number) { tmp = qAbs(number); for (int i=0; tmp > 0;) { if (digits[i] == (tmp % 10)) { if (++i == numDigits) { if (match) *match = number; QSBDEBUG("returns true 1"); return true; } } tmp /= 10; } if (failures++ == 500000) { //upper bound if (match) *match = num; QSBDEBUG("returns true 2"); return true; } } QSBDEBUG("returns false"); return false;}/*! \reimp */bool QSpinBox::event(QEvent *event){ Q_D(QSpinBox); if (event->type() == QEvent::StyleChange#ifdef Q_WS_MAC || event->type() == QEvent::MacSizeChange#endif ) d->setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem); return QAbstractSpinBox::event(event);}#endif // QT_NO_SPINBOX
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -