How to make work simple button class with callback? - c++

How to make simple button class to call custom function on press. Some code example:
class Button
{
public:
Button();
Draw();
Press();
SetCallback(void(*cback)());
priate:
void (*callback)();
}
void Button::SetCallback(void(*cback)())
{
callback = cback;
}
class GameState
{
...
}
class MenuState : public GameState
{
Button *btn;
}
class Game
{
...
}
bool Game::Init()
{
std::unique_ptr<GameState> menu = std::unique_ptr<MenuState>(new MenuState);
}
void Game::PopState(){
states.pop_back();
}
How to set callback in button to Game::PopState() function in this example. I need Then I press button it call Game::PopState function.

What you're looking for is a tutorial on function pointers, which can be found here.
If you need to pass an argument, your button function pointer should either have a pointer or a reference to your Game object, as member functions require references( to which object owns the function call). If the popstate function in your Game class is private you may need to make it public or a friend function.
You should be able to modify the example below by replacing the string reference with a reference to the Game object. If you need a more generic callback look into templates(better but a bit more complicated) or type punning(generally considered bad practice)
#include <iostream>
#include <string>
class Button
{
public:
void SetCallback(void(*cback)(std::string&));
void Press(std::string str){
//Make sure some sort of check is done in order to prevent undefined behavior from a call
if(callback != nullptr)
callback(str);
}
Button(){
callback = nullptr;
}
private:
void (*callback)(std::string&);
};
void Button::SetCallback(void(*cback)(std::string&))
{
callback = cback;
}
//Method 2 for calling function
void DoStuff(std::string& str){
std::cout << str;
}
int main(void){
Button btn;
//Method 1 for calling function, replace body with Game.PopStates();
auto foo = [](std::string& str){ std::cout<<str.size();};
btn.SetCallback(foo);
btn.Press("A");
//Method 2 for calling function
btn.SetCallback(&DoStuff);
btn.Press("\nPressed Button");
return 0;
}
Your function pointer for Game should be something like this:
void SetCallback(void(*cback)(Game&));
You can call it like this:
auto foo = [](Game& g){ g.DoStuffInClass(); };
btn.SetCallback(foo);
btn.Press(game);
The above examples work fine and are usually all you need to do, but this article here goes more in-depth about member function pointers. The main takeaway from the article is typedef is another way for writing member function pointers like shown:
typedef int (Fred::*FredMemFn)(char x, float y); // Please do this!
All the above does(when implemented with PopStates), however, is lock your button callback into using void functions called by your Game objects, which limits your ability to use the button. You can use a pointer instead of a reference if you want to allow special cases for acting without a Game object, but either way your Game object has to find some way of being put in inside your callback.

Related

Pass an object function by reference

I'm trying to pass an object function by reference. I can only make it work with a simple function.
Code:
class Light {
...... omitted some code here, not relevant .......
void toggle2() {
Serial.println("TOGGLE");
};
}
class Button {
public:
OneButton pin;
void single();
Button(int _pin, void (&_single)() ){
pin = OneButton(_pin, false, false);
_single();
pin.attachClick(_single);
}
};
Light lights[] = {
Light("Cozinha", CONTROLLINO_A15, CONTROLLINO_R0)
};
Button buttons[] = {
Button(CONTROLLINO_A0, lights[0].toggle2)
};
the code above gives an error on button declaration
no instance of constructor "Button::Button" matches the argument list -- argument types are: (int, void ())
toggle2 function is a void function but maybe the program is confusing because of the Light type?
If I make the code with a simple function it works well, like this:
void toggle() {
Serial.println("TOGGLE");
};
Button buttons[] = {
Button(CONTROLLINO_A0, toggle)
};
Any suggestion??
I've removed all of the noise from the code sample to focus on the how-tos of passing and calling a function pointer.
class Light {
public:
void toggle2() {
};
};
class Button {
public:
Button(int _pin,
void (Light::*single)(), // the function. Compiler needs to know the class
// the function belongs to or it'll assume a free
// function
Light& light) // class instance to invoke the member function on
{
(light.*single)(); // note the weird-looking invocation syntax.
// all of it is essential and easily <expletive deleted>ed up.
// C++FAQ recommends using a macro to keep from leaving
// anything out. They don't recommend macros lightly.
// note you will want to store these two variables as Button
// class members rather than using them immediately.
// I did the call in the constructor to keep the example simple.
}
};
Light lights[] = {
Light()
};
Button buttons[] = {
Button(1, // the pin
&Light::toggle2, // address of the fully-qualified member function
lights[0]) // instance to invoke member function on
};
The gory details, and some very good suggestions, can be found at Pointers to Member Functions
Note that since Button must now carry around the a reference to the Light instance it uses, making lights and Buttons local variable variables in a sufficiently widely scoped function is an attractive option.
For completeness, here's what it looks like with std::function and a Lambda Expression.
#include <functional>
class Light {
public:
void toggle2() {
};
};
class Button {
public:
Button(int _pin,
std::function<void()> single){ // std::function contains the necessary
// instance reference
single(); // no muss, no fuss function call
}
};
Light lights[] = {
Light()
};
Button buttons[] = {
Button(1,
[](){lights[0].toggle2();}) // lambda expression wrapping the function call
};

How to pass lambda function by pointer?

I am a new in c++ maybe I miss something, but actually what I need to do is: I have a class that processing something in other thread, during this processing I need that it invoke a callback for progress.
How I see I can do it, I need to declarate pointer (maybe shared_ptr) for my callback function as a class member, than I have a setter in order to pass pointer to callback and then I can use it. A few issues here are how to pass it correctly? How to invoke pointer on function?
My implementation is:
class RobocopyCopy
{
//Public members
public:
typedef std::function<void(int)> TVoidIntCallback;
RobocopyCopy * set_monitoring_done_callback(TVoidIntCallback monitoring_done_callback)
{
m_pMonitoring_done_callback = &monitoring_done_callback;
return this;
}
//This method executes in background
void execute()
{
...
//and here I need to invoke my callback
(TVoidIntCallback *)m_pMonitoring_done_callback(777); //but this is not correct
private:
TVoidIntCallback * m_pMonitoring_done_callback;
...
}
and final implementation of this should be like this (I think) :
RobocopyCopy robocopy;
robocopy.set_monitoring_done_callback([this](int my_progress) {
printf("Progress is :: %d", my_progress);
});
So, as I mentioned above questions is :
how to pass this function callback as a lambda and save in Robocopy class as a pointer
How to invoke this function correctly, because this (TVoidIntCallback *)m_pMonitoring_done_callback(777); doesn't work.
I am using VC++ I hope this code will be successful for you.
class RobocopyCopy
{
typedef std::function<void(int)> TVoidIntCallback;
TVoidIntCallback evnt;
public:
RobocopyCopy* set_monitoring_done_callback(TVoidIntCallback
monitoring_done_callback)
{
//set callBack function from out side.
evnt = monitoring_done_callback;
return this;
}
void execute() {
//invoke your callBack
evnt(1000000);
}
};
int main()
{
RobocopyCopy obj;
obj.set_monitoring_done_callback([](int data) {
std::cout << data << "\n";
})->execute();
}

Override a method when creating an object in Arduino/C++

I am working on a C++ Arduino sketch that creates a GUI on an OLED display. I want to have buttons buttons that all do different things when you press them. In Java, I can simply override the method when creating an anonymous class like this:
class Example {
public void method() {
}
}
Example e = new Example() {
#Override
public void method() {
//do something
}
};
So my question is: Can I do this in an C++?
As arduino sketch are in fact C/C++, you could do the same as in Java.
class Button {
virtual void push() = 0;
}
class PowerButton : public Button {
virtual void push() {
shutdown();
}
}
Notice the virtual keyword, it's used to declare a method overidable, the "= 0" means pure virtual (the address of the method is 0). It simply says that this method is not implemented in this class, the class became abstract as in Java.
Also, the virtual keyword is not mandatory, but if you don't put it, C++ will just call the method of the given type and not from the real type.
Take a look there
But, the difference with Java is that you can't create an anonymous class directly in the code. Instead, maybe take a look for lambda.
For example, the class Button would became :
class Button {
public:
Button(const std::function<void()> &pushCallback) :
mPushCallback(pushCallback) {}
void push() { mPushCallback(); }
private:
const std::function<void()> mPushCallback;
And then the usage:
Button powerButton([]() {
powerOff();
});
Brackets are use to "capture" a variable, for example this, &str { myMethodInMyClass(str); }
Parenthesis are used to pass parameters
The std::function class take the function type as type parameter, a function that take a string as const ref and an int and that return an int will look like this : std::function<int(const std::string &, int)>

Pass in and store function pointer to object

I'm writing a basic GUI framework as a school project and I'm trying to create an object (think a button) that, when interacted with, will call a particular function.
To explain my setup simply, I have a button class and a window manager class. The window manager is instantiated once from main and many buttons are instantiated from the window manager, with all 3 being in separate files. Nothing should go in main.
I'm a bit of a C++ noob, but as far as I can see, it would be best to use function pointers for this. My idea is to instantiate my button object then to pass it a function pointer to a function that when called would edit another object.
Firstly, I presume that the best way to do this would be to have the functions be defined locally to the window manager otherwise I'd have trouble with access? I had wanted to initially not have them listed in the header to make things easier (with a view to creating a kind of drag and drop editor in the future).
Second, how would I pass (from the window manager) a pointer to a function (which would exist within the window manager) to an instance of a button object? I thought I'd be able to treat it similarly to any other variable and do something as:
Button btn1 = new Button();
btn1->SetText("Button 1");
btn1->SetOnClick(functionpointer);
But, after looking through various tutorials I don't quite understand how I'd implement this. For example, how do I even define somewhere to store the function pointer in my button class?
Would appreciate any insight, I think I've confused myself enough for one day.
EDIT: Seems I should add that my Button and WindowManager classes are in separate files and my entry point so to speak is an instance of WindowManager. All the setup of my GUI including assigning a function to a button would be done in the constructor of WindowManager.
Here is one approach by using function pointers. However using std::function makes the code more flexible. For example you can use lambda expressions.
To use std::function you can simply change the typedef to typedef std::function<void(Button*)> EventCallback; and add the include #include <functional>
#include <iostream>
class Button
{
public:
// Typedef of the event function signature
typedef void(*EventCallback)(Button* button);
Button() : onClick(nullptr) {}
// Set the function to call
void SetOnClick(EventCallback func) { onClick = func; }
// Call the function if exists
void OnClick() {
if (onClick)
onClick(this);
}
private:
// This stores the function pointer for the button
EventCallback onClick;
};
// just some example function that has the same signature as Button::EventCallback
void MyEventFunc(Button* button)
{
std::cout << "Triggered" << std::endl;
}
int main() {
Button button;
button.SetOnClick(&MyEventFunc);
button.OnClick();
return 0;
}
http://ideone.com/x5O49B
You can do it with pointer to member function like this (in this case Button has to know WindowManager);
class WindowManager
{
public:
typedef void (WindowManager::* TypeOnClickFunc)( void );
void anyfunction( void ) {}
};
class Button
{
public:
Button( WindowManager * wm ) :_windowmanager( wm ) {}
void SetOnClick( WindowManager::TypeOnClickFunc fptr )
{
_onclickfptr = fptr;
}
void OnClick( void )
{
(_windowmanager->*_onclickfptr )( ); // indirect call WindowManager::anyfunction
}
private:
WindowManager *_windowmanager;
WindowManager::TypeOnClickFunc _onclickfptr;
};
WindowManager wm;
Button *btn1 = new Button( &wm );
btn1->SetOnClick( &WindowManager::anyfunction );
... or with pointer to static function like this ...
class WindowManager
{
public:
typedef void (*TypeOnClickFunc)( void );
static void anyfunction( void ) {}
};
class Button
{
public:
Button() {}
void SetOnClick( WindowManager::TypeOnClickFunc fptr )
{
_onclickfptr = fptr;
}
void OnClick( void )
{
(*_onclickfptr )( ); // indirect call static WindowManager::anyfunction
}
private:
WindowManager::TypeOnClickFunc _onclickfptr;
};
Button *btn1 = new Button();
btn1->SetOnClick( &WindowManager::anyfunction );
... with typdef in Button instead of WindowManager ...
class WindowManager
{
public:
static void anyfunction( void ) {}
};
class Button
{
public:
typedef void (*TypeOnClickFunc)( void );
Button() {}
void SetOnClick( TypeOnClickFunc fptr )
{
_onclickfptr = fptr;
}
void OnClick( void )
{
(*_onclickfptr )( ); // indirect call
}
private:
TypeOnClickFunc _onclickfptr;
};
Button *btn1 = new Button();
btn1->SetOnClick( &WindowManager::anyfunction );

C++ an object with its own method?

I'm sorry, this is probably a stupid question. I am obviously misunderstanding something fundamental about object oriented programming. I am used to C and am now trying to use C++.
I have some buttons in a class called Button. Each button does something different. What I want to write is something like this:
Button button1;
Button button2;
...
void button1::onClick () {
...
}
void button2::onClick () {
...
}
But that does not work ("button 1 is not a class, namespace or enumeration" - yes I know!). I know I could just make a separate class for each button:
class button1_class : public Button {
public:
void onclick () {
...
}
} button1;
class button2_class : public Button {
...
}
But to me it 'feels' wrong to make a class when I know for sure it will only have one member.
I'm using Agui, a GUI library for Allegro 5.
EDIT
Thanks for the responses. While they are all helpful and (I think) all valid answers, nobody has actually said yet "no you cannot have an object with its own unique method because..."
So for example, if object1 is of type ObjectClass then object1 is not allowed to have a method (a member function) that is unique to object1, but rather possesses only the methods that are defined as part of ObjectClass. Is that right?
I'm sorry I did not include my actual use case. I was kind of more interested in just getting my head around OOP so that I can do it properly on my own.
EDIT2
Looking at the responses in more detail I suppose it is possible with lambda expressions, it's just not in the way I imagined it. Thanks again
The natural C++ way is to do as vsoftco explained, with virtuals and inheritance.
However, if your Button class has already everything needed, and the only thing that changes between the buttons is the unique (trhow-away) action to be performed, you may want to consider this alternative:
class Button {
function<void()> f;
public:
Button(function<void()> mf) : f(mf) {}
void onClick() { f(); }
};
This variant of your class uses a function object (think of it as a kind of function pointer but much more flexible to use).
You can then use it with lambda-functions as in this example:
int main(int ac, char**av)
{
Button button1([&]() { cout << "Hello 1!\n"; });
Button button2 ([]() { cout << "Hello 2!\n"; });
button1.onClick();
button2.onClick();
}
If the buttons have different functionalities, best thing to do is to create a BaseButton class in which you mark the onclick() as virtual (or make it pure virtual, which will make BaseButton an abstract class), then derive each other button from BaseButton, making sure to override onclick() in each derived class. You then need to use the buttons via a reference or pointer to a BaseButton, this way you achieve what is called "polymorphic behaviour".
For example:
class BaseButton
{
virtual void onclick() {/*implement here or declare pure virtual*/}
};
class RedButton: public BaseButton /* overrides only onclick */
{
void onclick() override { /*specific implementation for Red Buttons */}
};
class ShinyRedButton: public RedButton /* overrides only onclick */
{
void onclick() override { /*specific implementation for Shiny Red Buttons */}
};
then use it like (C++14 smart pointers)
std::unique_ptr<BaseButton> bb = new ShinyRedButton;
bb->onclick(); // will pick up the "right" ShinyRedButton::onclick()` function
You can do this in many ways.
Using a Button class where button objects have a pointer to methods that are invoked onClick. In C you would do this using a callback and you can also do it that way in C++:
class Button {
using funType = void(void);
public:
Button(funType* callback) : function(callback) { }
void onClick() { function(); }
private:
funType* function;
};
However do take note that function pointers are error prone, can't really be inlined by the compiler, and should generally be avoided. This method also works with capture-less lambdas.
Button red([] { std::cout << "Red button\n"; });
Button green(&green_button_function);
Creating different Button objects with different onClick methods on the fly. C++ has a mechanism to do this called templates:
template <class Fun>
class Button {
public:
Button(Fun f) : functor(f) { }
void onClick() { functor(); }
private:
Fun functor;
};
template <class Fun>
Button<Fun> make_button(Fun f) { return Button<Fun>(f); }
I am omitting details such as references on purpose here.
You could then use the Button class with callbacks as well as lambdas in the following way:
auto green = make_button([] { std::cout << "Green button pressed!\n"; });
auto red = make_button(&red_button_function);
You need to use auto with this method because otherwise you would have to specify the type of the functionality by hand, which is not possible e.g. for lambda objects.
Using polymorphism as shown by vsoftco, where you create separate classes for each Button functionality. Or you can make a ButtonAction abstract class to which Button has a reference. Then you implement different functionalities in different classes, but stay with one Button class. This is known as the strategy pattern:
class ButtonAction {
public:
virtual void onClick() = 0;
};
class Button {
public:
Button(std::unique_ptr<ButtonAction> action) :
action_(std::move(action)) {}
void onClick() { action_->onClick(); }
private:
std::unique_ptr<ButtonAction> action_;
};
class RedButtonAction : public ButtonAction {
void onClick() override { red(); }
};
class GreenButtonAction : public ButtonAction {
void onClick() override { green(); }
};
Using this method requires constructing Buttons from ButtonAction unique_ptrs
Button red(std::unique_ptr<ButtonAction>(new RedButtonAction));
Button green(std::unique_ptr<ButtonAction>(new GreenButtonAction));
You're right in that, if each button is fundamentally the same but needs different event handlers bound to it, implementing a new type for each one is not quite right.
Instead your Button type would have a member function that allows users to "attach" an event handler, and a member function to invoke it.
class Button
{
public:
Button()
: onClickHandler()
{}
void setOnClickHandler(std::function<void()> callback)
{
onClickHandler = callback;
}
friend class UI;
private:
void onClick()
{
onClickHandler();
}
std::function<void()> onClickHandler;
};
Then your user does:
void foo()
{
std::cout << "Some buttons do this!\n";
}
Button btn;
btn.setOnClickHandler(foo);
And your program's internals will set up things such that your window manager (above I've assumed that it's some class called UI) invokes btn.onClick() for you, which, since you "attached" foo, will end up invoking foo.
(In modern C++ you'd probably make use of lambda functions to tidy this up, but the above is a simple example to showcase the general design idea.)
In this way, you can attach different handlers to different Button instances, but the Button interface itself is stable.
This is similar to how, for example, you manipulate the DOM in JavaScript.
Using a std::function is the key here. You will have the virtual call overheard and potential memory allocation if your callable (lambda, function, member function) is large. This achieves your requirements of a single type executing different callbacks without defining an class inheritance. Also using uniform initialization makes it very convenient to construct Button class with a lambda without manually creating a constructor.
Live example:
http://coliru.stacked-crooked.com/a/f9007c3f103f3ffe
#include <functional>
#include <vector>
using namespace std;
struct Button
{
function<void()> OnClick;
};
int main()
{
vector<Button> buttons =
{
{[] { printf("Button0::OnClick()\n"); }},
{[] { printf("Button1::OnClick()\n"); }},
{[] { printf("Button2::OnClick()\n"); }},
};
for(auto&& button : buttons)
button.OnClick();
}
Your Agui library supports a signaling system, with the member function addActionListener.
This allows you to derive a class from agui::ActionListener to perform the specific task intended for one or more buttons:
class SimpleActionListener : public agui::ActionListener
{
public:
virtual void actionPerformed(const agui::ActionEvent &evt)
{
std::cout << "Button pushed" << std::endl;
}
};
The object above can be attached to a button's "press" action with:
SimpleActionListener simpleAL;
button1.addActionListener(&simpleAL);