c++qt5

qspinbox64 in QT5.15.2


I tried to create a qspinbox64 as suggested in

64bit int Spin Box in QT

qspinbox64.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 

main.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();
}

An error occurs after compilation:

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

What should I do to avoid this error?


Solution

  • The culprit is Q_WIDGETS_EXPORT, defined in qtwidgetsglobal.h

    #  if defined(QT_BUILD_WIDGETS_LIB)
    #    define Q_WIDGETS_EXPORT Q_DECL_EXPORT
    #  else
    #    define Q_WIDGETS_EXPORT Q_DECL_IMPORT
    #  endif
    

    You should declare QT_BUILD_WIDGETS_LIB in your project by adding this line to the .pro file

    DEFINES += QT_BUILD_WIDGETS_LIB
    

    Some side notes:

    1. You are missing the header guard #ifndef QSPINBOX64_H
    2. The constructor should call the base class constructor and set the min/max as instructed in the original post.
    3. stepEnabled() needs to be implemented

    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;
    }