class ApplicationCommandTarget::CommandMessage : public MessageManager::MessageBase
{
public:
CommandMessage (ApplicationCommandTarget* const target, const InvocationInfo& inf)
: owner (target), info (inf)
{
}
void messageCallback() override
{
if (ApplicationCommandTarget* const target = owner)
target->tryToInvoke (info, false);
}
private:
WeakReference<ApplicationCommandTarget> owner;
const InvocationInfo info;
JUCE_DECLARE_NON_COPYABLE (CommandMessage)
};
查看button類的消息處理,可以發現,除了調用listener進行處理外,還調用了commandmanager進行處理,這個有點相當於MFC向父窗口發送通知消息。
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)
}
接着看具體調用
bool ApplicationCommandManager::invoke (const ApplicationCommandTarget::InvocationInfo& inf, const bool asynchronously)
{
// This call isn't thread-safe for use from a non-UI thread without locking the message
// manager first..
jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
bool ok = false;
ApplicationCommandInfo commandInfo (0);
if (ApplicationCommandTarget* const target = getTargetForCommand (inf.commandID, commandInfo))
{
ApplicationCommandTarget::InvocationInfo info (inf);
info.commandFlags = commandInfo.flags;
sendListenerInvokeCallback (info);
ok = target->invoke (info, asynchronously);
commandStatusChanged();
}
return ok;
}
中間有個重要的函數
ApplicationCommandTarget* ApplicationCommandManager::getTargetForCommand (const CommandID commandID,
ApplicationCommandInfo& upToDateInfo)
{
ApplicationCommandTarget* target = getFirstCommandTarget (commandID);
if (target == nullptr)
target = JUCEApplication::getInstance();
if (target != nullptr)
target = target->getTargetForCommand (commandID);
if (target != nullptr)
target->getCommandInfo (commandID, upToDateInfo);
return target;
}
//==============================================================================
ApplicationCommandTarget* ApplicationCommandManager::getFirstCommandTarget (const CommandID)
{
return firstTarget != nullptr ? firstTarget
: findDefaultComponentTarget();
}
這裏需要注意的是,如果這裏返回了null的話,那麼對象便成了application對象
ApplicationCommandTarget* ApplicationCommandManager::findDefaultComponentTarget()
{
Component* c = Component::getCurrentlyFocusedComponent();
if (c == nullptr)
{
if (TopLevelWindow* const activeWindow = TopLevelWindow::getActiveTopLevelWindow())
{
c = activeWindow->getPeer()->getLastFocusedSubcomponent();
if (c == nullptr)
c = activeWindow;
}
}
if (c == nullptr && Process::isForegroundProcess())
{
Desktop& desktop = Desktop::getInstance();
// getting a bit desperate now: try all desktop comps..
for (int i = desktop.getNumComponents(); --i >= 0;)
if (ComponentPeer* const peer = desktop.getComponent(i)->getPeer())
if (ApplicationCommandTarget* const target = findTargetForComponent (peer->getLastFocusedSubcomponent()))
return target;
}
if (c != nullptr)
{
// if we're focused on a ResizableWindow, chances are that it's the content
// component that really should get the event. And if not, the event will
// still be passed up to the top level window anyway, so let's send it to the
// content comp.
if (ResizableWindow* const resizableWindow = dynamic_cast <ResizableWindow*> (c))
if (Component* const content = resizableWindow->getContentComponent())
c = content;
if (ApplicationCommandTarget* const target = findTargetForComponent (c))
return target;
}
return JUCEApplication::getInstance();
}
這裏可以看到,查找的是focus的對象來處理,這裏有個函數要關注下
//==============================================================================
ApplicationCommandTarget* ApplicationCommandManager::findTargetForComponent (Component* c)
{
ApplicationCommandTarget* target = dynamic_cast <ApplicationCommandTarget*> (c);
if (target == nullptr && c != nullptr)
target = c->findParentComponentOfClass<ApplicationCommandTarget>();
return target;
}
實際上就是轉換成爲commandtarget 如果轉換失敗,那麼再往父窗容器查找。
分析不是很詳細,後續再深入分析。
juce交流羣:68016614