Goal is to create a simple class that can be used for GUI buttons. My question is how can I define a function variable, and then when constructing a 'button' define which function should be called when clicked.

This obviously isn't right, but just to get the idea:

class button {
private:
function whenClicked;
public:
button(function f1) : whenClicked(f1) {}

};

I've read that its possible to pass a function as a parameter, but I don't think that's what I'm looking for. I'd like to have all the functions defined once when created, and not pass the function every time the button's called. I think that will make it easier to cycle through a list or array and check if pressed and execute the appropriate function.

I hope I'm making sense here, thanks for any help

Recommended Answers

All 3 Replies

Function pointers are the way to go:

class button
{
  public:
    button(void (*onClick)(button&)) : onClick(onClick) {}
    void click() {onClick(*this);}
  private:
    void (*onClick)(button&);
};

void myOnClick(button& owner)
{
  cout << "Button clicked!" << endl;
}

int main()
{
  button myButton(myOnClick);
  myButton.click();
}

If you don't want to use function pointers, you can make button an abstract class:

class button
{
  public:
    button() {}
    void click() {onClick();}
  protected:
    virtual void onClick()=0;
};

class MyButton : public button
{
  private:
    void onClick()
    {
      cout << "Button clicked!" << endl;
    }
};

int main()
{
  MyButton myButton;
  myButton.click();
}

That would require you to create a new class for every button with different functionality, though.

Thanks for the quick response.

Function pointers was the term I was looking for, thanks.

It seems the implication here is any function called using the onClick pointer has to accept the same arguments as any other button, correct?
So, if myOnClick1 needed parameters besides (button& owner), there could be a problem.

For anyone else reading, the website below had a pretty in depth tutorial on function pointers:
http://www.newty.de/fpt/index.html

Thanks

It seems the implication here is any function called using the onClick pointer has to accept the same arguments as any other button, correct?
So, if myOnClick1 needed parameters besides (button& owner), there could be a problem.

That's right. After all, where are these other parameters supposed to come from? The click() function wouldn't know anything about them.
However, if you're using the second approach with inheritance, you can have an onClick function that takes different parameters:

class button
{
  public:
    button() {}
    virtual void click() {onClick();}
  protected:
    virtual void onClick()=0;
};

class MyButton : public button
{
  public:
    void click(int a,int b) {onClick(a,b);}

  private:
    void onClick() {} //we don't use that one
    void onClick(int a,int b)
    {
      cout << "Button clicked with a=" << a << " and b=" << b << "!" << endl;
    }
};

int main()
{
  MyButton myButton;
  myButton.click(5,2);
}

You can also pass a pointer to some "wildcard class" instead:

struct ArbitraryData
{
  virtual ~ArbitraryData() {}
};

class button
{
  public:
    button(void (*onClick)(button&,ArbitraryData*)) : onClick(onClick) {}
    void click(ArbitraryData* data=0) {onClick(*this,data);}
  private:
    void (*onClick)(button&,ArbitraryData*);
};

struct MyAdditionalData : public ArbitraryData
{
  int a;
  MyAdditionalData(int a) : a(a) {}
  virtual ~MyAdditionalData() {}
};

void myOnClick(button& owner,ArbitraryData* adata)
{
  MyAdditionalData* data=dynamic_cast<MyAdditionalData*>(adata);
  if (data)cout << "Button clicked with a=" << data->a << "!" << endl;
  else cout << "Button clicked without any data!" << endl;
}

int main()
{
  button myButton(myOnClick);
  MyAdditionalData myData(5);
  myButton.click(&myData);
  myButton.click();
}

There's always one way or another.
Depends on what you actually need.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.