Sign in to follow this  
choffstein

Function Pointers (with UI)

Recommended Posts

So I was thinking about UI systems and how I would create my own, and its organization, etcetera. Having no experience with this, I assume that buttons and the likes must use some sort of function pointer to work. I mean, just create a base button class that you can assign location, size, and texture for normal and clicked to. Then upon release, execute some function. Now my issue is, how to use these function pointers. I figured I would want to use some sort of void function pointer for the button, and have derivative buttons for specific uses (maybe true/false buttons, etcetera). I know how to create general function pointers, and I just learned how to create function pointers for a specific class...but I want my buttons to have generic options for the class member function they call. Is there anyway to have a function pointer that has the ability to call any class member function (all of the same return and parameter type), or will I have to use some sort of template system and create the button with a template parameter on its creation to define the function pointer? Thanks.

Share this post


Link to post
Share on other sites
Have a look at boost::function, or these.

Using such function objects have multiple advantages over naked function pointers, not the least of which is that they can store the associated object pointer with the member function pointer. People often notice that lack when they code in Win32 when they try to use member functions as callbacks.

If you design your UI API from scratch to take function objects (boost::function makes a good baseline type), you'll get a lot of power and flexibility for a minimal investment.

Share this post


Link to post
Share on other sites
Thank ya sir. I will definitely check out those resources.

While I was waiting for a reply, I kind of figured out what I wanted. This sort of works:


#include <iostream>

using namespace std;

class A
{
private:
string str;
public:
A(string s){ str = s; }
~A(){}

inline void print(void)
{
cout << str << endl;
}
};

template <class T>
class Button
{
private:
void (T::*FP)(void);
T *t;

public:
Button(void (T::*fp)(void), T *pT = NULL){ FP = fp; t = pT; }
~Button(){}

inline void reassign(T *pT = NULL)
{
t = pT;
}

inline void push()
{
if(t)
(t->*FP)();
}
};


int main (int argc, char * const argv[]) {
A a1("string 1");
A a2("string 2");

Button<A> b(&A::print, &a1);

b.push();

b.reassign(&a2);
b.push();
return 1;
}




A simply dirty example, but that might even work for what I want. Then I can have a specific buttons if I need more info.

Thanks for the resources anyway. Ill definitely check em out.

Share this post


Link to post
Share on other sites
Quote:
Original post by visage
Now my issue is, how to use these function pointers. I figured I would want to use some sort of void function pointer for the button, and have derivative buttons for specific uses (maybe true/false buttons, etcetera). I know how to create general function pointers, and I just learned how to create function pointers for a specific class...but I want my buttons to have generic options for the class member function they call.


I'm doing what you're wanting to do... the trick has been to create Update objects that contain the functor (a Loki::Functor) which generates the type of data that the Widget needs. If, for example, the widget is a TextButton... the Update's functor takes one (1) argument; a std::string...

To trigger the update, you should map the update to an event

MAKELONG(ID_BUTTON,BN_CLICKED)

Or something... keep a map (std::map?) or multimap inside the Widget class, and, using the Observer pattern, whenever an EVENT happens... notify the Widget of the event

MAKELONG(ID_BUTTON,BN_CLICKED)

The Widget will look up the event in its map, and load the Update object... which will then run its Functor, and generate the data for the Widget.

...

It's really pretty slick.

Hope I didn't lose you [smile]

Share this post


Link to post
Share on other sites
When I wrote my GUI system I used probably the simplest way - simple callback functions. For each event (mouse move, on paint...) I have special callback function which has parameters needed for event (eg. mouse position, key pressed...) and then it has parameter for control on which it is called.
Main application window class contains code to manage all gui elements and call appropriate events when needed.

So for example I have base class defined like this (it contains much more, but its not too important now):

class Windowed;

/* x, y : coordinates of click in local coordinates
mb : mouse button pressed
This : pointer to control receiving event */

typedef void (*MouseClickProc)(int x, int y, int mb, Windowed *This);

// Base class for control
class Windowed
{
public:
/* wnd is pointer to main window whic provides font management and
interaction with os
name is unique name of control */

Windowed(AppWindow *wnd, std::string name);

void SetUserMouseDown(MouseClickProc mouse_down);
void SetUserMouseUp(MouseClickProc mouse_up);
void SetUserMouseClick(MouseClickProc mouse_click);
// Similar functions for other events.
};



This way callback function can interact with object it is called on.
All controls are then derived from this base class which provides all methods common to all controls. Every derived control only overrides methods such as OnMouseMove, OnClick, OnPaint etc.
With this system my controls support 12 types of events (mouse click, mouse move, mouse enter, mouse leave, key down, key up, mouse down, mouse up, focus get, focus lost, on paint).
Usage is pretty easy too, for example:

void cancel_click(int x, int y, int mb, Windowed *This)
{
// beep if left mouse was pressed
if (mb == MOUSE_LEFT)
{
Beep(1000, 1000);
}
}

void InitGUI(void)
{
Button *cancel = new Button(&window, "Cancel");

// set position and dimensions
cancel->Move(100, 100, 100, 20);
cancel->SetUserMouseClick((MouseClickProc) cancel_click);

// add button as child control of main window
window->AddGuiElem(cancel);
}



This system surely isn't the best one out there, but it was very easy to implement (I wrote whole GUI during 1 week before deadline [smile] and it's almost 7000 lines).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this