- Note
- This page describes an example listed in 7GUIs.
- Fahrenheit to Celsius and vice versa.
Challenges: bidirectional data flow, user-provided text input.
The task is to build a frame containing two textfields TC and TF representing the temperature in Celsius and Fahrenheit, respectively. Initially, both TC and TF are empty. When the user enters a numerical value into TC the corresponding value in TF is automatically updated and vice versa. When the user enters a non-numerical string into TC the value in TF is not updated and vice versa. The formula for converting a temperature C in Celsius into a temperature F in Fahrenheit is C = (F - 32) * (5/9) and the dual direction is F = C * (9/5) + 32.
Temperature Converter increases the complexity of Counter by having bidirectional data flow between the Celsius and Fahrenheit inputs and the need to check the user input for validity. A good solution will make the bidirectional dependency very clear with minimal boilerplate code.
#include <AUI/Platform/Entry.h>
#include <AUI/Platform/AWindow.h>
#include <AUI/Util/UIBuildingHelpers.h>
#include <AUI/View/AButton.h>
#include "AUI/View/ATextField.h"
#include "AUI/View/ANumberPicker.h"
using namespace declarative;
auto myPicker() {
return _new<ANumberPicker>()
let {
it->setMin(-999);
it->setMax(999);
};
}
class TemperatureConverterWindow :
public AWindow {
public:
TemperatureConverterWindow() : AWindow("AUI - 7GUIs - TempConv", 300_dp, 50_dp) {
Horizontal {
it->focus();
},
Label { "°C" },
Label {
"=" }
with_style { Margin { {}, 16_dp } },
Label { "°F" },
},
});
connect(mFahrenheit.changed, [&] { mCelsius = (*mFahrenheit - 32.f) * (5.f / 9.f); });
connect(mCelsius.changed, [&] { mFahrenheit = *mCelsius * (9.f / 5.f) + 32.f; });
}
private:
AProperty<int> mCelsius, mFahrenheit;
};
_new<TemperatureConverterWindow>()->show();
return 0;
}
void setContents(const _< AViewContainer > &container)
Moves (like via std::move) all children and layout of the specified container to this container.
Represents a window in the underlying windowing system.
Definition AWindow.h:45
static void biConnect(PropertySource &&propertySource, PropertyDestination &&propertyDestination)
Connects source property to the destination property and opposite (bidirectionally).
Definition AObject.h:156
static decltype(auto) connect(const Signal &signal, Object *object, Function &&function)
Connects signal to the slot of the specified object.
Definition AObject.h:86
#define let
Performs multiple operations on a single object without repeating its name (in place) This function c...
Definition kAUI.h:262
#define with_style
Allows to define a style to the view right in place.
Definition kAUI.h:287
#define AUI_ENTRY
Application entry point.
Definition Entry.h:90
Comparison to Jetpack Compose#
Here's implementation of the same app with Jetpack Compose:
package ...
import ...
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
CounterTheme {
Counter()
}
}
}
}
@Composable
fun TemperatureBiConverter() {
var celsiusInputData by remember { mutableStateOf("0.0") }
var fahrenheitInputData by remember { mutableStateOf("32.0") }
Row(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
OutlinedTextField(
modifier = Modifier.weight(1f),
value = celsiusInputData,
onValueChange = { input ->
celsiusInputData = input
input.toFloatOrNull()?.also {
fahrenheitInputData = (it * (9f / 5f) + 32f).toString()
}
},
label = { Text("Celsius") }
)
Text(
text = "=", fontSize = 18.sp,
modifier = Modifier.padding(horizontal = 8.dp)
)
OutlinedTextField(
modifier = Modifier.weight(1f),
value = fahrenheitInputData,
onValueChange = { input ->
fahrenheitInputData = input
input.toFloatOrNull()
?.also {
celsiusInputData = ((it - 32) * (5f / 9f)).toString()
}
},
label = { Text("Fahrenheit") }
)
}
}
Source Files#