Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTableView display data in millimeter or inch



  • Hi at all,

    do you know the "best way" to display data in millimeters or inch inside a QTableView and QLineEdit mapped to a database table?

    As usual, any suggestion will be appreciated.


  • Lifetime Qt Champion

    Hi,

    What version of the value are you storing in the database ?



  • Hi @SGaist,
    inside the database all datas are stored in millimeters.


  • Lifetime Qt Champion

    In that case, a QStyledItemDelegate for the QTableView.

    For the QLineEdit, are you sure you will not be better served by a QSpinBox ?



  • @SGaist said in QTableView display data in millimeter or inch:

    In that case, a QStyledItemDelegate for the QTableView.

    I forgot to specify that the QTableView is in "read-only mode", to edit or insert a new row the user write the data inside the QLineEdits mapped by QDataWidgetMapper.
    I've about 15 column to convert on the fly between mm / inch depending of the user choice.

    The qtwidgets-itemviews-stardelegate-example could be a good starting point?

    QSpinBox... I don't know why, there is no real reason, but I don't like much the "spin box" widget. Not only in QT, but in general. Anyway, I'll give it a chance :-)



  • Hi @SGaist ,

    I've created my QStyledItemDelegate...

    #pragma once
    
    #include <QStyledItemDelegate>
    
    class VTMmInchItemDelegate : public QStyledItemDelegate
    {
      public:
        explicit VTMmInchItemDelegate(QObject *parent = nullptr);
        virtual QString displayText(const QVariant &value, const QLocale &locale) const;
    
      public slots:
        void slotMeasChanged(bool mm);
    
      private:
        /// unit measure (mm = 1.0, inch = 25.4)
        double m_unitMeas = 1.0;
    
        /// decimal precision mm = 3, inch = 5
        int m_decimalPrecision = 3;
    };
    
    #include "vtmminchitemdelegate.h"
    
    VTMmInchItemDelegate::VTMmInchItemDelegate(QObject *parent) : QStyledItemDelegate(parent)
    {
        //
    }
    
    QString VTMmInchItemDelegate::displayText(const QVariant &value, const QLocale &locale) const
    {
        // unit measure (mm = 1.0, inch = 25.4)
        // decimal precision (mm = 3, inch = 5)
        return QString::number(value.toDouble() / m_unitMeas, 'f', m_decimalPrecision);
    }
    
    void VTMmInchItemDelegate::slotMeasChanged(bool mm)
    {
        if (mm)
        {
            m_unitMeas         = 1.0;
            m_decimalPrecision = 3;
        }
        else
        {
            m_unitMeas         = 25.4;
            m_decimalPrecision = 5;
        }
    }
    

    ...and I can use it with a QTableView in this way:

    ui->tableView->setItemDelegateForColumn(2, new VTMmInchItemDelegate(this));
    ui->tableView->setItemDelegateForColumn(3, new VTMmInchItemDelegate(this));
    

    But now I don't know how to achieve the same behavior with the widgets mapped by QDataWidgetMapper.

    I have about 30 widgets (QlineEdit or QComboBox) and I'd like to map some QLineEdits to display as the QTableView, the data correctly according to the setting mm / inch.

    Do you have any suggestion please?
    Thank you so much.

    PS: I've try another way, subclassing the QSqlTableModel and reimplementing the function:

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    

    ...but I obtain the same result, the QTableView works fine, the widgets mapped by QDataWidgetMapper not.


  • Lifetime Qt Champion

    You can create a widget that contains a QLineEdit and serves as proxy.



  • Hi @SGaist ,

    thank you for your suggestions, follow my implementation.

    • QSqlTableModel subclass
    • QItemDelegate subclass

    vtsqltablemodel.h

    #pragma once
    
    #include <QSqlTableModel>
    
    class VTSqlTableModel : public QSqlTableModel
    {
      public:
        VTSqlTableModel(const QVector<int> &column, QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase());
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    
      public slots:
        void slotMeasChanged(bool mm);
    
      private:
        /// list of columns to format in mm or inch
        QVector<int> m_column;
    
        /// unit measure (mm = 1.0, inch = 25.4)
        double m_unitMeas = 1.0;
    
        /// decimal precision mm = 3, inch = 5
        int m_decimalPrecision = 3;
    };
    

    vtsqltablemodel.cpp

    #include "vtsqltablemodel.h"
    
    VTSqlTableModel::VTSqlTableModel(const QVector<int> &column, QObject *parent, QSqlDatabase db) : QSqlTableModel(parent, db), m_column(column)
    {
        //
    }
    
    QVariant VTSqlTableModel::data(const QModelIndex &index, int role) const
    {
        if (role == Qt::DisplayRole)
        {
            if (m_column.contains(index.column()))
                return QVariant(QString::number(QSqlTableModel::data(index, role).toDouble() / m_unitMeas, 'f', m_decimalPrecision));
        }
    
        return QSqlTableModel::data(index, role);
    }
    
    void VTSqlTableModel::slotMeasChanged(bool mm)
    {
        if (mm)
        {
            m_unitMeas         = 1.0;
            m_decimalPrecision = 3;
        }
        else
        {
            m_unitMeas         = 25.4;
            m_decimalPrecision = 5;
        }
        select();
    }
    

    vtmminchitemdelegate.h

    #pragma once
    
    #include <QItemDelegate>
    
    class VTMmInchItemDelegate : public QItemDelegate
    {
        Q_OBJECT
      public:
        explicit VTMmInchItemDelegate(const QVector<int> &column, QObject *parent = nullptr);
        void setEditorData(QWidget *editor, const QModelIndex &index) const;
        void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
    
      public slots:
        void slotMeasChanged(bool mm);
    
      private:
        /// list of columns to format in mm or inch
        QVector<int> m_column;
    
        /// unit measure (mm = 1.0, inch = 25.4)
        double m_unitMeas = 1.0;
    
        /// decimal precision mm = 3, inch = 5
        int m_decimalPrecision = 3;
    };
    

    vtmminchitemdelegate.cpp

    #include "vtmminchitemdelegate.h"
    
    #include <QDebug>
    #include <QLineEdit>
    #include <QVariant>
    
    VTMmInchItemDelegate::VTMmInchItemDelegate(const QVector<int> &column, QObject *parent) : QItemDelegate(parent), m_column(column)
    {
        //
    }
    
    void VTMmInchItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
    {
        QLineEdit *edt = (dynamic_cast<QLineEdit *>(editor));
    
        if ((m_column.contains(index.column())) && (edt))
        {
            // I have only to display data because is already formatted as QString by my SqlTableModel
            edt->setText(index.data().toString());
        }
        else
            QItemDelegate::setEditorData(editor, index);
    }
    
    void VTMmInchItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
    {
        QLineEdit *edt = (dynamic_cast<QLineEdit *>(editor));
    
        if ((m_column.contains(index.column())) && (edt))
        {
            // I have to convert the user input data regarding to the "unit measure" private variable
            QVariant value = edt->text().toDouble() * m_unitMeas;
            model->setData(index, value);
        }
        else
            QItemDelegate::setModelData(editor, model, index);
    }
    
    void VTMmInchItemDelegate::slotMeasChanged(bool mm)
    {
        if (mm)
        {
            m_unitMeas         = 1.0;
            m_decimalPrecision = 3;
        }
        else
        {
            m_unitMeas         = 25.4;
            m_decimalPrecision = 5;
        }
    }
    

    ...and you can use it as follow.

        QVector<int> cols;
        cols << 2 << 3 << 4;
        m_model = new VTSqlTableModel(cols);
    ...
        m_mapper = new QDataWidgetMapper;
        m_mapper->setModel(m_model);
        m_mapper->setItemDelegate(new VTMmInchItemDelegate(cols, this));
    

Log in to reply