using acebutton in a class with a non static callback function #89
-
I'm trying to add a button to a user interface class with a non-static callback so that UI elements can be updated on button presses. What's the best way to refactor the code below to use a non-static class method as the callback function for a button event? #include <AceButton.h>
using namespace ace_button;
const int BUTTON_PIN = 6;
const int LED_PIN = LED_BUILTIN;
const int LED_ON = HIGH;
const int LED_OFF = LOW;
class UserInterface
{
public:
UserInterface();
int button_presses;
void NonStaticFunction();
void Setup();
void Update();
private:
AceButton *_button;
};
UserInterface::UserInterface()
{
_button = new AceButton(BUTTON_PIN);
}
void UserInterface::NonStaticFunction()
{
button_presses += 1;
}
void UserInterface::Update()
{
_button->check();
}
UserInterface ui;
// An object that handles the event.
class ButtonHandler: public IEventHandler {
public:
void handleEvent(AceButton* /* button */, uint8_t eventType,
uint8_t buttonState) override {
Serial.print(F("handleEvent(): eventType: "));
Serial.print(eventType);
Serial.print(F("; buttonState: "));
Serial.println(buttonState);
switch (eventType) {
case AceButton::kEventPressed:
digitalWrite(LED_PIN, LED_ON);
break;
case AceButton::kEventReleased:
digitalWrite(LED_PIN, LED_OFF);
// how could this be refactored to not use a global variable
ui.NonStaticFunction();
Serial.println(ui.button_presses);
break;
}
}
};
ButtonHandler handleEvent;
void UserInterface::Setup()
{
ButtonConfig* buttonConfig = _button->getButtonConfig();
buttonConfig->setIEventHandler(&handleEvent);
}
void setup() {
delay(1000);
Serial.begin(115200);
while (! Serial);
Serial.println(F("setup(): begin"));
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
ui.Setup();
Serial.println(F("setup(): ready"));
}
void loop() {
ui.Update();
} |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
(Edit: Added some missing words in my initial post for clarity, inside []) There are many ways to avoid passing
class ButtonHandler : public IButtonHandler {
public:
ButtonHandler(UserInterface* ui) : _ui(ui) {
...
}
private:
Userinterface* _ui;
};
class UserInterface : public IButtonHandler {
public:
void Setup() {
_button->getButtonConfig()->setIEventHandler(this);
}
void handleEvent(...) override {
...
NonStaticFunction();
....
}
}; I'm not a huge fan of this type of design because I find code [with] circular dependencies hard to understand, maintain, and refactor in the future.
class UserInterface {
public:
UserInterface(AceButton *button) { ... }
};
class ButtonHandler : public IButtonHandler {
public:
ButtonHandler(UserInterface* ui) { ... }
};
AceButton button(PIN);
UserInterface ui(button);
ButtonHandler handler(ui);
void setup() {
button->getButtonConfig()->setIButtonHandler(handler);
...
} As a side-effect, this avoids creating There are proabbly other ways of designing this, but I hope this gives you some ideas. |
Beta Was this translation helpful? Give feedback.
-
hey @bxparks I feel like my question is very close to this one, but seemingly a bit more simple. I figured posting it here would make more sense than a new question. Unfortunately, I'm struggling to use this information or other info about the right way to do this. I am trying to refactor my project into a separate classes/files primarily so that I can more easily build upon it later. My main.cpp
My Buttons.h
And my Buttons.cpp
My issue is coming down to how I'm passing the handleButton1Event to the setEventHandler. I've been able to discern that because it is a non-static member function, it is a different type than I should be passing, but I'm not understanding the right way to do this. And it seems like this answer SHOULD be the one to clarify it for me...but I'm just not quite getting it. |
Beta Was this translation helpful? Give feedback.
(Edit: Added some missing words in my initial post for clarity, inside [])
There are many ways to avoid passing
ui
as a global variable. The appropriate solution will depend on the complexity of the rest of the application. Here are a few off the top of my head:ui
intoButtonHandler
:UserInterface
implement theIButtonHandler
interface directly, and usesetIEventHandler()
to inject itself into theAceButton
: