Skip to main content
prathima
Associate III
February 26, 2020
Solved

long touch detect on STM32L4R9AI-eval

  • February 26, 2020
  • 14 replies
  • 4355 views

hello...

I am working on STM32L4R9AI-EVAL board..i want to detect the long touch..means in one screen if i do long touch it has to go to the other screen...I need deep explanation

how do i do this ....any example code

thank you

This topic has been closed for replies.
Best answer by Alexandre RENOUX

A way of doing that is to create a button class that allows you to receive an event on both press and release action. Then, you just implement the handleTickEvent() in your screenView. As @Martin KJELDSEN​ mentioned, referring to Button, AbstractButton and at the code generated when creating a FlexButton in the Designer can help you considerably.

Here is a possible version :

customButtonContainer.hpp

#ifndef CUSTOMBUTTONCONTAINER_HPP
#define CUSTOMBUTTONCONTAINER_HPP
 
#include <touchgfx/containers/Container.hpp>
#include <touchgfx/widgets/Image.hpp>
 
namespace touchgfx
{
/**
 * @class CustomButtonTrigger CustomButtonTrigger.hpp
 */
class CustomButtonContainer : public Container
{
public:
 
 /**
 * @fn CustomButtonContainer::CustomButtonContainer()
 *
 * @brief Default constructor.
 */
 CustomButtonContainer() : pressed(false), alpha(255), up(), down(), action(0)
 {
 setTouchable(true);
 buttonImage.setXY(0, 0);
 add(buttonImage);
 }
 
 /**
 * @fn virtual CustomButtonContainer::~CustomButtonContainer()
 *
 * @brief Destructor.
 */
 virtual ~CustomButtonContainer() {}
 
 /**
 * @fn virtual void CustomButtonContainer::setBitmaps(const Bitmap& bmpReleased, const Bitmap& bmpPressed)
 *
 * @brief Sets the bitmaps.
 *
 * @param bmpReleased The bitmap released.
 * @param bmpPressed The bitmap pressed.
 */
 virtual void setBitmaps(const Bitmap& bmpReleased, const Bitmap& bmpPressed)
 {
 up = bmpReleased;
 down = bmpPressed;
 setWidth(down.getWidth());
 setHeight(down.getHeight());
 
 handlePressedUpdated();
 }
 
 /**
 * @fn void CustomButtonContainer::setBitmapXY(uint16_t x, uint16_t y)
 *
 * @brief Sets bitmap xy.
 *
 * @param x An uint16_t to process.
 * @param y An uint16_t to process.
 */
 void setBitmapXY(uint16_t x, uint16_t y)
 {
 buttonImage.setXY(x, y);
 }
 
 /**
 * @fn Bitmap CustomButtonContainer::getCurrentlyDisplayedBitmap() const
 *
 * @brief Gets currently displayed bitmap.
 *
 * @return The currently displayed bitmap.
 */
 Bitmap getCurrentlyDisplayedBitmap() const
 {
 return (pressed ? down : up);
 }
 
 /**
 * @fn void CustomButtonContainer::setPressed(bool isPressed)
 *
 * @brief Sets the pressed state.
 *
 * @param isPressed True if is pressed, false if not.
 */
 void setPressed(bool isPressed)
 {
 pressed = isPressed;
 handlePressedUpdated();
 }
 
 /**
 * @fn bool CustomButtonContainer::getPressed()
 *
 * @brief Gets the pressed state.
 *
 * @return True if it succeeds, false if it fails.
 */
 bool getPressed()
 {
 return pressed;
 }
 
 /**
 * @fn void CustomButtonContainer::setAlpha(uint8_t newAlpha)
 *
 * @brief Sets an alpha value.
 *
 * @param newAlpha The new alpha.
 */
 void setAlpha(uint8_t newAlpha)
 {
 alpha = newAlpha;
 handleAlphaUpdated();
 }
 
 /**
 * @fn uint8_t CustomButtonContainer::getAlpha() const
 *
 * @brief Gets the alpha.
 *
 * @return The alpha value.
 */
 uint8_t getAlpha() const
 {
 return alpha;
 }
 
 /**
 * @fn void CustomButtonContainer::setAction(GenericCallback< const CustomButtonContainer&, bool& >& callback)
 *
 * @brief Sets an action callback.
 *
 * @param callback The callback.
 */
 void setAction(GenericCallback< const CustomButtonContainer&, bool& >& callback)
 {
 action = &callback;
 }
 
 /**
 * @fn virtual void CustomButtonContainer::handleClickEvent(const ClickEvent& event)
 *
 * @brief Handles the click event described by event.
 *
 * @param event The event.
 */
 virtual void handleClickEvent(const ClickEvent& event)
 {
 bool wasPressed = getPressed();
 bool newPressedValue = (event.getType() == ClickEvent::PRESSED);
 if ((newPressedValue && !wasPressed) || (!newPressedValue && wasPressed))
 {
 setPressed(newPressedValue);
 invalidate();
 if (action->isValid())
 {
 action->execute(*this, pressed);
 }
 }
 }
 
 
protected:
 bool pressed; ///< True if pressed
 uint8_t alpha; ///< The current alpha value. 255 denotes solid, 0 denotes completely transparent.
 Image buttonImage; ///< The button image
 Bitmap up; ///< The image to display when button is released.
 Bitmap down; ///< The image to display when button is pressed.
 
 GenericCallback< const CustomButtonContainer&, bool&>* action; ///< The action
 
 /**
 * @fn virtual void CustomButtonContainer::handlePressedUpdated()
 *
 * @brief Handles the pressed updated.
 */
 virtual void handlePressedUpdated() 
 {
 buttonImage.setBitmap(pressed ? down : up);
 }
 
 /**
 * @fn virtual void CustomButtonContainer::handleAlphaUpdated()
 *
 * @brief Handles the alpha updated.
 */
 virtual void handleAlphaUpdated()
 {
 buttonImage.setAlpha(alpha);
 }
};
 
 
} // namespace touchgfx
 
#endif // CUSTOMBUTTONCONTAINER_HPP

Screen1View.hpp

#ifndef SCREEN1VIEW_HPP
#define SCREEN1VIEW_HPP
 
#include <gui_generated/screen1_screen/Screen1ViewBase.hpp>
#include <gui/screen1_screen/Screen1Presenter.hpp>
#include <gui/common/customButtonContainer.hpp>
 
class Screen1View : public Screen1ViewBase
{
public:
 Screen1View();
 virtual ~Screen1View() {}
 virtual void setupScreen();
 virtual void tearDownScreen();
 
 virtual void handleTickEvent();
protected:
 touchgfx::CustomButtonContainer customButton1, customButton2;
 
 uint16_t counter;
 bool buttonPressedFlag;
 
 Callback<Screen1View, const CustomButtonContainer&, bool&> buttonEventCallback;
 
 void handleButtonEvent(const CustomButtonContainer& element, bool& buttonState);
};
 
#endif // SCREEN1VIEW_HPP

Screen1View.cpp

#include <gui/screen1_screen/Screen1View.hpp>
#include "BitmapDatabase.hpp"
 
Screen1View::Screen1View():
 counter(0),
 buttonPressedFlag(false),
 buttonEventCallback(this, &Screen1View::handleButtonEvent)
{
 customButton1.setBitmaps(Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_ID), Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_PRESSED_ID));
 customButton1.setBitmapXY(0, 0);
 customButton1.setPosition(285, 200, 230, 60);
 
 customButton2.setBitmaps(Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_ID), Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_PRESSED_ID));
 customButton2.setBitmapXY(0, 0);
 customButton2.setPosition(20, 20, 230, 60);
 
 add(customButton1);
 add(customButton2);
 
 customButton1.setAction(buttonEventCallback);
 customButton2.setAction(buttonEventCallback);
}
 
void Screen1View::setupScreen()
{
 Screen1ViewBase::setupScreen();
}
 
void Screen1View::tearDownScreen()
{
 Screen1ViewBase::tearDownScreen();
}
 
void Screen1View::handleButtonEvent(const CustomButtonContainer& element, bool& buttonState)
{
 if(buttonState)
 {
 if(&element == &customButton1)
 {
 touchgfx_printf("pressed 1\n");
 buttonPressedFlag = true;
 }
 else if(&element == &customButton2)
 {
 touchgfx_printf("pressed 2\n");
 }
 }
 else
 {
 if(&element == &customButton1)
 {
 touchgfx_printf("released 1\n");
 buttonPressedFlag = false;
 counter = 0;
 }
 else if(&element == &customButton2)
 {
 touchgfx_printf("released 2\n");
 }
 }
}
 
void Screen1View::handleTickEvent()
{
 if(buttonPressedFlag)
 {
 counter++;
 if(counter%180 == 0) // 3 seconds has passed
 {
 //move to another screen
 }
 }
}

/Alexandre

14 replies

Martin KJELDSEN
Principal III
February 27, 2020

Look at how a Button and AbstractButton is implemented. The callback is fired, in the case of a normal button, when the user presses the button (not releases). It's easy to create your own subclass LongPressButton that registers itself to receive ticks, and you simply count those until you're satisfied and fire the event once the press is "long".

I've written this button a thousand times, so i'll look around my harddrive :) But until them, look at Button, AbstractButton and look for widgets that register themselves as "Timer widgets". You should be able to do it easily. Source code for a lot of widgets is available in the distribution.

/Martin

Martin KJELDSEN
Principal III
February 27, 2020

Okay, this explains how to register a widget as a timer widget to receive ticks - Hence the handleTickEvent() method. I'll leave it up to you to decide how you want to call fadeIn() - Take a look at Button and AbstractButton and see how Button offers pressed/released images and how AbstractButton offers a clickHandler() - Combine the two to get what you want. E.g. once the button is pressed, call fadeIn() (could be private function) - handleTickEvent() will be called every tick. Unregister timer widget once number of ticks = long press, and invoke the callback (check AbstractButton to see how this is done).

So, the code below is just to show you how to register timer widgets and react to ticks. The FadeButton actually does not handle fadeIn() internally.

void FadeButton::fadeIn()
{
 fadingOut = false;
 Application::getInstance()->registerTimerWidget(this);
}
 
void FadeButton::fadeOut()
{
 fadingOut = true;
 Application::getInstance()->registerTimerWidget(this);
 
 // Deactivate during fade out
 setTouchable(false);
}
 
void FadeButton::handleTickEvent()
{
 if (fadingOut)
 {
 if (alpha <= 2) // Be careful of not underrunning datatype
 {
 alpha = 0;
 Application::getInstance()->unregisterTimerWidget(this);
 }
 else
 {
 alpha -= 3;
 }
 }
 else // fading in
 {
 if (alpha >= 253) // Be careful of not overrunning datatype
 {
 alpha = 255;
 Application::getInstance()->unregisterTimerWidget(this);
 // Activate after fade in is finished
 setTouchable(true);
 }
 else
 {
 alpha += 3;
 invalidate();
 }
 }
 
 // Force redrawing of FadeButton, since changing alpha does not yield redraw.
 invalidate();
}

prathima
prathimaAuthor
Associate III
February 28, 2020

Application::getInstance()->unregisterTimerWidget(this);

when am writing this project in my screen1...am getting error at "this"in above statement

it saying argument of type "screenview1*" is incompatable with screen parameter of type screen1 "touchgfx::drawable*"

Martin KJELDSEN
Principal III
March 6, 2020

You register timer widget from a widget, not a screen. For instance, if you're inheriting from AbstractButton, you will register timer widget when the button pressed handler is activated.

/Martin

prathima
prathimaAuthor
Associate III
February 29, 2020

Hello....Martin

I am not getting properly what your trying to say....my need is when i long touch the screen let say 3 sec, i want to take another action like i want to go to other screen.....that before releasing the touch ..i hope you understand what i mean to say.......

and the code that you have provided was ,i just can't able to understand what your intention,,,there

Can you explain bit more information......

thank you

Alexandre RENOUX
Alexandre RENOUXBest answer
Visitor II
March 5, 2020

A way of doing that is to create a button class that allows you to receive an event on both press and release action. Then, you just implement the handleTickEvent() in your screenView. As @Martin KJELDSEN​ mentioned, referring to Button, AbstractButton and at the code generated when creating a FlexButton in the Designer can help you considerably.

Here is a possible version :

customButtonContainer.hpp

#ifndef CUSTOMBUTTONCONTAINER_HPP
#define CUSTOMBUTTONCONTAINER_HPP
 
#include <touchgfx/containers/Container.hpp>
#include <touchgfx/widgets/Image.hpp>
 
namespace touchgfx
{
/**
 * @class CustomButtonTrigger CustomButtonTrigger.hpp
 */
class CustomButtonContainer : public Container
{
public:
 
 /**
 * @fn CustomButtonContainer::CustomButtonContainer()
 *
 * @brief Default constructor.
 */
 CustomButtonContainer() : pressed(false), alpha(255), up(), down(), action(0)
 {
 setTouchable(true);
 buttonImage.setXY(0, 0);
 add(buttonImage);
 }
 
 /**
 * @fn virtual CustomButtonContainer::~CustomButtonContainer()
 *
 * @brief Destructor.
 */
 virtual ~CustomButtonContainer() {}
 
 /**
 * @fn virtual void CustomButtonContainer::setBitmaps(const Bitmap& bmpReleased, const Bitmap& bmpPressed)
 *
 * @brief Sets the bitmaps.
 *
 * @param bmpReleased The bitmap released.
 * @param bmpPressed The bitmap pressed.
 */
 virtual void setBitmaps(const Bitmap& bmpReleased, const Bitmap& bmpPressed)
 {
 up = bmpReleased;
 down = bmpPressed;
 setWidth(down.getWidth());
 setHeight(down.getHeight());
 
 handlePressedUpdated();
 }
 
 /**
 * @fn void CustomButtonContainer::setBitmapXY(uint16_t x, uint16_t y)
 *
 * @brief Sets bitmap xy.
 *
 * @param x An uint16_t to process.
 * @param y An uint16_t to process.
 */
 void setBitmapXY(uint16_t x, uint16_t y)
 {
 buttonImage.setXY(x, y);
 }
 
 /**
 * @fn Bitmap CustomButtonContainer::getCurrentlyDisplayedBitmap() const
 *
 * @brief Gets currently displayed bitmap.
 *
 * @return The currently displayed bitmap.
 */
 Bitmap getCurrentlyDisplayedBitmap() const
 {
 return (pressed ? down : up);
 }
 
 /**
 * @fn void CustomButtonContainer::setPressed(bool isPressed)
 *
 * @brief Sets the pressed state.
 *
 * @param isPressed True if is pressed, false if not.
 */
 void setPressed(bool isPressed)
 {
 pressed = isPressed;
 handlePressedUpdated();
 }
 
 /**
 * @fn bool CustomButtonContainer::getPressed()
 *
 * @brief Gets the pressed state.
 *
 * @return True if it succeeds, false if it fails.
 */
 bool getPressed()
 {
 return pressed;
 }
 
 /**
 * @fn void CustomButtonContainer::setAlpha(uint8_t newAlpha)
 *
 * @brief Sets an alpha value.
 *
 * @param newAlpha The new alpha.
 */
 void setAlpha(uint8_t newAlpha)
 {
 alpha = newAlpha;
 handleAlphaUpdated();
 }
 
 /**
 * @fn uint8_t CustomButtonContainer::getAlpha() const
 *
 * @brief Gets the alpha.
 *
 * @return The alpha value.
 */
 uint8_t getAlpha() const
 {
 return alpha;
 }
 
 /**
 * @fn void CustomButtonContainer::setAction(GenericCallback< const CustomButtonContainer&, bool& >& callback)
 *
 * @brief Sets an action callback.
 *
 * @param callback The callback.
 */
 void setAction(GenericCallback< const CustomButtonContainer&, bool& >& callback)
 {
 action = &callback;
 }
 
 /**
 * @fn virtual void CustomButtonContainer::handleClickEvent(const ClickEvent& event)
 *
 * @brief Handles the click event described by event.
 *
 * @param event The event.
 */
 virtual void handleClickEvent(const ClickEvent& event)
 {
 bool wasPressed = getPressed();
 bool newPressedValue = (event.getType() == ClickEvent::PRESSED);
 if ((newPressedValue && !wasPressed) || (!newPressedValue && wasPressed))
 {
 setPressed(newPressedValue);
 invalidate();
 if (action->isValid())
 {
 action->execute(*this, pressed);
 }
 }
 }
 
 
protected:
 bool pressed; ///< True if pressed
 uint8_t alpha; ///< The current alpha value. 255 denotes solid, 0 denotes completely transparent.
 Image buttonImage; ///< The button image
 Bitmap up; ///< The image to display when button is released.
 Bitmap down; ///< The image to display when button is pressed.
 
 GenericCallback< const CustomButtonContainer&, bool&>* action; ///< The action
 
 /**
 * @fn virtual void CustomButtonContainer::handlePressedUpdated()
 *
 * @brief Handles the pressed updated.
 */
 virtual void handlePressedUpdated() 
 {
 buttonImage.setBitmap(pressed ? down : up);
 }
 
 /**
 * @fn virtual void CustomButtonContainer::handleAlphaUpdated()
 *
 * @brief Handles the alpha updated.
 */
 virtual void handleAlphaUpdated()
 {
 buttonImage.setAlpha(alpha);
 }
};
 
 
} // namespace touchgfx
 
#endif // CUSTOMBUTTONCONTAINER_HPP

Screen1View.hpp

#ifndef SCREEN1VIEW_HPP
#define SCREEN1VIEW_HPP
 
#include <gui_generated/screen1_screen/Screen1ViewBase.hpp>
#include <gui/screen1_screen/Screen1Presenter.hpp>
#include <gui/common/customButtonContainer.hpp>
 
class Screen1View : public Screen1ViewBase
{
public:
 Screen1View();
 virtual ~Screen1View() {}
 virtual void setupScreen();
 virtual void tearDownScreen();
 
 virtual void handleTickEvent();
protected:
 touchgfx::CustomButtonContainer customButton1, customButton2;
 
 uint16_t counter;
 bool buttonPressedFlag;
 
 Callback<Screen1View, const CustomButtonContainer&, bool&> buttonEventCallback;
 
 void handleButtonEvent(const CustomButtonContainer& element, bool& buttonState);
};
 
#endif // SCREEN1VIEW_HPP

Screen1View.cpp

#include <gui/screen1_screen/Screen1View.hpp>
#include "BitmapDatabase.hpp"
 
Screen1View::Screen1View():
 counter(0),
 buttonPressedFlag(false),
 buttonEventCallback(this, &Screen1View::handleButtonEvent)
{
 customButton1.setBitmaps(Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_ID), Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_PRESSED_ID));
 customButton1.setBitmapXY(0, 0);
 customButton1.setPosition(285, 200, 230, 60);
 
 customButton2.setBitmaps(Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_ID), Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_PRESSED_ID));
 customButton2.setBitmapXY(0, 0);
 customButton2.setPosition(20, 20, 230, 60);
 
 add(customButton1);
 add(customButton2);
 
 customButton1.setAction(buttonEventCallback);
 customButton2.setAction(buttonEventCallback);
}
 
void Screen1View::setupScreen()
{
 Screen1ViewBase::setupScreen();
}
 
void Screen1View::tearDownScreen()
{
 Screen1ViewBase::tearDownScreen();
}
 
void Screen1View::handleButtonEvent(const CustomButtonContainer& element, bool& buttonState)
{
 if(buttonState)
 {
 if(&element == &customButton1)
 {
 touchgfx_printf("pressed 1\n");
 buttonPressedFlag = true;
 }
 else if(&element == &customButton2)
 {
 touchgfx_printf("pressed 2\n");
 }
 }
 else
 {
 if(&element == &customButton1)
 {
 touchgfx_printf("released 1\n");
 buttonPressedFlag = false;
 counter = 0;
 }
 else if(&element == &customButton2)
 {
 touchgfx_printf("released 2\n");
 }
 }
}
 
void Screen1View::handleTickEvent()
{
 if(buttonPressedFlag)
 {
 counter++;
 if(counter%180 == 0) // 3 seconds has passed
 {
 //move to another screen
 }
 }
}

/Alexandre

Alexandre RENOUX
Visitor II
March 5, 2020

I forgot to mention that in the Screen1View.cpp, the initialization should be in the setupScreen() function. In this specific case, where I have only one screen it is the same behavior but in your case it should be in setupScreen() as follows

#include <gui/screen1_screen/Screen1View.hpp>
#include "BitmapDatabase.hpp"
#include <touchgfx/Color.hpp>
 
Screen1View::Screen1View():
 counter(0),
 buttonPressedFlag(false),
 buttonEventCallback(this, &Screen1View::handleButtonEvent)
{
}
 
void Screen1View::setupScreen()
{
 Screen1ViewBase::setupScreen();
 
 customButton1.setBitmaps(Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_ID), Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_PRESSED_ID));
 customButton1.setBitmapXY(0, 0);
 customButton1.setPosition(285, 200, 230, 60);
 
 customButton2.setBitmaps(Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_ID), Bitmap(BITMAP_BLUE_BUTTONS_ROUND_EDGE_MEDIUM_PRESSED_ID));
 customButton2.setBitmapXY(0, 0);
 customButton2.setPosition(20, 20, 230, 60);
 
 add(customButton1);
 add(customButton2);
 
 customButton1.setAction(buttonEventCallback);
 customButton2.setAction(buttonEventCallback);
}

prathima
prathimaAuthor
Associate III
March 6, 2020

hello

what is customButtonContainer.hpp...how you taken it designer,,,

you have taken one custom container in that you have taken container and flex button eith image size.....can u Provide designer file....

prathima
prathimaAuthor
Associate III
March 6, 2020

how do you done it in the touchgfx designer

Alexandre RENOUX
Visitor II
March 6, 2020

It was not done using the Designer, it's a class completely written by the programmer. Therefore, you will not see it in the Designer but only when you run the application. Every custom widget you create will not be displayed in the Designer.

customButtonContainer is an arbitrary name you can call it whatever you want.

/Alexandre

prathima
prathimaAuthor
Associate III
March 9, 2020

This a new file you have added into project ...or you have modified any existing file....

please mention where your doing it....and what is the result so that i can modify according to my application...

Thank you..

RGajd.1
Associate
June 11, 2020

Hi @prathima​ 

You can also detect long touch in handleTickEvent if You use flexButton with Touch trigger.

Then You can detect how long is pressed the button.

Pseudocode:

bool btTouched; 
uint32_t timeTouched; // variable for long touch time measurment
 
void buttonClicked() { // virtual function declared in TouchGFX designer
 btTouched = true;
 timeTouched = 0;
}
 
void screenView::handleTickEvent() {
 if(myFlexButton.getPressed()) timeTouched += 16; // every tick has around 16ms
 if(timeTouched>500 && btTouched) {
 btTouched = false; // avoid retriggering
 // do anything when 500ms elapsed
 }

Regards,

R. Gajda

}