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

How to prevent exponential numbers view in tableView?



  • Hi,
    I have tableView and need to show big numbers in it like 1 million which is more than 6 digit. But unforunatelly it's shown like attached picture?!
    0_1556806249425_e8cc232b-dad3-4143-9c5e-6db8556530c7-resim.png

    How can I show it normal?!...

    Regards,
    Mucip:)


  • Moderators

    @Mucip
    what type of model are you using? standard item model or custom model?
    Also whats the type of the corresponding column data?



  • Hi @raven-worx ,
    The number comes from PostgreSQL as numeric which is double...
    For SQL Query: QSqlQueryModel
    For tableView: QTableView

    Regards,
    Mucip:)


  • Moderators

    @Mucip
    ok so then you could try to cast the column already in the SQL query.
    Or subclass your sql model and in data() (for the corresponding column's Qt::DisplayRole) return:

    QString::number(doubleVal, 'f', 0)
    


  • @Mucip
    you can use a delegate override to return a correct string to the view.
    Take a look at this old forum post, it will give you an idea of how it can be implemented:
    https://forum.qt.io/topic/35577/formatting-numbers-in-qtableview-solved/4



  • Hi @raven-worx ,
    My code is like below:

    QSqlQueryModel *modelTableDinamoStok;
    
    this->modelTableDinamoStok = new QSqlQueryModel(this);
    modelTableDinamoStok->setQuery("SELECT stok_kod, stok_ad, stok_birim FROM stok_kart WHERE stok_tip = 'HAMMADDE' OR stok_tip = 'HAZIRMALZEME' ORDER BY stok_kod;", baglanti::mdb() );
     ui->tVStok->setModel(modelTableDinamoStok);
    

    Regards,
    Mucip:)



  • Hi @KillerSmath ,
    I already use delegate in other forms. But this number comes directly from sql query?!...

    Regards,
    Mucip:)



  • Hi @KillerSmath ,
    I think same problem.
    Yes, I will check this... ;-)

    Regards,
    Mucip:)



  • @Mucip
    The delegate uses QLocale to convert it to String, and by default, it uses 'g' format to convert float and double values to string.

    Edit: If you're little curious, you can see this conversion directly in the QAbstractItemDelegate source code (Inherited By QItemDelegate, the standard QTableView delegate)



  • Please excuse me for having my say, but this area has ben a bug-bear of mine for some time.

    I'm sure that @KillerSmath, the post he links to and the others who do this via a delegate know much more than I do about Qt. But to me this is just the wrong place to do number formatting. For one, thing it locks all the logic down into some QStyledItemDelegate. But the string formatting of the number, to me, is just not something to do with a table's/delegate's displayText(). You may want it for all sorts of other purposes, e.g. exporting the data. Shouldn't a delegate be used for drawing it big, or upside-down or with purple stripes in a box?

    Surely @raven-worx's very, very simple code in data(Qt::DisplayRole) is the place that makes logical sense for this feature, returning the desired string representation to be used for display while still being available to be called by anything else which wants it, and that's where I have done mine. It also has the virtue of being about one line of code instead of all the code required for a NumberFormatDelegate-type solution!



  • Hi @raven-worx ,
    Well, How can I cast it in SQL?

    Regards,
    Mucip:)



  • Hi @raven-worx ,
    I appllied CAST as follow:

    modelTableTalep->setQuery("select sn, stok_kod, stok_ad, CAST(talep_adet AS TEXT), talep_birim, mevcut_stok, talep_onay, sebep, talep_zaman, termin_tarih, kullanici, talep_eden FROM talep ORDER BY sn DESC;",baglanti::mdb());
    But still same problem 1,2E+8 like?!...

    But I wanted to use "Qt::DisplayRole"
    Any example please?...

    regards,
    Mucip:)



  • @Mucip
    If you are saying that your column is the CAST(talep_adet AS TEXT) and that still comes out as 1,2E+8, then that would mean that is the textual representation of that number up at SQL. Depending on your SQL server, something like CONVERT(talep_ad, ???) would be required, where the ??? is whatever your SQL allows for producing a number in digits instead, assuming there is such a parameter.

    As for doing it in your model override's data() function (which is how I would do it), you could actually look at the docs. You want something like:

    QVariant MyModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const
    {
        val = QSqlQueryModel::data(index, role);
        if (role == Qt::DisplayRole && index.column() == aDoubleNumberColumn)
        {
            doubleVal = static_cast<double>(val.value());
            return QString::number(doubleVal, 'f', 0)
        }
        return val;
    }
    


  • Hi @JonB ,
    In this way I neet to change row by row?! Am I wrong?!...

    Regards,
    Mucip:)



  • @JonB Strongly disagree with your post.

    The model should be pure data. If it contains a double then the model only has to care about those 64bits of data. It does not have to care about how to represent that data to the user, it's not its job. The delegate is the one that is concerned to converting pure data into something the user can read/interact with.

    Surely @raven-worx's very, very simple code in data(Qt::DisplayRole) is the place that makes logical sense for this feature

    This is even worse as it breaks the logic of the model itself. Try sorting the column containing the numbers converted to string using QSortFilterProxyModel and you'll quickly realised how bad it is to make the model care about visual representation of data.

    The solution proposed by @KillerSmath is the correct one and the only acceptable one from a model-view logic point of view.

    class NumberFormatDelegate : public QStyledItemDelegate{
        Q_OBJECT
        Q_DISABLE_COPY(NumberFormatDelegate)
    public:
        NumberFormatDelegate(QObject *parent = Q_NULLPTR)
            :QStyledItemDelegate(parent)
        {}
        QString displayText(const QVariant &value, const QLocale &locale) const Q_DECL_OVERRIDE{
            switch(value.type()){
            case QMetaType::Float:
                return locale.toString(value.toFloat(),'f');
            case QMetaType::Double:
                return locale.toString(value.toDouble(),'f');
            default:
                return QStyledItemDelegate::displayText(value,locale);
            }
        }
    };
    

    ui->tVStok->setItemDelegateForColumn(3, new NumberFormatDelegate(this));



  • Dear @VRonin ,
    I uset ItemDelegate and perfect result. Thanks all...

    Regards,
    Mucip:)



  • @VRonin
    Well, just to say I equally strongly disagree with yours :) Of course I respect your doubtless expert views too! I trust we can still be friends.

    There is a reason that the data() method has a role of DisplayRole. Docs:

    The key data to be rendered in the form of text. (QString)

    That's precisely what I want to use. Otherwise remove it, and say there is no such role for the data. I absolutely do allow sorting of my data. And of course the whole point is that I do not sort by DisplayRole, I sort by EditRole (or SortRole).

    If I sit down one day and have a column in my model which is, say, an int like an enumerated which I want displayed as apples, pears, oranges, and I decide I do want my users to be able to sort by the string they see, I have the option of sorting by DisplayRole if that is what I intend. I can't if it's buried away in some styled item delegate.

    Meanwhile, I do not only use the data in the model for display in views/tables. I might, for example wish to use to export textual data from my model. And I want the same text whether it's a cell in a table or an item in a PDF file. So again, I don't want the logic to be in some styled item delegate. The textual format of a number, commas, negative signs, leading currency symbol etc. is a real attribute of the data, not just a whim of a table view. To me.



  • @JonB said in How to prevent exponential numbers view in tableView?:

    The key data to be rendered in the form of text

    data to be rendered the model doesn't care about actual rendering it provides the data to be rendered by someone else

    And of course the whole point is that I do not sort by DisplayRole, I sort by EditRole

    EditRole and DispalyRole have another purpose. The easiest comparison is with excel/libreoffice calc: EditRole contains the formula of a cell, DispalyRole contains the result of that formula. The formula does not need to be rendered hence it is buried in that role while the result (not his graphical representation, just the data of the result) is stored in DispalyRole. Then there's the practical point of all the models provided by Qt implement EditRole and DispalyRole as one and the same.

    I might, for example wish to use to export textual data from my model. And I want the same text whether it's a cell in a table or an item in a PDF file

    Nothing stops you from storing suggestions on how to render the data inside other roles. There are even pre built roles for fonts and colours, so you can store even the number formatting you prefer in a user role to be used by whoever will take care of rendering that data but the model should only care about data, never of its representation



  • @VRonin
    So it's OK for ForegroundRole to return the color to display text in a table but it's not OK for DisplayRole to return the desired text to be displayed there? The text should be done in a delegate instead, so why shouldn't the color be done in one too? You treat DisplayRole very differently from other roles such as ForegroundRole, and I certainly did not get that as I learned Qt, I don't see from the docs where I should understand this very special handling of DisplayRole.

    I wish you had been there when I started out on this! [What's your phone number, we should talk so I can understand? ;-) ] Anyway, I am where I am now, and am committed to the way I have implemented in my code. Next time, when I don't start out from existing 32K of already (badly) written code, I will go down the delegate route!



  • @JonB said in How to prevent exponential numbers view in tableView?:

    So it's OK for ForegroundRole to return the color to display text

    Indeed. It tells the guy who actually needs to render the item what color to use but it's pure data it doesn't take ownership of the painting. The delegate is free to ignore that role when rendering if it doesn't fit the representation it is showing to the user

    so why shouldn't the color be done in one too?

    it is indeed done in the delegate.

    I don't see from the docs where I should understand this very special handling of DisplayRole

    And there isn't. [slight simplification ahead] ForegroundRole contains 4 integers for argb. it's pure data as well

    but it's not OK for DisplayRole to return the desired text to be displayed there?

    Yep, as it hides from the delegate the fact that it should render a decimal number, the delegate will just see a string and it might render it in the wrong way.



  • @VRonin
    Hmm, food for thought, thank you.


Log in to reply