cancel
Showing results for 
Search instead for 
Did you mean: 

TextArea with Wildcard displays residue of previous value when modified.

DSwea.1
Associate III

The Problem

A TextArea with one wildcard is used to display a floating point number centered in its field. When a larger number is overwritten with a smaller number, the new number is centered in the TextArea, but a “residue�? of the previous, larger number, remains visible on both sides.

The issue is seen in the GUI of a client project for an industrial meter and process monitor, and is reproduced here in it's own TouchGFX Designer project which runs in the Simulator.

Simple Screen

The project includes a single screen with a white background, and three additional objects:

  • A blue Flex Button (setBtn), labeled “Set 1.0�?
  • A single-wildcard TextArea (numberText( with initial setting “345.67�?
  • A red Box background (numberBgd) to the TextArea.

Screen Appearance

0693W00000UnfacQAB.pngTextArea

The TextArea (numberText) is of fixed width, non-autosize, includes a buffer with a 16 character size. and has an initial setting og 345.67:

0693W00000UnfamQAB.png 

0693W00000UnfawQAB.pngText Resource

The text resource (numberDisp) specifies the default font, centered display, and single wildcard (<>):

0693W00000UnfbBQAR.pngText Background

The red background (numberBnd) to the text is a simple box with no outline:

0693W00000UnfbGQAR.pngButton

The blue button (setBtn) is a Flex Button with a background and text:

0693W00000UnfbLQAR.pngInteraction

The screen defines an interaction for a click on the setBtn to execute inline C++ code:

0693W00000UnfbQQAR.pngScenario 1: Text Replacement Error

In the first attempt, the following code places the number “1.00�? into the text buffer associated with TextArea numberText:

    touchgfx::Unicode::snprintfFloat(numberTextBuffer, NUMBERTEXT_SIZE, "%.2f", 1.0f);
    numberTextBuffer[NUMBERTEXT_SIZE-1] = 0;     // ensure string termination
 
    numberText.resizeToCurrentTextWithAlignment();
    numberText.invalidate();
 

One would expect that numberText would now display “1.0�? against its red background. But, instead, the following screen is displayed:

0693W00000UnfbVQAR.pngIt goes without saying that this reading, interpreted as valid by factory personnel, might result in a seriously incorrect response, or even dangerous actions. So, this display error demands careful examination to determine the cause.

Scenario 2: Text Replacement Success

In this scenario, the code is modified to also invalidate the red rectangle background to numberText.  

    touchgfx::Unicode::snprintfFloat(numberTextBuffer, NUMBERTEXT_SIZE, "%.2f", 1.0f);
    numberTextBuffer[NUMBERTEXT_SIZE-1] = 0;     // ensure string termination
 
    numberText.resizeToCurrentTextWithAlignment();
    numberText.invalidate();
 
    Rect toDraw = numberBgd.getRect();
    invalidateRect(toDraw);

And, in fact, this does seem to “solve�? the problem, with the new value now displayed correctly:

0693W00000UnfbHQAR.pngScenario 3: Text Replacement Error

But now, in order to make reorganization of the screen easier, we decide to place the screen objects inside a simple container:

0693W00000UnfbzQAB.pngAnd then, use the same code as before to update the display:

    touchgfx::Unicode::snprintfFloat(numberTextBuffer, NUMBERTEXT_SIZE, "%.2f", 1.0f);
    numberTextBuffer[NUMBERTEXT_SIZE-1] = 0;     // ensure string termination
 
    numberText.resizeToCurrentTextWithAlignment();
    numberText.invalidate();
 
    Rect toDraw = numberBgd.getRect();
    invalidateRect(toDraw);

But, we once again see the problem of “residue�? of the original contents of numberText remaining on screen.

Scenario 4: Text Replacement Success

Finally, extrapolating the idea that appeared to fix the issue in the first case, we add code to also invalidate the container as well:

    touchgfx::Unicode::snprintfFloat(numberTextBuffer, NUMBERTEXT_SIZE, "%.2f", 1.0f);
    numberTextBuffer[NUMBERTEXT_SIZE-1] = 0;     // ensure string termination
 
    numberText.resizeToCurrentTextWithAlignment();
    numberText.invalidate();
 
    Rect toDraw = numberBgd.getRect();
    invalidateRect(toDraw);
 
    container.invalidate();

And this does indeed “correct�? the issue once again:

Conclusion

The problem is that one does not know where to stop with this approach. Depending on a screen's complexity, do we reach a point where we must invalidate the entire screen in order to guarantee the correct display of change to a single value?

And why doesn't the original approach of invalidating the changed TextArea alone result in correct display?

As I indicated earlier, this is far from a trivial issue, as it can possibly result in disastrous actions in response to an incorrect reading. And, when a number of interacting quantities are being monitored, it may be near impossible to test in advance every situation that may lead to the issue described here.

So, we really must understand why this problem occurs, and what actions, precautions we may take in design and coding to be certain that it will not happen.

1 ACCEPTED SOLUTION

Accepted Solutions
Osman SOYKURT
ST Employee

Hello DSwea.1,

Thank you for your very detailed description of your issue. I'll try to be as detailed in my answer as you did.

"Invalidating" is the action to rewrite on the framebuffer and so, in your screen. The issue you're facing is not a bug. Indeed, as described in our documentation you need to invalidate the entire area that needs to be redrawn. So in your example, when you're calling resizeToCurrentTextWithAlignment() function you're actually reducing your text area size. So in the framebuffer the allocated space for this area is also reduced. Then when you call invalidate() you'll just rewrite inside this reduced sized area in your framebuffer. That means that the other numbers at the edges of your text area will still be visible, because in the framebuffer, they've not been updated.

What you'll need to do instead, is to call invalidate() before resizeToCurrentTextWithAlignment() so the numbers at the edges will be also included in this area to be "refreshed", and after you can call resizeToCurrentTextWithAlignment() to reduce your text area size.

This is also why in your scenario 2 and 4 it's working fine, because you're asking to redraw your entire rectangle area in the framebuffer, that includes the numbers of the edge of your reduced sized text area.

I invite you to use the F2 shortcut in simulator to see all the invalidated areas during runtime. You can pause with F9 and go tick by tick with F10. That way you'll se what is invalidated and what is not ;)

/Osman

Osman SOYKURT
ST Software Developer | TouchGFX

View solution in original post

3 REPLIES 3
Osman SOYKURT
ST Employee

Hello DSwea.1,

Thank you for your very detailed description of your issue. I'll try to be as detailed in my answer as you did.

"Invalidating" is the action to rewrite on the framebuffer and so, in your screen. The issue you're facing is not a bug. Indeed, as described in our documentation you need to invalidate the entire area that needs to be redrawn. So in your example, when you're calling resizeToCurrentTextWithAlignment() function you're actually reducing your text area size. So in the framebuffer the allocated space for this area is also reduced. Then when you call invalidate() you'll just rewrite inside this reduced sized area in your framebuffer. That means that the other numbers at the edges of your text area will still be visible, because in the framebuffer, they've not been updated.

What you'll need to do instead, is to call invalidate() before resizeToCurrentTextWithAlignment() so the numbers at the edges will be also included in this area to be "refreshed", and after you can call resizeToCurrentTextWithAlignment() to reduce your text area size.

This is also why in your scenario 2 and 4 it's working fine, because you're asking to redraw your entire rectangle area in the framebuffer, that includes the numbers of the edge of your reduced sized text area.

I invite you to use the F2 shortcut in simulator to see all the invalidated areas during runtime. You can pause with F9 and go tick by tick with F10. That way you'll se what is invalidated and what is not ;)

/Osman

Osman SOYKURT
ST Software Developer | TouchGFX
DSwea.1
Associate III

Hi Osman,

Thank you for your helpful reply regarding invalidating. Your comments and the documentation reference make it perfectly clear why I was having the problem in question, and why invalidating a larger surrounding area provided a workaround.

It would be great if every programmer learning a new environment first made a detailed study of the existing documentation (which, in the case of TGFX I note has been given a lot of effort), and then proceeded with all of it imprinted in memory for ready recall when coding. However, even if this were possible, documentation, like code itself, must be continuously revised if it is to remain useful and effective.

So, when I first read your reply, as one who tries always to proceed only after a survey of documentation and the development environment, I was a bit embarrassed by my oversight. And, in retrospect, the problem seems obvious.

As it turns out, in my post, I failed to include the fact that we're operating in version 4.17 of TGFX---the version is fixed by my client's policy during phase 1 of the development effort. And, in fact, the documentation reference you provide, which clearly explains the issue here, was not present in 4.17 documentation, at lease not in the place it occupies in the 4.20 document ("Position and Size"), and not anywhere that I could locate by searching in 4.17:

4.20 Documentation

0693W00000Uo6nTQAR.png 

4.17 Documentation

0693W00000Uo6ndQAB.png 

So, finally, all's well that ends well. And, when my current client or a future client selects 4.20 (or whatever then is the current version), I promise once again to go over the docs to make sure I'm aware of all the new information and nuance that has been added.

Best wishes and thanks again,

Donald

DSwea.1
Associate III

Thanks also for the suggestions regarding the Function keys in the simulator. It's only quite recently that we've adapted our application to run in the simulator, as we've needed to make a number of code emulations to substitute in roles normally assumed by code in our FreeRTOS tasking environment.

These functions are indeed helpful. But I do have an observation: it seems that the RGB color values reported in the simulator match those reported in PhotoShop for a screen shot from the simulator. But the reported numbers are generally a bit off from the hex values that we set in our code.

For example, the following code (copied from several separate locations):

#define GUI_COLOR(VAL24)        (0xff000000 | (VAL24))
#define COLOR_RED4                  0xef1649
 
#define SCREEN_HOME_INFO_BGD_COLOR  COLOR_RED4
 
flowVelocField.setFieldBgdColor(GUI_COLOR(SCREEN_HOME_INFO_BGD_COLOR));

which eventually reaches the Box::setColor() with the correct value:

    void setColor(colortype color)
    {
        this->color = color;
    }
 
Name : color
	Details:4293858889
	Default:4293858889
	Decimal:-1108407
	Hex:0xffef1649
	Binary:11111111111011110001011001001001
	Octal:037773613111

but is reported in both the simulator and Photoshop as 0xef144a rather than 0xef1649. It would seem that the simulator would report the actual value that was set, and that Photoshop's indication would be perhaps biased by the display's characteristics. It's not off in any noticeable way, but this is puzzling. And such is the case for every color we use in the application---the values reported in the simulator and PS are all just a bit off from the original setting.