PDA

View Full Version : Multiple representation of same data (kgs and lbs)



DLabonte
28th August 2017, 21:51
Good afternoon,

I am working of a QML form where a user can enter a weight value in either lbs or kgs (using 2 different textedits). The value is maintained in a C++ structure (in kgs) and both representations are to be displayed. Is there a need for a model?

Early tests also reveal a binding loop for property 'text' ... between the fields even when testing for a change in value before issuing an emit. In the QML file, I am using onTextChanged to update the other representation of the value.

Any tip of the best approach?

Regards,
Daniel

high_flyer
29th August 2017, 00:07
The value is maintained in a C++ structure (in kgs)
From how you described it, it sounds you only have one data field, the kg value.
Why use a struct for that?
You can simply have in a member variable and expose it to QML via property.
For one data filed a model would not be needed.

DLabonte
5th September 2017, 16:34
Hi again,

Thanks for the response. To answer the question Why use a struct for that?: The height and weight values are maintained in C++ class, stored and recalled from a DB.

The operator can enter either imperial or metric values. The GUI presents TextInputs for both representations, each updated when values are entered; ie. enter 100kg, 220 lbs is also shown. Only the metric values are stored, Javascript functions are defined to do the conversion.

I am using Q_PROPERTY in the C++ code, and slots are defined to handle the height and weight changes as shown here:


Q_PROPERTY(int heightCm READ getHeightCm WRITE setHeightCm NOTIFY heightCmChanged)
Q_PROPERTY(int weightKg READ getWeightKg WRITE setWeightKg NOTIFY weightKgChanged)
...

int getWeightKg() {
return weightKg;
}

void setWeightKg( int v)
{
if (getWeightKg() == v) {
return;
}

weightKg = v;
emit weightKgChanged();
}

In the QML code, properties are defined for the imperial values, and onTextChanged() signals are used to handle changes in the TextInput

// Define the imperial representation of the metric values of the patient height and weight
property int heightFt : 0
property int heightInches : 0
property int weightLbs: 0
property alias heightCms: patientHeightCm.text // TextInput for height
property alias weightKg: patientWeightKg.text // TextInput for weight

...
TextInput {
id: patientWeightLbs
...
onTextChanged: {
var totalKgs = ScreenFuncs.poundsToKg( patientWeightLbs.text) + 0.5;
console.log( "patientWeightLbs: onTextChanged(); totalKgs: ", totalKgs)
patientForm.weightKg = Math.floor( totalKgs); // local alias
}
...
TextInput {
id: patientWeightKg

onTextChanged: {
var totalLbs = ScreenFuncs.kgToPounds( patientWeightKg.text) + 0.5;
PatientHelper.setPatientWeight( patientWeightKg.text) // C++ slot; will call the setter for the Q_PROPERTY
}
...

The QML code also has a button used to clear the content of the from. The conversion works, however, clearing the form is not reflected in the TextInput elements. To clear the form, a call is made to a Q_INVOKABLE method, and emits are issued for all data members of the class. Everything in the form is cleared with the exception of the height and weight. These are the two fields where onTextChanged is used instead of Binding

I would like to avoid defining the imperial representation in the C++ code. Although the height and weight data members are cleared, it feels as if the QML does do receive/process the NOTIFY. This fails even if the Q_PROPERTY setters are called when clearing the form.
Any suggestions on what is missing?

Thanks,
Daniel

DLabonte
12th September 2017, 16:02
Hi again,

after some trials and errors I have resolved this issue. I was able to correct the binding loop errors by removing the aliases and calling the C++ slot directly when entering weight in pounds or height in ft and inches. So the final implementation using the sample code already given looks like this:

Item {
id: patientForm

// Define the observers; imperial representation of the metric values of the patient height and weight
property int heightFt : 0
property int heightInches : 0
property int weightLbs: 0
...
TextInput {

id: patientWeightLbs

onTextChanged: {
var lbsValue = Number( patientWeightLbs.text);
var totalKgs = (lbsValue > 0) ? Math.floor( ScreenFuncs.poundsToKg( lbsValue) + 0.5) : 0;
PatientHelper.setPatientWeight( totalKgs) // C++ slot; will call the setter for the Q_PROPERTY; do not use an alias
}
}

When clearing the form, the local properties are also cleared.

Does anyone now why the notification was not handled properly by the pound representation when using an alias for the metric (kg) representation?

Daniel