Messaging between components


#1

I need to send messages from a child component to its parent.

Reading up, it appears I have {Action/Change}(Broadcaster&Listener), where Change accumulates messages and sends a batch every 'tick', whereas Action works instantly.  So for my case I want Action.

This is what I've got:

Sender.hpp

class Sender: public Component, private ActionBroadcaster
{
private:
    void send(int data) { sendActionMessage(String(data)); }
}

mainComponent.cpp

#include "Sender.h"

class MainContentComponent : public Component, private ActionListener
{
    ScopedPointer<Sender> pSender;
public:
    MainContentComponent()
    {
        pSender = new Sender();
        addAndMakeVisible(pSender);
        pSender->addActionListener(this);
    }
private:
    // event from Sender
    void actionListenerCallback(const String& message) {
        int val = message.getIntValue();
    }

It works, but is it the correct approach?

A couple of things worry me:

  •  What if I wish to send more information? Must I manually serialise and deserialise it into a String?
     
  •  What if my main component is listening for three different message-sending-components? They are all going to trigger the same callback, aren't they! Does this mean I would need to encode the sender in the string, and extract it and branch accordingly inside the handler?

 An alternative architecture might be:

class Targ {
    void fromA(int data) {...}
    void fromB(int data) {...}

    Targ() {
        A.addHandler(& this->fromA );
        B.addHandler(& this->fromB );

That would let me name a handler for each type of message, which might result in clearer code, although now I quite like the idea of having all the message handling occur in one place.

π


Sending slider events from popup window?
#2

Do you really need to post a message, or could you just call a method on the object?

ActionBroadcaster is a bit antiquated now, something like CallbackMessage may be a better choice. Or even MessageManager::callAsync


#3

If I just call a method, this means the child has to have a pointer to the parent. Which typically means it has to #include "Parent.hpp" -- and I prefer to avoid circular dependency.

https://www.juce.com/doc/classMessageManager doesn't document callAsync -- looking at the code I see it is in an #ifdef block, maybe that flag needs to be set before auto generating the doc page...

CallbackMessage could do with an example somewhere! It's so much easier to implement something with an example!

I'm looking ahead as regards messaging; my last project I was able to (using C# delegates) have each component completely separate, and a controller component that hooked up the exposed attachment points. This let me reuse components very cleanly.

π


#4

Using messages to avoid an include sounds like a bad decision to me. Perhaps a virtual base class that the parent implements, or a ListenerList on the child.

And you should just grep CallbackMessage - it's used in many places and is very easy to use.