Skip to main content
ELero.1
Associate III
August 8, 2022
Solved

TouchGFX kept in memory my previous settings for DigitalClock (removed widget) [solved]

  • August 8, 2022
  • 5 replies
  • 3794 views

Hello,

I created a test project (Riverdi_101STM32H7-4.20) on the side of my main project the other day about managing a clock between multiple screens via a container (see here : https://community.st.com/s/question/0D53W00001g13KBSAY/custom-container-on-multiple-screen-set-digitalclock-problem-solved )

I recently tried to replace my digitalClocks in my screens of my main project by a digitalClock in a container (banner). I copied exactly the same code as in my test project but it failed to work. Indeed, the behavior of the clock was really weird. It started back at 08:25:36 in the first screen (normal because it's the time I set), but then it was 00:00:00 in the second screen and 12:40:28 in the third one.

I tried everything, renaming mytickCounter, renaming the clockbanner widget, but nothing worked.

I printed on my screens the tickCounter/60 to see the problem.

  • 1st screen: number of seconds/ticks goes well. It stops counting (pauses) when I change screens but comes back to the good number when I I get back to the 1st screen.
  • 2d and 3d screen the tick goes back to 0 (it didn't go back to 0 in my test project).

Now, I saw that when I waited 3 seconds in my 1st screen and came back to my 3d, the digitalClock of the 3d screen had passed 3 hours and not 3 seconds. And there was some other weird behavior of time adding up when I changed screens.

Now ... I remember exactly setting in my DigitalClock of the 3d screen (so before I changed it for a banner/container) the time 12:40:28 in the Designer (and 00:00:00 in the 2d screen). But I deleted ALL the digitalClocks of my project in the designer to only leave the one in my banner (which is set to the typical 10:10:00 and not 12:40:28). They had the same name though.

My guess is that the designer or the project kept in memory the information for the previous digitalClocks and didn't erase everything when I deleted the widgets from my screens.

So I tested something out. I recreated from scratch my project, added the banner, copied the GUI entire file (so all my personal code) and now it works perfectly fine, like my test project.

  1. How to be sure that the designer or the project doesn't keep in memory the previous widgets even if they have the same name as the old deleted widgets please?
  2. I've already started from scratch and wouldn't want to do it again if it happened again in the future, could you see if there is a problem with TouchGFX or if I did something wrong, please?
  3. Do you know if there is a way to keep the screens and code of my project but removing all the temporary files (wouldn't want to start from scratch again ^^)

I cannot share my current (failing) project a it has personal info in it, that's why I created a test project in the beginning, to be able to share that one (shared in the link at the beginning of my question).

Thanks a lot in advance,

Eve

This topic has been closed for replies.
Best answer by Yoann KLEIN

Hello @ELero.1​ ,

After discussing those weird issues with my colleagues, we found out that your project needs a complete functioning change.

To help you change your project, I made an example for you, with 3 screens and a clock + counter running simultaneously on the 3 screens, without any bugs or reset of your values.

You will find the project attached to this post.

Of course, I will now explain you what was wrong and what we have done :

1) In your project, the handleTickHandler() method is called in the Banner directly (and then linked to a view). Since you want to share same clock values with all 3 screens, this method should cycle in a common place between this 3 screens : the Model. So, in Model.cpp, you have to include your clock routine inside the tick() method.

void Model::tick()
{
 tickCounter++;
 
 if (tickCounter % 60 == 0)
 {
 secondsCounter++;
 modelListener->updateCounterValue(secondsCounter);
 
 if (++seconds >= 60)
 {
 seconds = 0;
 if (++minutes >= 60)
 {
 minutes = 0;
 if (++hours >= 24)
 {
 hours = 0;
 } // End hours
 } // End minutes
 } // End seconds
 
 updateClock();
 
 } // End modulo
}

Then, you need to declare the updateClock() method, also in the Model.cpp class. This method will provide the updated values to the modelListener.

void Model::updateClock()
{
 // Update the clocks
 modelListener->updateClockValues(hours,minutes,seconds);
 modelListener->updateCounterValue(secondsCounter);
}

2) After that, you will have to declare 2 virtual functions in your ModelListener.hpp class, in order to propagate later the value to the Presenters (because the ScreenPresenter.hpp of your screens inherit from the ModelListener).

 virtual void updateClockValues(int hour, int minute, int second){
 
 }
 
 virtual void updateCounterValue(int secondsCounter){
 
 }

3) Then, in each of your ScreenPresenter.hpp, you have to re-declare those virtual functions. That will enable you to get the clock and counter values into the Presenter class, and to give them later to the Views.

 virtual void updateClockValues(int hour, int minute, int second);
 virtual void updateCounterValue(int secondsCounter);

4) In your ScreenView.hpp files, add a function which will return the CustomContainer object of your screen. That's mandatory because you need to access the container's widgets from the presenter.

 ClockContainer& getClockContainer() {
 return clockContainer1;
 }

5) Then, in your Presenter.cpp, implement the 2 previous methods, in order to call the CustomContainer methods for updating the UI with clock data.

void Screen1Presenter::updateClockValues(int hour, int minute, int second){
 view.getClockContainer().setTime24Hour(hour, minute, second);
}
 
void Screen1Presenter::updateCounterValue(int secondsCounter){
 view.getClockContainer().updateCounter(secondsCounter);
}

6) Don't forget to declare the corresponding methods in the CustomContainer class.

void ClockContainer::setTime24Hour(uint8_t hour, uint8_t minute, uint8_t second)
{
 digitalClock1.setTime24Hour(hour,minute,second);
 digitalClock1.invalidate();
}
 
void ClockContainer::updateCounter(int secondsCounter)
{
 Unicode::snprintf(textArea1Buffer, TEXTAREA1_SIZE, "%d", secondsCounter);
 textArea1.invalidate();
}

That's the best, cleanest, and more efficient way to achieve what you want.

Don't hesitate to ask me if you have question or things you didn't succeed to implement/ didn't understand :)

/Yoann

5 replies

Yoann KLEIN
ST Employee
August 8, 2022

Hello @ELero.1​ ,

What happens now, when you try to run the previous project on your board or on simulator ?

Does it still display wrong number after you ran sucessfully the test project ?

/Yoann

Yoann KLEINST Software Developer | TouchGFX
ELero.1
ELero.1Author
Associate III
August 8, 2022

Hello @Yoann KLEIN​ ,

When I run my test project it works perfectly fine, when I run my main project (version 1=faulty version) it doesn't work well. When I run my main project version 2 (started from scratch again in designer then copy pasting the gui file with all the functions from main v1), it works well. So there's something TouchGFX must keep in memory in my main project v1. I deleted all the digitalClocks from my screens and added the banner but it keeps in memory the parameters I set in those digitalClocks in the screens.

Version 2 works well because I never added the digitalClocks in the screens and removed them.

I searched in the entirety of my code in the IDE but I cannot find the place where it is set to 00:00:00 or 12:40:28 in version 1. And it has been proven that it wasn't in my code because when I copy the files into a new project, the weird behavior disappears.

Eve

Yoann KLEIN
ST Employee
August 15, 2022

Hello @ELero.1​ ,

That is a really weird behavior. Could you share this new version of your project, so I can try it myself and discuss the potential causes with my colleagues ?

Thanks,

/Yoann

Yoann KLEINST Software Developer | TouchGFX
ELero.1
ELero.1Author
Associate III
August 16, 2022

Hello @Yoann KLEIN​ ,

Since I cannot share my full project, I added an image below the banner in my first screen of the test project and it recreated the problem so I'm sending this to you.

Thanks in advance,

Eve

Yoann KLEIN
ST Employee
September 5, 2022

Hello @ELero.1​ ,

Sorry, I was busy on other things lately.

I tried to reproduce your issue, but I don't obtain the same behavior as the one you mentioned.

In the project you shared me, the "print" counter works normally when you switch from Screen1>Screen2>Screen3, not depending whether you put images above or below in the widget list.

But, when I switch from Screen2>Screen1 again, this "print" counter gets initialized to 7620, for some reason:

0693W00000SuUcdQAF.png 

Does that sound familiar to you, or do you observe a complete different behavior in your project ?

/Yoann

Yoann KLEINST Software Developer | TouchGFX
ELero.1
ELero.1Author
Associate III
September 5, 2022

Hello @Yoann KLEIN​ ,

I have found out maybe a clue that could help us:

No problems between the screens if you put the banner at the exact same position in the 3 screens (here for example position number 4 but it also works when everything is in position 2)

0693W00000SuUw9QAF.pngBut the moment I change this (for example 4th position in screen 1 and 5th in screen 2 and 3), the moment I switch from screen 1 to 2, the counter is starting at 0 on screen 2 and increments perfectly between screen 2 and 3 no matter how many times I change. When I get back to screen 1, it counts on its own counter (starting from where it left off the previous time we were in screen 1). I therefore think that there is one counter keeping in memory where it is for screen 1 and one other counter keeping also in memory where it is for screens 2 and 3.

0693W00000SuV0BQAV.png 

But something else happens when I choose positions s1:4, s2:4, s3:2,

Screen 1 → screen 2 : everything goes well, continues counting.

Screen 2 → screen 3: starts back at 00:00:00 (cnt=0).

Screen 3 → screen 2: 14:10:30 (cnt=0) not like the first example when it started back from where it left off in screen1.

0693W00000SuV2WQAV.png 

Other example s1:4, s2:2, s3:2

Screen 1 → screen 2 : gets back to 00:00:00 (cnt=0)

Screen 2 → screen 3: continues counting from the time of screen 2 so for example 00:00:25 (cnt=25)

Screen 3 → screen 2: same, continues counting

Screen 2 → screen 1: 15:00:27 (cnt=0)

0693W00000SuV4mQAF.pngI didn't manage to get the counter initialized to 7620 like you, it always came back to 0 when there was a problem with the time.

I'm really wondering if there isn't different tick counters based on the position the custom container is in.

Kind regards,

Eve

Yoann KLEIN
Yoann KLEINBest answer
ST Employee
September 5, 2022

Hello @ELero.1​ ,

After discussing those weird issues with my colleagues, we found out that your project needs a complete functioning change.

To help you change your project, I made an example for you, with 3 screens and a clock + counter running simultaneously on the 3 screens, without any bugs or reset of your values.

You will find the project attached to this post.

Of course, I will now explain you what was wrong and what we have done :

1) In your project, the handleTickHandler() method is called in the Banner directly (and then linked to a view). Since you want to share same clock values with all 3 screens, this method should cycle in a common place between this 3 screens : the Model. So, in Model.cpp, you have to include your clock routine inside the tick() method.

void Model::tick()
{
 tickCounter++;
 
 if (tickCounter % 60 == 0)
 {
 secondsCounter++;
 modelListener->updateCounterValue(secondsCounter);
 
 if (++seconds >= 60)
 {
 seconds = 0;
 if (++minutes >= 60)
 {
 minutes = 0;
 if (++hours >= 24)
 {
 hours = 0;
 } // End hours
 } // End minutes
 } // End seconds
 
 updateClock();
 
 } // End modulo
}

Then, you need to declare the updateClock() method, also in the Model.cpp class. This method will provide the updated values to the modelListener.

void Model::updateClock()
{
 // Update the clocks
 modelListener->updateClockValues(hours,minutes,seconds);
 modelListener->updateCounterValue(secondsCounter);
}

2) After that, you will have to declare 2 virtual functions in your ModelListener.hpp class, in order to propagate later the value to the Presenters (because the ScreenPresenter.hpp of your screens inherit from the ModelListener).

 virtual void updateClockValues(int hour, int minute, int second){
 
 }
 
 virtual void updateCounterValue(int secondsCounter){
 
 }

3) Then, in each of your ScreenPresenter.hpp, you have to re-declare those virtual functions. That will enable you to get the clock and counter values into the Presenter class, and to give them later to the Views.

 virtual void updateClockValues(int hour, int minute, int second);
 virtual void updateCounterValue(int secondsCounter);

4) In your ScreenView.hpp files, add a function which will return the CustomContainer object of your screen. That's mandatory because you need to access the container's widgets from the presenter.

 ClockContainer& getClockContainer() {
 return clockContainer1;
 }

5) Then, in your Presenter.cpp, implement the 2 previous methods, in order to call the CustomContainer methods for updating the UI with clock data.

void Screen1Presenter::updateClockValues(int hour, int minute, int second){
 view.getClockContainer().setTime24Hour(hour, minute, second);
}
 
void Screen1Presenter::updateCounterValue(int secondsCounter){
 view.getClockContainer().updateCounter(secondsCounter);
}

6) Don't forget to declare the corresponding methods in the CustomContainer class.

void ClockContainer::setTime24Hour(uint8_t hour, uint8_t minute, uint8_t second)
{
 digitalClock1.setTime24Hour(hour,minute,second);
 digitalClock1.invalidate();
}
 
void ClockContainer::updateCounter(int secondsCounter)
{
 Unicode::snprintf(textArea1Buffer, TEXTAREA1_SIZE, "%d", secondsCounter);
 textArea1.invalidate();
}

That's the best, cleanest, and more efficient way to achieve what you want.

Don't hesitate to ask me if you have question or things you didn't succeed to implement/ didn't understand :)

/Yoann

Yoann KLEINST Software Developer | TouchGFX
ELero.1
ELero.1Author
Associate III
September 6, 2022

Hello @Yoann KLEIN​ ,

Thanks a lot for the help, it works in my bigger project too now. It's just a little bulky since I have to add the code in all my screens (I have A LOT of screens with the banner). But if that's the best way to do it, so be it ^^

I have two questions:

  • I don't understand why we pass through the ModelListener (Presenter of the screens inherit from the ModelListener) because we could previously obtain the time thanks to a function like this in the presenter.hpp of the screens, without passing by the listener. What's the added value of adding this step? The getTime function returns the clockvalues from the model.
MyClock getTimePres()
{
 return model->getTime();
}

  • Why create a function to get the container "getContainer" in ScreenView.hpp, and not just include the container file in the header of the presenter of the screen <gui/containers/Banner.hpp> ?

Thanks in advance,

Eve

Yoann KLEIN
ST Employee
September 6, 2022

Hello @ELero.1​ ,

  • Sorry I think I forgot something. Indeed, you can also use this method from the Presenter. Actually, in ScreenPresenter.cpp you can call the updateClock() method from the model in your activate() method. This will enable you to refresh your clock instantly every time you switch back to Screen1. Of course, you will have to do the same for every screens.
void Screen1Presenter::activate()
{
 model->updateClock();
}
  • The banner object is protected inside the ScreenViewBase class. That means that you will have to inherit from this class in your presenter to be able to call it directly. The ScreenView already inherits from ScreenViewBase, that's why it's more simple to do it that way.

/Yoann

Yoann KLEINST Software Developer | TouchGFX