Advanced HMI programming

Dynamic button repeat action

Did you ever see the need to increment or decrement values, for example on a settings screen? Did you want to avoid multiple clicks and would have preferred just keeping a button pressed while the value would continue to increment or decrement? And which would go at a higher speed when pressing the button for a longer time? After reading this article, you’ll know how to do that with your beloved Nextion HMI! And no, there is no need to add to the event code of each button!

Only 4 invisible components and less than 20 lines of code (comment lines don’t count) are required to transform all buttons on a page into repeater buttons. That is so compact that we’ll pack these into a single page template and export it. From then on, if you need buttons with accelerated auto-repeat on a page, go to the page pane, but instead of adding a blank page, import the template and you are done. Automatically, without an additional line of code, all buttons will magically have the repeat functionality!

Using a TouchCap component to hook the additional functionality

Just as a reminder: If you add a TouchCap component to a page, this one will receive all TouchPress and TouchRelease Events and execute its own TouchPress and TouchRelease event code before the component itself, and the TouchCap’s .val attribute will already be set to the id of the pressed or released component. This allows us with the help of a single if() clause to limit our action to a specific component type, buttons whose .type attribute is 98 in our case.

Then we will compare if the newly pressed or released button is the same as before, which makes everything multi-touch safe. On resistive screens without multi-touch, two consecutive TouchPress events without a TouchRelease in-between will never happen. But on a multi-touch screen, one might press a second button while a first one is already be pressed for several seconds, so that it went into the accelerated mode. In that case, we’ll stop the repeater action of the first button, set the timing back to the slower mode and activate the repetition on the second button.

Same for the TouchRelease event: Only if the id of the released button is equal to the actual “button under repetition”, a release event will stop and re-initialize everything. Thus, only a numeric variable component, button_i, is required to retain the .id of the active button.

The Repeat function itself

There is a Timer component, named repeat_tm for this. By default (the slow repeat mode), its .tim attribute is set to 500ms. Thus, the repeat action is executed two times per second. And the action itself is a one-liner, simulating a press on the button whose .id is in button_i.val using indirect addressing: click b[button_i.val], 1

The acceleration

Here, another numeric variable component is required: tick_c, a simple counter which is incremented each time the timer runs. When it reaches 4, the timer interval is divided by 4, so that from then on, the repeat rate is not longer 2/second but 8/second. This is also handled in the timer event code. And that’s it.

The code blocks

Now let’s transform everything said above into code:

tc0 TouchPress
// check if the pressed component is a button and act accordingly
// other conditions might be added with && if not all buttons shall repeat
if(b[tc0.val].type==98)
{
  // for multitouch screens: if a further button is pressed,
  // the repater will restart and act on the last pressed
  if(tc0.val!=button_i.val)
  {
    button_i.val=tc0.val
    repeat_tm.tim=500 // start with slow repeat
    tick_c.val=0 // reinitialize
  }
  repeat_tm.en=1 // start timer if not already running
}
tc0 TouchRelease
// check if the pressed component is a button and act accordingly
// other conditions might be added with && if not all buttons shall repeat
if(b[tc0.val].type==98)
{
  // for multitouch screens: check if the released button is the currently repeated one
  // the repater will stop and reinitialize the timer and tick counter
  if(tc0.val==button_i.val)
  {
    repeat_tm.en=0 // stop timer
    repeat_tm.tim=500 // start the next again  with slow repeat
    tick_c.val=0 // reinitialize
    button_i.val=0 // reinitialize
  }
}
repeat_tm timer event
click b[button_i.val],1 //repeat
tick_c.val++ // increment ticks counter
if(tick_c.val==4)
{
  repeat_tm.tim/=4 // handle acceleration
}

And that’s all. You don’t need to re-type everything, just download our “Button repeater library” in form of a page template and import it into your HMI project where needed: btn_repeater.page

The Demo project as seen in the video above

Create a new HMI project, set your screen type, size, and orientation. Go to the page pane. Right click and select “Import” from the context menu. Select the previously downloaded btn_repeater.page file and click OK. Since we don’t need other pages in our project, delete page0 which will automatically make the btn_repeater page the start page. Now add fonts, 8 button components and 4 number components. This would then look like this:

For the buttons, add the simple event code as if there were no repeater function, it will happen automatically. Here are two examples:

b0 (increment n0) TouchPress event
n0.val++
b7 (decrement n3) TouchPress event
n3.val--

Add the code for the remaining buttons accordingly. Now, either launch the simulator/debugger or upload the project directly to your Nextion HMI and be amazed! Since everything was preloaded and automatically installed with our page template, no additional code was required and all 8 buttons have the dynamic or accelerated repeat function, though!

You are welcome 🙂

Happy Nextioning!