Attaching code to an instance of a class?

Started by
5 comments, last by paulcoz 22 years, 9 months ago
I've been trying to implement some simple buttons in my program so that I can add a list of buttons to the screen (any number) and then determine which button was pressed by the user and run a different procedure for each. I've got this so far: class button { char[4] name; int startposx, startposy; // left-bottom corner of button int endposx, endposy; // top-right corner of button }; void SetupATestButton() { button* butt = new button; butt->name = "test"; butt->startposx = 130, butt->startposy = 130; butt->endposx = 250, butt->endposy = 250; } Then, when the program detects that the mouse has been clicked on a screen with buttons: cycle all buttons (cbutt = pointer to current button to test) if (cursurposx > cbutt->startposx && cursorposx < cbutt->endposx && cursorposy > cbutt->startposy && cursorposy < cbutt->endposy) { if (cbutt->name == 'test') { // PUT PROCEDURE HERE } if (cbutt->name == 'more') { // PUT MORE PROCEDURE HERE } } This works in theory (I haven't coded it), but I'd really like to include the procedure calls I want to make with the button setup if possible. Something like: butt->Method() SHOULD RUN Program->Exit(); (Program->Exit() being an existing procedure that shuts down the program) I can then run the button procedures like this: if (current button pressed) { cbutt->Method(); } See how it's a lot neater - more modular? Especially if I include the button press test code as a member function of class button. Any ideas how I can implement the buttons this way? I'd like to encapsulate some procedure code within an instance of a class, sort of...or something similar. Paulcoz. Edited by - paulcoz on July 26, 2001 6:02:34 AM
Advertisement
Use function pointers. When you construct a button, pass in the function name you want that button to execute. I''ve never done anything like this, but the theory is sound.
Here''s an example from my stuff.
  class gdn_GUIWindow{...  public:  void SetFunction(void (* handler)(gdn_Message message, void*   param1 = NULL, void* param2= NULL, gdn_GUIWindow* from = NULL)){    InternalMessageHandler = handler;}void LeftClick(){   // Do left click stuff then do handler.   if ( InternalMessageHandler != NULL )   InternalMessageHandler(GDN_MESSAGE_LEFT_CLICK, NULL,NULL,this )}private:void (*InternalMessageHandler)(gdn_Message message, void* param1 = NULL, void* param2= NULL, gdn_GUIWindow* from = NULL);...};////////////////////////////////////////////////////////////void ButtonHandler(gdn_Message message, void* param1 = NULL, void* param2= NULL, gdn_GUIWindow* from = NULL){   char buffer[10];   int id = int(param1);   switch( id )   {   	case 2:      {      	rootWindow->FindWindowWithID(100)->SetVisible(true);         break;      }   }....}gdn_GUIWindow window;window.SetFunction(ButtonHandler);  


-------
Andrew
"Power comes in response to a need not a desire."
gdNgine Development
You can pass a whole procedure/function as a parameter??? Where can I find out more about this? What category would it be under in the compiler help? This looks like the sort of thing I''m after.

Paulcoz.
I don''t think that it would be part of the compilier help since it is more of a technique. Try these sites:

The Function Pointer Tutorials

And
Google search results




-------
Andrew
"Power comes in response to a need not a desire."
gdNgine Development
It would be called a function pointer
There is another solution, which is basically equivalent with different syntax. That solution is using inheritence and virtual functions. Since virtual functions are implemented as function pointers anyway, they end up being effectively the same solution. (Yes, I know that virtual functions aren't direct function pointers, but instead use a table lookup... But the table contains function pointers, so it is the same basic idea.)

    class ButtonListenerI{public:    virtual void mouseEnter()  {}    virtual void mouseExit()   {}    virtual void mouseDown()   {}    virtual void mouseUp()     {}    virtual void mouseClick()  {}    ButtonListenerI()          {}    virtual ~ButtonListenerI() {}};  


Then, put a function like this in your Button class:
      void addButtonListener(ButtonListenerI *bli)  


Then, for an exit button, you'd do something like this:
  class ExitListener : public ButtonListenerI{public:    virtual void mouseClick()    {        // code to clean up and exit here    }};  


And when you were creating the buttons:
       exitButton.addButtonListener(new ExitListener());  


Then, your event dispatching system will send appropriate events to button's listeners, if they have one (or more, if you decide that's acceptable) registered. For instance, a typical move mouse to button, click, move away sequence might generate the following events: mouseEnter, mouseDown, mouseUp, mouseClick, mouseExit. Note that you'd only need to override the functions for dealing about the ones you care about. That's why I declared empty bodies for the functions in the ButtonListenerI class.

Of course, if you don't see ever needing all of those events, there's no need to include them. But if they might be used at some point, it's a good idea to have them.

This is the OOD method used for dealing with systems that generate events and want to allow the programmer to easily add code to recognize and respond to those events. It is basically equivalent to using simple function pointers, but I think it's easier to maintain and read.

Just presenting an alternative.....

Edited by - c_wraith on July 26, 2001 11:40:29 PM

This topic is closed to new replies.

Advertisement