Home > OS >  Best practice to manage units of measurement conversion in a Qt/C application
Best practice to manage units of measurement conversion in a Qt/C application

Time:12-15

What is the best practice to add the possibility for users to choose the preferred units of measurement in an application written in Qt/QML and C ?

My case is a front-end application that shows data coming from a PLC, giving also the possibility to edit some of them. The PLC data is in millimeters, grams, degrees Celsius, and meters per minute and need to remain in these units.

I want to add the possibility in the front-end application to choose if you want to show the data in millimeters or feet, Celsius or Fahrenheit, etc...

I was thinking about a singleton QObject derived class that returns as Q_PROPERTY the units of measurement ("mm", "oz", etc...), but I'm not sure about developing some slots that convert the values because I can not dynamically update the interface when the user switch the unit of measurement.

P.S. I would like to avoid using boost libraries

CodePudding user response:

I don't know if it's the best practice, but the way I would handle it is to frame it as a problem of converting between the PLC's native data formats and an equivalent user-readable QString, and back.

Given that, I might create an abstract interface for a class that knows how to do that, like this:

class IUnitsPresentationLayer {
public:
   virtual QString lengthToString(long lengthInMillimeters) const = 0;
   virtual long stringToLength(const QString & lengthStr) const = 0;

   virtual QString temperatureToString(float temperatureCelsius) const = 0;
   virtual float stringToTemperature(const QString & tempStr) const = 0;

   [... and so on...]
};

Then the rest of your GUI code can be handed a const IUnitsPresentationLayer * pointer to use whenever it needs to display a PLC-data-value (or parse a user-entered QString back into a PLC-data-value). The actual implementation can be kept private inside one .cpp file, and it could be a singleton, or if necessary you could create different IUnitsPresentationLayer-subclasses for different behaviors, and maybe pass them around via QPointer or std::shared_ptr as necessary. Since these objects are entirely const/immutable, it's okay for many GUI widgets to all have shared read-only access to them simultaneously.

CodePudding user response:

I have a QML Qt C UI. It interfaces with a back-end application.
UI supports both Imperial & Metric modes. User can make this selection from UI at runtime.
User can view and edit data values via the UI.
Back-end application works only in Imperial mode.

A C utility object is exposed to QML as a context property. This utility object has methods to:

  • Set and Get the System of measurement.
  • Convert unit string from Imperial to Metric. Example: °F to °C.
  • Convert data value from Imperial to Metric and Metric to Imperial. Example: Fahrenheit to Celsius -> 50 to 10, Celsius to Fahrenheit -> 0 to 32.

C data object has these 2 properties:

Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
Q_PROPERTY(QString unitString READ unitString NOTIFY unitStringChanged)
// value - In Imperial mode, you get Imperial value. In Metric mode, you get Metric value.
// unitString - In Imperial mode, you get Imperial units. In Metric mode, you get Metric units.

QVariant data::value()
{
    // fetch Imperial data value from back-end application
    // get current System of measurement
    // if current System of measurement is Metric, convert data value from Imperial to Metric
    // return data value
}

QString data::unitString()
{
    // fetch Imperial unit from back-end application
    // get current System of measurement
    // if current System of measurement is Metric, convert unit from Imperial to Metric
    // return unit
}

void data::setValue(QVariant value)
{
    // get current System of measurement
    // if current System of measurement is Metric, convert value from Metric to Imperial
    // write value to back-end Controller application
}
  • Related