Function Pointers (with UI)

Started by
3 comments, last by b2b3 18 years, 10 months ago
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.
Advertisement
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.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
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.
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]

my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]
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 controlclass 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).

This topic is closed to new replies.

Advertisement