KeypressMappingSet callback function


#1

This has had me puzzled the last couple of days… I declare a callback function in the header file:

but when I try to pass keyPressCallback in addCommand, it says it can’t convert void keyPressCallback to juce::keyPressCallbackFunction(cdtl*)… (or something along those lines)


#2

Are you passing in the address of the function? (i.e. &keyPressCallback)?


#3

that gives me “&”: illegal operation on bound member function expression.


#4

Well it must be something simple you’re doing wrong…


#5

Well I found the problem, but I don’t see an easy way around it. According to this you can’t pass a non static class method as a normal function pointer… :?

Just wondering, is there any reason for using function pointers in KeypressMappingSet instead of the normal OO callbacks that are used in the rest of the library?

Cheers,
Caleb


#6

…well yeah, how would it know which object you want it to call the method on?

Good question. The main reason was because if you’re writing a whole bunch of callbacks, it’s much less code to do them as functions rather than having to define a whole class for each one, and maintain the instances of those classes somewhere, etc.

I guess a cool way of doing it would be by having an option to use the function callbacks, or some kind of listener class instead. I’ll probably do that when I get a moment.


#7

I use non-static method pointers inside classes all the time, but this is how I do it… Let me just whip up a code example, make a blank console app and put this in it to run it…

[code]#include

class mainbase
{
public:
void toPrint()
{
printf(“The mainbase Class is talking.\n”);
}
protected:
private:
};

typedef void (testFunc)(void, int);

class testBase
{
public:
testBase()
{
theFunc = 0;
}

void doCommand(unsigned long theCommand)
{
	printf("Calling a function now");
	if(theFunc!=0)
		theFunc(this,theCommand);
	else
		printf("theFunc was zero?\n");
}
testFunc theFunc;

};

class testClass : public mainbase, public testBase
{
public:
testClass() : testBase()
{
theFunc = (testFunc)aFunc;
}

static void aFunc(testClass *self, int testInt)
{
	printf("a test phrase, now to call toPrint on me :)\n");
	if(self!=NULL)
		self->toPrint();
	else
		printf("self was empty? the wha?");
}

void toPrint()
{
	printf("The testClass Class is talking.\n");
}

};

int _tmain(int argc, _TCHAR* argv[])
{
testClass theTest;

theTest.doCommand(12);
printf("\n\n");

return 0;

}[/code]

This is an example I made for someone else showing a few class things, along with pointing to class methods. All you have to do is just have teh delegate have a void* for it’s first param, and anytime you want to call it, just pass the class as the first param as shown above. Albeit it, this example it is a static, but you can set it up to be a normal one as well following the same method, do note you get compilier warnings about such actions so it’s good to pragma those out for that file. :slight_smile:


#8

…well yeah, how would it know which object you want it to call the method on?
[/quote]

well i thought that since i’m referencing it inside of a non static method it would know about the current instance and c++ would automatically take of it but i guess that’s not the way function pointers work.

Good question. The main reason was because if you’re writing a whole bunch of callbacks, it’s much less code to do them as functions rather than having to define a whole class for each one, and maintain the instances of those classes somewhere, etc.

I guess a cool way of doing it would be by having an option to use the function callbacks, or some kind of listener class instead. I’ll probably do that when I get a moment.[/quote]

In my case the class using the KeypressMappingSet may not be the only instance so it wouldn’t make sense to make it a singleton. I guess a work around would be to have a singleton that holds the instance of the class that uses KeypressMappingSet that’s currently in use but that seems a bit hacky so a listener class would be much appreciated. If only c++ had inner classes…


#9

[quote=“jules”]
I guess a cool way of doing it would be by having an option to use the function callbacks, or some kind of listener class instead. I’ll probably do that when I get a moment.[/quote]

I’m finding the KeyPressMappingSet class a little hard to use elegantly right now.

I need to be able to have keyboard commands created on the fly, as my app supports menu assignable macros. Consequently, landing in a static function is a little tricky given that my app doesn’t necessarily know very much about the menu option/shortcut that generated a key callback.

For the way my app is structured, it’d be much cleaner to have a listener style callback.


#10

Yes, well don’t get too embroiled in the KeyPressMappingSet because I’m currently trying to redesign it.

What I want to end up with are command objects and command targets, which can be automatically connected to buttons, menus, keys etc. It’s a bit of a tough thing to design, actually.


#11

to valley:
The example you give is not the right way to implement callback functions in C++ (it is still using a static function)

to juce:
A way to avoid using a static function is to create an callback object, something like

class Callback
{
public:
   virtual void doAction() = 0;
};

in your class add ": public Callback" to the inheritance declaration, and the doAction() overload method. 

then pass the object to the callback system.

Another way is to use method pointers (as opposed to function pointers in C) like this

class SimpleBase
{
public:

};
typedef void (SimpleBase::*PFunctionPtr)();

class Derived : public SimpleBase
{
public:
     void something() {}

     void setFunctionPtr() 
     { 
          PFunctionPtr pointerToFunction = &Derived::something;
          // call the pointer
          this->*pointerToFunction();
     }
}

However, the syntax is then obscure and still require passing an object pointer.

A final solution, used in UPP (upp.sf.net) and in new C++ standard, is to template the callback function like said here
and in UPP (same method plus template function to create the callback object on the fly (compiler generated) and avoid the complex typedef Callback<something, … >.

Good luck for your refactoring


#12

[quote=“X-Ryl669”]A final solution, used in UPP (upp.sf.net) and in new C++ standard, is to template the callback function like said here
and in UPP (same method plus template function to create the callback object on the fly (compiler generated) and avoid the complex typedef Callback<something, … >.Good luck for your refactoring[/quote]

And of course, boost’s function library is infinitally useful in that regard, type checking and all. You can even, say, bind a class pointer to the function object so if you call the object directly it is identical to passing it anyway (demo’d in the function documentation, bind’s documentation is located here. I thought many of you used boost? One of the most helpful libraries created.

The signals library in boost is also useful for relying messages around.


#13

I wasn’t planning on doing any fancy templated stuff, just having virtual objects that implement each type of command. That’d be easy to read and to see what’s going on.

The hard bit is how to store and dispatch these commands - e.g. you might have a “paste” command, which gets sent to a text editor when it’s focused, or to that editor’s parent component when it’s not. The same command could do different things. And when you have those commands going into menus too, with some menu items disabled depending on which component has focus, it all gets quite tricky.


#14