You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于ImGui实现桌面应用的页面导航切换系统

ImGui 页面导航实现方案

针对你的需求,下面给出几种实用的实现思路,完全基于你已有的Application和Page类结构扩展:

方案1:回调函数传递(最直接简单)

核心思路是让每个Page实例持有一个页面切换的回调函数,这个函数由Application在注册页面时传入,当Page内触发切换事件(比如按钮点击)时,直接调用回调通知Application执行切换。

代码示例:

首先修改Page类,添加回调成员:

#include <functional>

class Page {
public:
    // 定义页面切换回调类型,参数为目标页面的唯一标识(字符串/枚举均可)
    using NavigateCallback = std::function<void(const std::string&)>;

    virtual ~Page() = default;
    virtual void Render() = 0;

    // 设置导航回调
    void SetNavigateCallback(NavigateCallback callback) {
        navigate_callback_ = std::move(callback);
    }

protected:
    NavigateCallback navigate_callback_;
};

然后修改Application类,在注册页面时绑定切换逻辑:

#include <unordered_map>
#include <memory>
#include <string>

class Application {
public:
    // 注册页面时同时绑定导航回调
    void RegisterPage(const std::string& page_id, std::unique_ptr<Page> page) {
        page->SetNavigateCallback([this](const std::string& target_id) {
            SwitchPage(target_id);
        });
        pages_[page_id] = std::move(page);
    }

    // 核心页面切换逻辑
    void SwitchPage(const std::string& target_id) {
        auto it = pages_.find(target_id);
        if (it != pages_.end()) {
            current_page_ = it->second.get();
        }
    }

    void RenderCurrentPage() {
        if (current_page_) {
            current_page_->Render();
        }
    }

private:
    std::unordered_map<std::string, std::unique_ptr<Page>> pages_;
    Page* current_page_ = nullptr;
};

最后在具体页面子类里触发切换:

class HomePage : public Page {
public:
    void Render() override {
        if (ImGui::Button("跳转到设置页面")) {
            if (navigate_callback_) {
                navigate_callback_("settings_page");
            }
        }
    }
};

class SettingsPage : public Page {
public:
    void Render() override {
        if (ImGui::Button("返回首页")) {
            if (navigate_callback_) {
                navigate_callback_("home_page");
            }
        }
    }
};

方案2:弱引用+接口调用(适合复杂场景)

如果应用逻辑较复杂,担心回调管理麻烦,可以给Page提供Application的弱引用(避免循环引用),同时让Application暴露公开的页面切换接口。

代码示例:

首先给Application添加公开切换接口:

class Application; // 前置声明

class Page {
public:
    virtual ~Page() = default;
    virtual void Render() = 0;

    void SetApplication(std::weak_ptr<Application> app) {
        app_ = std::move(app);
    }

protected:
    std::weak_ptr<Application> app_;
};

class Application : public std::enable_shared_from_this<Application> {
public:
    void RegisterPage(const std::string& page_id, std::unique_ptr<Page> page) {
        page->SetApplication(shared_from_this());
        pages_[page_id] = std::move(page);
    }

    // 公开的页面切换接口
    void SwitchPage(const std::string& target_id) {
        auto it = pages_.find(target_id);
        if (it != pages_.end()) {
            current_page_ = it->second.get();
        }
    }

    // ... 其他方法同方案1
};

页面子类里调用切换接口:

class HomePage : public Page {
public:
    void Render() override {
        if (ImGui::Button("跳转到设置页面")) {
            if (auto app = app_.lock()) {
                app->SwitchPage("settings_page");
            }
        }
    }
};

方案3:事件总线(适合多页面复杂交互)

如果需要多个组件完全解耦,可以引入单例事件总线,Page发送切换事件,Application监听事件并处理切换,适合大型应用场景。

简单实现示例:

// 单例事件总线
class EventBus {
public:
    static EventBus& GetInstance() {
        static EventBus instance;
        return instance;
    }

    using NavigateEventHandler = std::function<void(const std::string&)>;
    void SubscribeNavigate(NavigateEventHandler handler) {
        navigate_handlers_.push_back(std::move(handler));
    }

    void PublishNavigate(const std::string& target_id) {
        for (auto& handler : navigate_handlers_) {
            handler(target_id);
        }
    }

private:
    EventBus() = default;
    std::vector<NavigateEventHandler> navigate_handlers_;
};

Application初始化时订阅事件:

Application::Application() {
    EventBus::GetInstance().SubscribeNavigate([this](const std::string& target_id) {
        SwitchPage(target_id);
    });
}

页面里触发切换事件:

void HomePage::Render() {
    if (ImGui::Button("跳转到设置页面")) {
        EventBus::GetInstance().PublishNavigate("settings_page");
    }
}

内容的提问来源于stack exchange,提问作者Essuman Godsaves

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:22:37