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
}