Unit Conversion in Table-Model link?



  • Are there any Qt convenient classes for unit conversion between Metric and English Imperial/US systems? (or should I program it myself?).

    And secondly, can a unit conversion be easily/elegantly implemented in the model/view paradigm for a table-model update (two-way).

    E.g. entering table data in pounds which is on the fly stored as kilograms in the model. Implemented in a generic way without customized conversion for each "case". As an example the next time the update takes place, the weight data at the exact same spot in the table would be entered in ounce and still stored in the model as kilograms.



  • What you want is to use a "QProxyModel":http://qt-project.org/doc/qt-4.8/qproxymodel.html to do custom processing of the data between the view and the model.
    For the conversion itself, you'll have to code it or look for libraries that offer such capability.



  • Thanks so much rcari. I was not aware of that one. Do you also know if the QProxyModel can intervene both ways (I could not understand if that was possible at first glance)?

    Another idea matured in the meantime. That would be to make/subclass a Delegate. Do you have an opinion on that?

    Thanks again for your QProxyModel hint.



  • That is another possible solution, however, you would have to set the delegate on every view that will display this model. I think it is less central and thus more prone to possible errors in the future. By providing a QAbstractItemModel instance (that is your QProxyModel on your read model in the background), you deal with this problem at a single point.
    You can deal with the values both ways:
    Read:
    @QProxyModel::data()@
    Write:
    @QProxyModel::setData()@



  • I agree, using a proxy model would be a good solution. However, to make it work, you would have to have data on what the actual quantity of each data point is in your basic model.

    There is no way to make a generic proxy model that can convert all quantity units without knowing what your data represents: a distance would need a different mapping than a volume for instance, and the natural mappings are not always straight forward. For instance: the length of person is usually expressed in meters in the EU, but in feet and inches in the US. Volume may be expressed as gallons or as ounces in the US, but will be in litres or in CC (centilitres) in the EU.

    If you know what data is in what column, and you can indicate the quantity, source unit and target unit, you can do it. Otherwise, all data points would need to individually communicate the quantity and unit by themselves (perhaps using different quantity subtypes to distinguish an amount of fuel from an amount of soda) using data roles.





  • Thanks guys for all your help!

    fyi; Each Physical Quantity (PQ) data in the model will be in SI units [base and derived], like weight - kilograms, length - metres, velocity - m/s, time - s. And each ´column´ in the model will have a fixed PQ, it will not change. As an example; The PQ Length will persistently be Length for a particular ´column´ in the model! But many ´columns´ may have Length as their unit. I have not figured out yet if the model itself should tell which PQ it represent, or if that is something the rest of the program just need to know.

    Another thing; The idea is that multiple views can access the same data, and display the value of the PQ in the chosen unit system. As an example; One view will present the Length value in metres, another in feet, and yet another in inch. Simultaneously. And the user can change that interactively such as in the next second the same views will show the values as metres, feet, metres (as an example). Would this information change anything in your suggestions?

    I am a little concerned that the class QProxyModel is marked as obsolete in the documentation. But since you guys seem to have very good overview, there are still good applications for this class? As per good recommendations.

    Thanks also for the hint about the unit converter! I will look into it.

    ( I would also look for multiple header rows to present (a) the PQ Name in the first row and (2) the actual presented unit in the second row. But that is really another issue...)



  • You are right, the class QProxyModel is obsolute, but it's cousins are not. Proxy model is a bit of a generic term. I'd recommend you base your proxy off [[doc:QIdentityProxyModel]] if you're using Qt 4.8 or up, and QSortFilterProxyModel otherwise. I usually #ifdef the base class for such proxies based on the Qt version, so the class will work in either case.

    If a whole column represents the same PQ, then I'd considder giving that (and the unit) information as a role for the header, as well as as a role for each individual item. The latter may seem a duplication, but it will make it easier to get the PQ and unit if you just have a QModelIndex to your data. In your proxy, you can use the knowledge to set up a simple mapping per column. Perhaps something like this:

    • if the source model for the proxy provides a PQ and unit for the header of a column, use that for all items in that column;
    • if the source model does not provide a PQ and unit for the header, try and see if there is a PQ and unit for the item itself. If so, use that;
    • if not, do not convert.

    That way, you can set up a default mapping for basically all your data by iterating over the headers of the source model once, avoiding endless calls to find out the PQ and unit for each item every time. However, you're still flexible to change in case you decide that your source data for a particular column is not uniform.

    For using multiple views on the same data, using proxy models is perfect. You'd give each view its own proxy model, set the unit system on it you want, and set the same base (SI) model on each of the proxies. That way, all views view the same data, just with their units converted.

    Multiple header rows is going to be complicated to achieve.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.