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

How to get comma as decimal separator in line edits?



  • Hi
    I am a beginner at this: Creating an application in Python using QT5.

    My application maintains and displays data stored in an Sqlite database.
    I use a QSqlRelationalTableModel, and I map data to comboboxes
    and lineedits using a QDataWidgetMapper. I also use QDoubleValidator to validate
    user input of numbers with decimals. The model uses OnFieldChange as edit-strategy.

    It is necessary that comma is used as decimal seprator in the user
    interface. The OS is configured to use comma as decimal separator, and
    QT Designer shows "Norwegian Bokmal, Norway" as locale in the QMainWindow locale
    property.

    The problem: Decimal number are still shown with point as decimal separator in all the
    lineedits. I have spent considerable time reading documentation, but I am still
    bewildered. I will be gratefull for an help on this. An explanation on how to
    go about to have my decimal numbers displayed in the line edits
    with comma as decimal seprator.

    By the way: The QDoubleValidator accepts comma and not dot, so that works
    as I want it to.

    Oh, and I use PyQt5.



  • @bkvldr said in How to get comma as decimal separator in line edits?:

    QT Designer shows "Norwegian Bokmal, Norway" as locale in the QMainWindow locale
    property.

    That's something at design-time. Start by verifying what the locale is at runtime.



  • I

    @JonB said in How to get comma as decimal separator in line edits?:
    ...

    That's something at design-time. Start by verifying what the locale is at runtime.

    Hi,
    I run this:
    q=QtCore.QLocale()
    print ('country',q.country())
    print ('decimalpoint ', q.decimalPoint())
    print ('language ', q.language())

    Output is:
    country 161
    decimalpoint ,
    language 85

    country 161 is QLocale::Norway
    language 85 is QLocale::NorwegianBokmal

    And that is what I expected.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Do you have the same issue if you create a QLineEdit with code that is not mapped to your model ?


  • Banned

    Okay @bkvldr there are two things you are doing wrong with this approach:

    1. Using the Qt Designer
    2. Using QSqlRelationalTableModel

    Yes they both exist but that does not mean they are the best tools to use

    (1) This is meant to create Gui's that are code portable and unless your Gui needs to exist in more than one language you do not need to deal with the garbage code it produces which btw is not at all proper Python-Qt. Further once you learn the basics you will find creating proper Python-Qt Guis is very easy and fairly quick

    (2) This I am not even sure about why it was created because in nearly all programs written today the MVC methodology should be applied as this turns out to often be the best approach to dealing with Data Sources and Guis. With that being said you would never have to be concerned about a direct model to the Sqlite3 database since your self-contained autonomous Database Class would handle all that -- passing back a simple parsed dictionary Recordset or simple reply depending on the requested data coming from the Controller which was in turn received from the Gui

    Model (Data Source) <> Controller(Translator) <> View(Gui)

    I believe I have posted a sqlite3 database class template on before but feel free to PM if you cannot find it as I am not aware of this Forum having a central repository for Code Examples that we can point you to or post to -- then again maybe there is and the Moderator will let me know --- or maybe they will create one due to this post



  • @SGaist
    So I tried this:

        number = 8.237        
        self.test2LineEdit.setText( QtCore.QLocale().toString(number,\
                'f', 2))
    

    test2LineEdit shows 8,24

    Decimal comma is used, and the number has been correctly rounded up.
    I thought the mapper would have done this, but obviously it did not.


  • Banned

    And so your headaches begin and they will only continue and perhaps get worse but I can guarantee you they will not stop without putting at least 5 times as much time and effort into trying to get your vehicle with its square wheels to move along as smoothly as the vehicle with the proper round wheels and in the end you will simply have something that looks a lot like the round wheeled vehicle that already exists just its wheels will not be perfectly round just as close to round as you can obtain via the method you are using -- seen this done before time and time again -- so just the same story with different flies. Basically you can either do it the easy way or can do it the hard way



  • @Denni-0
    My project is a private learning project. I have no dead-line, and I am free to reconsider my approach. Guess I have to do som reading on MCV. Are the models provided by Qt really so troublesome as your post gives me the impression of ? Sent you a PM (or was it a chat)


  • Banned

    First you will find it by searching MVC Methodology even though technically its M<>C<>V not sure why they did it the other way it seems more intuitive me to put it in communication order MCV but the did not.

    Next are the Qt Models all that troublesome -- technically no and in fact you may end up using a Model to handle the data on the GUI side of things anyway BUT what you will not be doing is tying your GUI directly to your Database via the QSqlRelationalTableModel because that is just loaded with issues -- and none of them really have to do with specifically using QSqlRelationalTableModel they have to do with using that design methodology. Having coded numerous Gui / Database programs both PC and Web based applications you eventually learn what does and does not work well and frankly MVC works well and universally and direct ties do not work well and are definitely not universal

    Basically if you create the Model (Data Source) and the View (Gui) such that neither one knows anything about the other and pass all request through your Controller (Translator) they never have to and lets say today your Model(Data Source) is an Sqlite3 database but next week the powers that be decide they want to invest into an Oracle database -- well the only thing that needs to be changed at all is your Model Class and maybe some minor tweaks to your Controller Class the Gui needs absolutely no changes -- conversely instead say the powers that be decide to go from supporting just a PC Application to supporting also a Web-based front-end well then all you need to do is add a new View (Web-based) and use the same (or similar) connections to the Controller class as the connection to the Model(Database) has not changed at all.

    Now maybe you do not see this occurring that is fine because besides this advantage there are numerous other reasons why one would want to use the MVC methodology over the direct connection methodology and all of these reasons are mainly getting away from the issues that come up when using the direct connection methodology.

    Basically this separation of View(Gui) and Model(Data Source) I have even used when developing simple MS Access Database applications by creating one MS Access that is just the front end and another that is the back end and keeping the two completely separate and frankly the end product was a blessing more than once as a couple of the customer actually exceeded the limits of an Access Database storage limits and the shift from Access back end to different database back in was pretty much straight forward replace old database with new database engine -- tweak the connector to point to the new database -- and done.


  • Qt Champions 2017

    @Denni-0, dude, what are you babbling about and what does it have to do with the question? Even I got confused ...



  • I find Denni 0's post very interesting, but I would definitely appreciate a follow up on my original question. I would like to know if I can finish the application with my approach.

    I use QSqlRelationalTableModel and QDataWidgetMapper. How can I display numeric data from the database in lineedits according to my locale, with decimal comma instead of decimal point?

    Please see posts above.



  • @bkvldr
    There are plenty of people and code using both the Qt Designer and the QSql... classes very happily. @Denni-0 has his own opinions about this, which is fair enough, but (respectfully) they are not the mainstream/majority views. Make of that as you choose.

    I use QSqlRelationalTableModel and QDataWidgetMapper. How can I display numeric data from the database in lineedits according to my locale, with decimal comma instead of decimal point?

    Since you show it does not seem to do this left to its own devices (admittedly surprising, possibly worth a bug report), but your test code with a QLineEdit does what you want, have you seen https://doc.qt.io/qt-5/qdatawidgetmapper.html#setItemDelegate which would allow you to use your code in a delegate? I'm not sure how you would, perhaps, achieve your own widget only for numbers in a line edit while forwarding all others to the original delegate, but you could investigate.


  • Moderators

    @bkvldr said in How to get comma as decimal separator in line edits?:

    I would like to know if I can finish the application with my approach.

    I use QSqlRelationalTableModel and QDataWidgetMapper. How can I display numeric data from the database in lineedits according to my locale, with decimal comma instead of decimal point?

    Understanding the root cause

    The behaviour that you see is caused by something a lot lower-level than QSqlRelationalTableModel and QDataWidgetMapper. It boils down to this (written in C++, but hopefully easy enough to understand for a Python developer):

    QLocale::setDefault(QLocale::Norwegian);
    
    QLineEdit le;
    le.setText( le.locale().toString(12.34) );
    // Shows "12,34"
    
    le.setText( QString::number(12.34) );
    // Shows "12.34"
    
    le.setProperty("text", 12.34);
    // Shows "12.34"
    

    QDataWidgetMapper does not know about the existence of QLineEdit. It relies on QAbstractItemDelegate to transfer data to/from widgets, and QAbstractItemDelegate in turn relies on the Qt property system to do data conversions.

    Now, QLineEdit's USER property (see https://doc.qt.io/qt-5/properties.html ) is "text", which is a QString instead of a double. Some kind of conversion is required.

    Unless the caller explicitly uses a locale-aware conversion, number-to-string conversions assume an en-US locale. See https://doc.qt.io/qt-5/qstring.html#number, for example: "The formatting always uses QLocale::C, i.e., English/UnitedStates. To get a localized string representation of a number, use QLocale::toString() with the appropriate locale."

    Solution(s)

    In a nutshell, you need to somehow invoke a locale-aware number-to-string conversion.

    As @JonB mentioned, you could implement your own QAbstractItemDelegate to do this conversion before passing a stringified number to your QLineEdit.

    Another way is to subclass QLineEdit and specialize it for numeric data:

    class NumericLineEdit : public QLineEdit
    {
        Q_OBJECT
        Q_PROPERTY(double number READ number WRITE setNumber USER true)
    
    public:
        // ...
    
        double number() const;
        void setNumber(double num); // In here, do a locale-aware conversion before calling QLineEdit::setText()
    };
    

    Yet another way is to avoid using QLineEdit and use QDoubleSpinBox instead.


  • Banned

    @JKSH the solution you propose is actually a lot more complex than it needs to be and while the end issue might be exactly what you describe it is not the core issue. The core issue is implementing a solution as a direct from the Database into GUI process as the MVC methodology version does not have this issue because the data when presented to the GUI is in format that it can easily consume and the data when presented to the Database is in a format that it can easily consume.

    The key is not how can we make the program more complex but how can we simplify it and yet make it as smart as possible or going to the model of K.I.S.S. (Keep It Simple and Smart). I have seen programmers create nightmares by trying to get fancy and slick when something a lot simpler would have been a whole lot smarter.

    BTW I did enjoy your in depth dive into this as I do enjoy having a better understanding of some of the inner workings as that in turns helps me to understand how to do things simpler and remain smart about doing it that way.



  • @JKSH said in How to get comma as decimal separator in line edits?:

    As @JonB mentioned, you could implement your own QAbstractItemDelegate to do this conversion before passing a stringified number to your QLineEdit.

    Now you have confused me about my own earlier answer! :)

    I thought there was only QDataWidgetMapper::setItemDelegate() to affect what widget it used for everything. Now I see there is QDataWidgetMapper::addMapping() for different widget per column. Given which, subclass QLineEdit is easiest. So I don't get what the point of the setItemDelegate() is over the QDataWidgetMapper as a whole is when you can set the widget per column?


  • Moderators

    @JonB said in How to get comma as decimal separator in line edits?:

    So I don't get what the point of the setItemDelegate() is over the QDataWidgetMapper as a whole is when you can set the widget per column?

    I listed 3 different ways to tackle the problem, from hardest to easiest. @bkvldr mentioned that this is a learning project, so the point here is to provide an opportunity to explore different parts of Qt. The point is not to showcase the Best Solution™.

    Given which, subclass QLineEdit is easiest.

    Actually, I'd say "use QDoubleSpinBox" is easiest.

    @Denni-0 said in How to get comma as decimal separator in line edits?:

    while the end issue might be exactly what you describe it is not the core issue. The core issue is implementing a solution as a direct from the Database into GUI process as the MVC methodology version does not have this issue because the data when presented to the GUI is in format that it can easily consume and the data when presented to the Database is in a format that it can easily consume.

    Even with the MVC methodology, we still need to be aware that certain data conversion pathways do not take the locale into account, and we must program our MVC components accordingly.

    This issue affects more than just choosing an architecture for transferring data between front-ends and back-ends. It also affects things like exporting data to CSV files; it also affects non-GUI applications.

    The key is... how can we simplify it and yet make it as smart as possible or going to the model of K.I.S.S. (Keep It Simple and Smart). I have seen programmers create nightmares by trying to get fancy and slick when something a lot simpler would have been a whole lot smarter.

    I agree with you that keeping things simple and smart is definitely desirable. What is "simplest" and "smartest" is situational though.

    If I have a whimsical boss who might suddenly demand that I replace a local native GUI with a web interface, then yes it could be smart for me to start with an ultra-flexible MVC implementation.

    However, if I know that I won't ever need to change my front-end or back-end, then using out-of-the-box components from the Qt toolkit is the simpler and smarter option because it lets me get my app working well with a lot less code.

    @JKSH the solution you propose is actually a lot more complex than it needs to be

    "Replace QLineEdit with QDoubleSpinBox" is much simpler than "Re-architect your whole program".

    BTW I did enjoy your in depth dive into this as I do enjoy having a better understanding of some of the inner workings as that in turns helps me to understand how to do things simpler and remain smart about doing it that way.

    I'm glad to hear that. Live till we're old, learn till we're old (Chinese proverb)

    If you'd like to do your own deep-dives, I highly recommend the Woboq Code Browser which lets us navigate the internals of Qt code interactively. I started here and traced the call chain to discover what was happening: https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qdatawidgetmapper.cpp.html#_ZN17QDataWidgetMapper7toFirstEv



  • @JKSH said in How to get comma as decimal separator in line edits?:

    Given which, subclass QLineEdit is easiest.

    Actually, I'd say "use QDoubleSpinBox" is easiest.

    I meant, the easiest solution given wanting to continue with a QLineEdit-type. Just sub-classing it for (floating point) numbers is easier than writing your own delegate.

    So I don't get what the point of the setItemDelegate() is over the QDataWidgetMapper as a whole is when you can set the widget per column?

    My question is here is not to do with "best solution". May I try asking again, as I did not get the answer I wanted and I really would like to understand?

    I said: at the time I recommended setItemDelegate() I did not know about addMapping(). Given that addMapping() allows the specification of individual widget types per each column, I am now asking: what is the point of setItemDelegate()? That is once per QDataWidgetMapper, not per column. I don't understand when that gets used given that you have per-column-mapped-widgets. When is it used? What is the point of one delegate across all columns when you have addMapping()? E.g. is it perhaps that the item delegate gets used if & only if you haven't specified any addMapping()s?? Or what? I have not gathered this from reading the docs. Thank you.


  • Moderators

    @JonB said in How to get comma as decimal separator in line edits?:

    May I try asking again, as I did not get the answer I wanted and I really would like to understand?

    I said: at the time I recommended setItemDelegate() I did not know about addMapping().  Given that addMapping() allows the specification of individual widget types per each column, I am now asking: what is the point of setItemDelegate()?  That is once per QDataWidgetMapper, not per column.  I don't understand when that gets used given that you have per-column-mapped-widgets.  When is it used?  What is the point of one delegate across all columns when you have addMapping()?  E.g. is it perhaps that the item delegate gets used if & only if you haven't specified any addMapping()s??  Or what?  I have not gathered this from reading the docs.  Thank you.

    Ah, I see. Sorry for misunderstanding your question.

    First, note that QDataWidgetMapper uses delegates a bit differently from QAbstractItemView.

    • A View asks the Delegate to create an editor widget; the Delegate can choose to create a different widget for different columns.
    • A Mapper tells the Delegate which editor widget to use; the Delegate has no say here because the choice is set by QDataWidgetMapper::addMapping().

    In both cases though, the Delegate is responsible for transferring/converting data between the editor widget and the model.

    If you don't call QDataWidgetMapper::setItemDelegate(), then you're using the default Delegate (which performs non-locale-aware conversion). However, if you subclass QAbstractItemDelegate and call QDataWidgetMapper::setItemDelegate(), then you can control how the data is converted between the editor widget and the model. For example, you can reimplement QAbstractItemModel::setEditorData() and force it to do a locale-aware conversion before calling QLineEdit::setText().

    Does this answer your question?



  • @JKSH
    So the default QDataWidgetMapper::itemDelegate() has code which says "look at what column, look at the addMapping()s, and create the QWidget mapped for the column", is that right? So in the normal/this case at least, you don't tend to need to do any setItemDeletegate() of your own, you just use the supplied one and let it work off your addMappings() (where e.g. you can sub-class QLineEdit for numbers --- which to me seems the easiest without creating your own delegate), right? So if the OP uses your NumericLineEdit there is no need to fiddle with setItemDelegate() at all, you only need to in other cases?


  • Moderators

    @JonB said in How to get comma as decimal separator in line edits?:

    So the default QDataWidgetMapper::itemDelegate() has code which says "look at what column, look at the addMapping()s, and create the QWidget mapped for the column", is that right?

    Nope.

    With a Mapper, the Delegate does not create a widget; the Delegate is given the pointer to the widget it should read/write.

    Views Mappers
    The editor Widget is... Created by the Delegate when the View calls QAbstractItemModel::createEditor() Created by the programmer first, then specified via QDataWidgetMapper::addMapping()
    Data is passed from the Model to the Widget when... The View calls QAbstractItemDelegate::setEditorData() The Mapper calls QAbstractItemDelegate::setEditorData()
    Data is passed from the Widget to the Model when... The View calls QAbstractItemDelegate::setModelData() The Mapper calls QAbstractItemDelegate::setModelData()

    So in the normal/this case at least, you don't tend to need to do any setItemDeletegate() of your own, you just use the supplied one...

    Yep.

    ...and let it work off your addMappings() (where e.g. you can sub-class QLineEdit for numbers --- which to me seems the easiest without creating your own delegate), right?

    Yep.

    So if the OP uses your NumericLineEdit there is no need to fiddle with setItemDelegate() at all, you only need to in other cases?

    Yep.

    In summary,

    • QDataWidgetMapper::addMapping() determines which widget is used.
    • QDataWidgetMapper::setItemDelegate() determines how data is transferred to/from the widget.


  • @JKSH
    Got it! So, as I think you said, QAbstractItemDelegate says

    The QAbstractItemDelegate class is used to display and edit data items from a model.

    but you're saying QDataWidgetMapper::itemDelegate() does not itself do the "display and edit data items" here, that gets done via the addMapping(). Here we only use it for its data value transfer features. Have I finally got it? Nice and confusing.... :)


  • Moderators

    @JonB said in How to get comma as decimal separator in line edits?:

    Here we only use it for its data value transfer features. Have I finally got it?

    That's a good summary :)


  • Banned

    Even with the MVC methodology, we still need to be aware that certain data conversion pathways do not take the locale into account, and we must program our MVC components accordingly.

    Okay @JKSH I am not sure what you mean by this because with a properly designed MVC this is all taken into account. What comes out of the Model (Database) is a simple native to Python dictionary structure and all it accepts are calls to pre-defined functions (stored procedures) that may include a parameter list. Thus there are no conversion pathways the data coming in is simple and the data coming out is simple

    This issue affects more than just choosing an architecture for transferring data between front-ends and back-ends. It also affects things like exporting data to CSV files; it also affects non-GUI applications.

    Again if the data coming out is always in the same format and the calls going in are always to pre-defined APIs it does not matter what that data is used for or how it is used the Model(Database) is utilized the same way regardless. In fact that is a core element of the MVC Methodology in that the Model (Data Source regardless of what it actually is) does not know nor does it care what the data it sends out is being used for and all requests/commands coming in are all pre-defined so that there is no funkiness going on in that realm either. It is all straight forward, streamlined, and simple.

    I agree with you that keeping things simple and smart is definitely desirable. What is "simplest" and "smartest" is situational though.

    In some cases yes but in most cases it is fairly simple itself -- anything that adds more complexity regardless of the what it does needs to be examined to determine if it adds enough functionality to warrant the added complexity. Further if learning to use it is a lot more complicated than using something simpler often is reason enough not to go that route

    However, if I know that I won't ever need to change my front-end or back-end, then using out-of-the-box components from the Qt toolkit is the simpler and smarter option because it lets me get my app working well with a lot less code.

    That is what I call short-term thinking which is always bad. I have encounter so many projects that were never meant to grow beyond their basic premise and were believed never would -- so it was designed with this kind of short-sighted thinking and when I enter the picture it has become a nightmare for those that created it and those that use it.

    "Replace QLineEdit with QDoubleSpinBox" is much simpler than "Re-architect your whole program".

    No continuing to use the GUI connected directly to the Database is -- which is an integral part of this much simplified version of what you purposed. Oh and btw that so-called re-architecture is extremely easy to create and maintain and might just use a lot less code in the long run with much better and safer results

    I'm glad to hear that. Live till we're old, learn till we're old (Chinese proverb)

    Yep always living and learning -- without constant learning life becomes a rut -- and the only difference between a rut and grave are it dimensions.

    If you'd like to do your own deep-dives, I highly recommend the Woboq Code Browser which lets us navigate the internals of Qt code interactively. I started here and traced the call chain to discover what was happening: https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qdatawidgetmapper.cpp.html#_ZN17QDataWidgetMapper7toFirstEv

    Thanks I might look into that



  • Thanks to all of you!
    A quick test shows that the particular problem I had with the decimal separator can be solved with QDoubleSpinBox


Log in to reply