我尝试按照
中的建议创建一个 qspinbox64qspinbox64.h
#define QSPINBOX64_H
#include <QtGui>
#include <QtWidgets>
namespace Ui {
class QSpinBox64;
}
class QSpinBox64Private;
class Q_WIDGETS_EXPORT QSpinBox64 : public QAbstractSpinBox//QSpinBox
{
Q_OBJECT
Q_PROPERTY(int64_t minimum READ minimum WRITE setMinimum)
Q_PROPERTY(int64_t maximum READ maximum WRITE setMaximum)
Q_PROPERTY(int64_t value READ value WRITE setValue NOTIFY valueChanged USER true)
int64_t m_minimum;
int64_t m_maximum;
int64_t m_value;
public:
explicit QSpinBox64(QWidget *parent = nullptr)
{
connect(lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onEditFinished()));
}
~QSpinBox64()
{
}
int64_t value() const
{
return m_value;
}
int64_t minimum() const
{
return m_minimum;
}
int64_t maximum() const
{
return m_maximum;
}
void setMinimum(int64_t min)
{
m_minimum = min;
}
void setMaximum(int64_t max)
{
m_maximum = max;
}
void setRange(int64_t min, int64_t max)
{
setMinimum(min);
setMaximum(max);
}
virtual void stepBy(int steps)
{
auto new_value = m_value;
if (steps < 0 && new_value + steps > new_value) {
new_value = std::numeric_limits<qlonglong>::min();
}
else if (steps > 0 && new_value + steps < new_value) {
new_value = std::numeric_limits<qlonglong>::max();
}
else {
new_value += steps;
}
lineEdit()->setText(textFromValue(new_value));
setValue(new_value);
}
protected:
virtual QValidator::State validate(QString &text, int &pos) const
{
//return validator->validate(text, pos);
bool ok;
int64_t val = text.toLongLong(&ok);
if (!ok)
return QValidator::Invalid;
if (val < m_minimum || val > m_maximum)
return QValidator::Invalid;
return QValidator::Acceptable;
}
virtual int64_t valueFromText(const QString &text) const
{
bool ok;
return text.toLongLong(&ok, 10);
}
virtual QString textFromValue(int64_t value) const
{
return QString::number(value, 10).toUpper();
}
virtual QAbstractSpinBox::StepEnabled stepEnabled() const;
public
Q_SLOTS:
void setValue(int64_t val)
{
if (m_value != val) {
lineEdit()->setText(textFromValue(val));
m_value = val;
}
}
void onEditFinished()
{
QString input = lineEdit()->text();
int pos = 0;
if (QValidator::Acceptable == validate(input, pos))
setValue(valueFromText(input));
else
lineEdit()->setText(textFromValue(m_value));
}
Q_SIGNALS:
void valueChanged(int64_t v);
private:
Ui::QSpinBox64 *ui;
Q_DISABLE_COPY(QSpinBox64)
Q_DECLARE_PRIVATE(QSpinBox64)
};
#endif
主.cpp
#include <QHBoxLayout>
#include "qspinbox64.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QSpinBox64 spinBox;
spinBox.setWindowTitle(QObject::tr("QSpinBox64"));
spinBox.show();
return app.exec();
}
编译后出现错误:
G:\proj\build-qspinbox64-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug\debug\moc_qspinbox64.cpp:141:
error: C2491: 'QSpinBox64::staticMetaObject': definition of dllimport static data member not allowed
我应该怎样做才能避免这个错误?
罪魁祸首是
Q_WIDGETS_EXPORT
,定义于qtwidgetsglobal.h
# if defined(QT_BUILD_WIDGETS_LIB)
# define Q_WIDGETS_EXPORT Q_DECL_EXPORT
# else
# define Q_WIDGETS_EXPORT Q_DECL_IMPORT
# endif
您应该通过将此行添加到 .pro 文件来在项目中声明
QT_BUILD_WIDGETS_LIB
DEFINES += QT_BUILD_WIDGETS_LIB
一些旁注:
#ifndef QSPINBOX64_H
stepEnabled()
需要实施explicit QSpinBox64(QWidget *parent = nullptr) : QAbstractSpinBox{parent}
{
setMaximum(std::numeric_limits<int64_t>::max());
setMinimum(std::numeric_limits<int64_t>::min());
connect(lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onEditFinished()));
}
virtual QAbstractSpinBox::StepEnabled stepEnabled() const
{
return QAbstractSpinBox::StepUpEnabled | QAbstractSpinBox::StepDownEnabled;
}
我真的不喜欢链接的原始代码,因为它的工作原理与
QSpinBox
类 plus 不能处理 stepBy
函数中设置的最小值/最大值一样。
这是我的方法,无需弄乱所有这些 Qt 宏:
#pragma once
#include <QAbstractSpinBox>
#include <QLineEdit>
#include <QString>
#include <QValidator>
#include <QWidget>
#include <limits>
class LongLongSpinBox : public QAbstractSpinBox
{
Q_OBJECT
using type = long long;
type m_minimum;
type m_maximum;
type m_value;
public:
explicit LongLongSpinBox(QWidget* parent = nullptr) : QAbstractSpinBox(parent)
{
setRange(std::numeric_limits<type>::min(), std::numeric_limits<type>::max());
QObject::connect(lineEdit(), &QLineEdit::textEdited, this, &LongLongSpinBox::onEditFinished);
};
~LongLongSpinBox(){};
type value() const
{
return m_value;
};
type minimum() const
{
return m_minimum;
};
void setMinimum(type min)
{
m_minimum = min;
}
type maximum() const
{
return m_maximum;
};
void setMaximum(type max)
{
m_maximum = max;
}
void setRange(type min, type max)
{
setMinimum(min);
setMaximum(max);
}
void stepBy(int steps) override
{
type new_value;
if (steps > 0 && m_value > std::numeric_limits<type>::max() - steps) // overflow
new_value = m_maximum;
else if (steps < 0 && m_value < std::numeric_limits<type>::min() - steps) // underflow
new_value = m_minimum;
else if ((m_value + steps) < m_minimum)
new_value = m_minimum;
else if ((m_value + steps) > m_maximum)
new_value = m_maximum;
else
new_value = m_value + steps;
setValue(new_value);
}
protected:
// bool event(QEvent *event);
QValidator::State validate(QString& input, int&) const override
{
if (input.isEmpty())
return QValidator::Acceptable;
// technically should check if the range allows positive / negative values
if (input.length() == 1 && (input[0] == '+' || input[0] == '-'))
return QValidator::Acceptable;
bool ok;
type val = input.toLongLong(&ok);
if (!ok)
return QValidator::Invalid;
if (val < m_minimum || val > m_maximum)
return QValidator::Invalid;
return QValidator::Acceptable;
}
virtual type valueFromText(const QString& text) const
{
return text.toLongLong();
}
virtual QString textFromValue(type val) const
{
return QString::number(val);
}
// virtual void fixup(QString &str) const;
virtual QAbstractSpinBox::StepEnabled stepEnabled() const
{
return StepUpEnabled | StepDownEnabled;
}
public Q_SLOTS:
void setValue(type val)
{
if (m_value != val)
{
auto new_text = textFromValue(val);
lineEdit()->setText(new_text);
m_value = val;
emit valueChanged(val);
emit valueChanged(new_text);
}
}
void onEditFinished()
{
auto new_text = text();
m_value = valueFromText(new_text);
emit valueChanged(m_value);
emit valueChanged(new_text);
}
Q_SIGNALS:
void valueChanged(type v);
void valueChanged(const QString& v);
};