juce命令消息處理

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;
}


裏邊又調用了getFirstCommandTarget

//==============================================================================
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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章