2025-04-10 2:14 AM
As the title, I can't get the difference between the Model and ModelListener.
From what I've understood the Model class is used to get and store/send the data coming between the phisical part of the microcontroller (i.e. peripheral) and the GUI. The ModelListener instead is the interface that checks if these data have been updated and inform specific Presenters when needed.
I have kind of understood the documentation provided here but, first of all, why in the Model.cpp it checks if modelListener != 0?
I can't understand where and how modelListener takes its value.
I've checked the E-Bike Demo and the process of passing data from the Model to the GUI is a little bit difference. In the Demo the Model.hpp has a bind function
void bind(ModelListener* listener)
{
modelListener = listener;
}
With the ModelListener.hpp having another bind to the Model class
class ModelListener
{
public:
ModelListener() : model(0) {}
virtual ~ModelListener() {}
void bind(Model* m)
{
model = m;
}
virtual void gaugeStartAnimationIsDone() {};
protected:
Model* model;
};
And in the various .CPP Presenters of the Views it returns the data directly from the model, not from the modelListener like:
int DashboardSmallPresenter::getHourTemperature(int hr)
{
return model->getHourTemperature(hr);
}
So why this disilign between the two usages?
Solved! Go to Solution.
2025-04-10 6:11 AM
Hello Nico.
I agree that the Flash-limited E-bike demo is not the best example to showcase the Model-View-Presenter structure. This is primarily due to the simplicity of the data transferred between the Model and the View.
In general, you can follow these guidelines:
Based on these guidelines, one could argue that the Model Listener should have been used in the Flash-limited E-bike demo for updating values such as speed and power.
However, a much better and more realistic MVP example is available in TouchGFX Designer: the HVAC IoT Demo.
This demo was originally designed to run on the STM32H7S78-DK board in an IoT setup, where it would receive data from AWS through a FreeRTOS thread. However, in the version available in TouchGFX Designer, this has been replaced by a data simulator located in gui\src\common\hvac.cpp.
Let's go through how the kitchen temperature is updated in relation to the MainView in the demo as an example:
1. In Model::tick(), the Model::checkForIncomingData() function is called, which checks if there is new incoming data through the xHVAC_ReceiveFromController(&incomingEvent, 0) function.
2. The current kitchen temperature is then stored in the Model.
3. The virtual function updateTemperature() in the Model Listener is called.
4. In MainPresenter.hpp a virtual updateTemperature() function is declared. Any presenter that wants to subscribe to this function being called must declare this function.
5. In MainPresenter.cpp, updateTemperature() is defined as this:
void MainPresenter::updateTemperature(Rooms roomId, float temperature)
{
view.updateRoomTemperature(roomId, temperature);
}
6. updateRoomTemperature() that is called in step 5 is implemented in MainView.cpp
void MainView::updateRoomTemperature(Rooms roomId, float temperature)
{
switch (roomId)
{
case KITCHEN:
kitchenCardContainer.setTemperature(temperature, presenter->getIsFahrenheit());
break;
...
}
}
7. And thereby the actual value in the view is updated.
However, the steps above only address the scenario where the kitchen temperature has changed. What should we do when we enter the view and have not yet received the first new kitchen temperature? In this case, we use a getter function. The flow is illustrated below.
1. In MainView::setupScreen(), MainView::setTemperatures() is called.
2. MainView::setTemperatures() calls presenter->getRoomTemeprature() to set the shown kitchen temperature accordingly
// Set temperatures in correct unit
kitchenCardContainer.setTemperature(presenter->getRoomTemperature(KITCHEN), presenter->getIsFahrenheit());
3. MainPresenter::getRoomTemperature() calls Model::getRoomTemperature()
float MainPresenter::getRoomTemperature(Rooms roomId)
{
return model->getRoomTemperature(roomId);
}
4. Model::getRoomTemperature() returns the saved value of kitchenTemperature
float Model::getRoomTemperature(Rooms roomId)
{
switch (roomId)
{
case KITCHEN:
return kitchenTemperature;
break;
...
}
}
5. And thus, the value is returned to the view.
I hope this provides a clearer overview of the Model-View-Presenter (MVP) structure and highlights why both the Model and the Model Listener are very valuable components. The Model cannot update the presenter/view by itself; this needs to go through the Model Listener.
I encourage you to explore the entire demo. Additionally, you can check out the example called "Understanding Application Structure," which is also available in TouchGFX Designer.
Best regards,
Johan
2025-04-10 6:11 AM
Hello Nico.
I agree that the Flash-limited E-bike demo is not the best example to showcase the Model-View-Presenter structure. This is primarily due to the simplicity of the data transferred between the Model and the View.
In general, you can follow these guidelines:
Based on these guidelines, one could argue that the Model Listener should have been used in the Flash-limited E-bike demo for updating values such as speed and power.
However, a much better and more realistic MVP example is available in TouchGFX Designer: the HVAC IoT Demo.
This demo was originally designed to run on the STM32H7S78-DK board in an IoT setup, where it would receive data from AWS through a FreeRTOS thread. However, in the version available in TouchGFX Designer, this has been replaced by a data simulator located in gui\src\common\hvac.cpp.
Let's go through how the kitchen temperature is updated in relation to the MainView in the demo as an example:
1. In Model::tick(), the Model::checkForIncomingData() function is called, which checks if there is new incoming data through the xHVAC_ReceiveFromController(&incomingEvent, 0) function.
2. The current kitchen temperature is then stored in the Model.
3. The virtual function updateTemperature() in the Model Listener is called.
4. In MainPresenter.hpp a virtual updateTemperature() function is declared. Any presenter that wants to subscribe to this function being called must declare this function.
5. In MainPresenter.cpp, updateTemperature() is defined as this:
void MainPresenter::updateTemperature(Rooms roomId, float temperature)
{
view.updateRoomTemperature(roomId, temperature);
}
6. updateRoomTemperature() that is called in step 5 is implemented in MainView.cpp
void MainView::updateRoomTemperature(Rooms roomId, float temperature)
{
switch (roomId)
{
case KITCHEN:
kitchenCardContainer.setTemperature(temperature, presenter->getIsFahrenheit());
break;
...
}
}
7. And thereby the actual value in the view is updated.
However, the steps above only address the scenario where the kitchen temperature has changed. What should we do when we enter the view and have not yet received the first new kitchen temperature? In this case, we use a getter function. The flow is illustrated below.
1. In MainView::setupScreen(), MainView::setTemperatures() is called.
2. MainView::setTemperatures() calls presenter->getRoomTemeprature() to set the shown kitchen temperature accordingly
// Set temperatures in correct unit
kitchenCardContainer.setTemperature(presenter->getRoomTemperature(KITCHEN), presenter->getIsFahrenheit());
3. MainPresenter::getRoomTemperature() calls Model::getRoomTemperature()
float MainPresenter::getRoomTemperature(Rooms roomId)
{
return model->getRoomTemperature(roomId);
}
4. Model::getRoomTemperature() returns the saved value of kitchenTemperature
float Model::getRoomTemperature(Rooms roomId)
{
switch (roomId)
{
case KITCHEN:
return kitchenTemperature;
break;
...
}
}
5. And thus, the value is returned to the view.
I hope this provides a clearer overview of the Model-View-Presenter (MVP) structure and highlights why both the Model and the Model Listener are very valuable components. The Model cannot update the presenter/view by itself; this needs to go through the Model Listener.
I encourage you to explore the entire demo. Additionally, you can check out the example called "Understanding Application Structure," which is also available in TouchGFX Designer.
Best regards,
Johan
2025-04-10 11:34 PM
Hi @JohanAstrup that made a lot of sense, thanks a lot for the explanation
Also, I will look for sure into the IoT example
Thanks again, cheers