//==============================================================================
/**
Used to receive callbacks when a button is clicked.
@see Button::addListener, Button::removeListener
*/
class JUCE_API Listener
{
public:
/** Destructor. */
virtual ~Listener() {}
/** Called when the button is clicked. */
virtual void buttonClicked (Button*) = 0;
/** Called when the button's state changes. */
virtual void buttonStateChanged (Button*) {}
};
上边是button类中定义的listener.
listener由发送消息者去定义,同时维护了一个listener的表,当事件发生的时候,先把消息发送到控件本身进行处理,处理完后,循环调用listoner进行消息处理,呵呵,一直不明白java的那个listener,没想到在这里明白了,真扯啊
enum { clickMessageId = 0x2f3f4f99 };
void Button::triggerClick()
{
postCommandMessage (clickMessageId);
}
发送自定义消息
void Component::postCommandMessage (const int commandId)
{
class CustomCommandMessage : public CallbackMessage
{
public:
CustomCommandMessage (Component* const c, const int command)
: target (c), commandId (command) {}
void messageCallback() override
{
if (target.get() != nullptr) // (get() required for VS2003 bug)
target->handleCommandMessage (commandId);
}
private:
WeakReference<Component> target;
int commandId;
};
(new CustomCommandMessage (this, commandId))->post();
}
当收到消息以后button先自己处理此消息,调用如下函数
void Component::postCommandMessage (const int commandId)
{
class CustomCommandMessage : public CallbackMessage
{
public:
CustomCommandMessage (Component* const c, const int command)
: target (c), commandId (command) {}
void messageCallback() override
{
if (target.get() != nullptr) // (get() required for VS2003 bug)
target->handleCommandMessage (commandId);
}
private:
WeakReference<Component> target;
int commandId;
};
(new CustomCommandMessage (this, commandId))->post();
}
接着调用handleCommandMessage,这里更新了button的状态
//重写了这个消息
void Button::handleCommandMessage (int commandId)
{
if (commandId == clickMessageId)
{
if (isEnabled())
{
flashButtonState();
internalClickCallback (ModifierKeys::getCurrentModifiers());
}
}
else
{
Component::handleCommandMessage (commandId);
}
}
但是到这个地方还没有listener任何事情,接着往下看
void Button::internalClickCallback (const ModifierKeys& modifiers)
{
if (clickTogglesState)
{
const bool shouldBeOn = (radioGroupId != 0 || ! lastToggleState);
if (shouldBeOn != getToggleState())
{
setToggleState (shouldBeOn, sendNotification);
return;
}
}
sendClickMessage (modifiers);
}
最后又调用了sendClickMessage
void Button::sendClickMessage (const ModifierKeys& modifiers)
{
Component::BailOutChecker checker (this);
if (commandManagerToUse != nullptr && commandID != 0)
{
ApplicationCommandTarget::InvocationInfo info (commandID);
info.invocationMethod = ApplicationCommandTarget::InvocationInfo::fromButton;
info.originatingComponent = this;
commandManagerToUse->invoke (info, true);
}
clicked (modifiers);
if (! checker.shouldBailOut())
buttonListeners.callChecked (checker, &ButtonListener::buttonClicked, this); // (can't use Button::Listener due to idiotic VC2005 bug)
}
到这里,listener终于闪登场
/** Calls a member function on each listener in the list, with no parameters and a bail-out-checker.
See the class description for info about writing a bail-out checker. */
template <class BailOutCheckerType>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) ())
{
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
(iter.getListener()->*callbackFunction) ();
}
此处,循环调用就不说了。 这里作个说明BailOutChecker的作用是防止消息处理过程中把button给删除了,后边的callback又使用到button这种情况,其实就是做个检查,这个在其它界面库中也遇到过这种情况。