`imgui`:高性能即时模式 GUI 在 Python 中的应用

好,让我们来聊聊 imgui 这个神奇的家伙,以及如何在 Python 中驾驭它。想象一下,你正在构建一个游戏,或者一个复杂的工具,你需要一个界面来控制它,而不是每次都对着黑乎乎的命令行敲代码。imgui 就是来拯救你的英雄!

什么是 imgui

imgui,全称 Immediate Mode GUI,翻译过来就是“即时模式 GUI”。 这是一种与传统 GUI 框架截然不同的思想。 传统的 GUI 框架,比如 Qt 或者 Tkinter,是“保留模式”(Retained Mode)。 啥意思呢?

  • 保留模式: 你创建了一堆控件(按钮、文本框等等),它们一直存在于内存中,框架负责管理它们的状态。你修改控件的属性,框架会帮你更新显示。这种方式就像你盖房子,房子盖好了就放在那里,你想改颜色就重新刷漆。

  • 即时模式: 每次渲染帧,你都要重新描述整个界面。 这听起来是不是很笨?但它实际上非常高效。你可以把 imgui 想象成一个画家,每次画画都要重新画一遍整幅画,而不是修改画上的某个部分。 这样做的优点是状态管理简单,性能可控,易于集成到游戏引擎中。

imgui 的优势

  • 简单易用: 学习曲线平缓,API 设计简洁明了。
  • 高性能: 渲染效率高,尤其适合嵌入到游戏引擎或需要高性能的应用中。
  • 跨平台: 支持多种操作系统和渲染后端。
  • 易于集成: 可以轻松地与各种图形库(OpenGL, Vulkan, DirectX)集成。
  • 无状态: 简化了状态管理,避免了传统 GUI 框架中复杂的事件处理机制。

imgui 在 Python 中的应用

Python 本身不是以性能著称的语言,但 imgui 的高性能特性弥补了这一点。 通过 Python 绑定,我们可以利用 imgui 创建出响应迅速、用户友好的界面。

如何开始?

  1. 安装:

    首先,你需要安装 imgui 的 Python 绑定。 常用的绑定库是 imguipyimgui

    pip install imgui pyimgui

    或者, 如果你用conda:

    conda install -c conda-forge imgui pyimgui
  2. 一个简单的例子:

    import imgui
    from imgui.integrations.glfw import GlfwRenderer
    import glfw
    
    def main():
        if not glfw.init():
            print("初始化 GLFW 失败")
            return
    
        glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
        glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
        glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
        glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, glfw.TRUE)
    
        window = glfw.create_window(1280, 720, "imgui in Python", None, None)
        if not window:
            print("创建窗口失败")
            glfw.terminate()
            return
    
        glfw.make_context_current(window)
    
        imgui.create_context()
        impl = GlfwRenderer(window)
    
        while not glfw.window_should_close(window):
            glfw.poll_events()
    
            impl.process_inputs()
    
            imgui.new_frame()
    
            # 在这里编写你的 imgui 代码
            imgui.begin("Hello, world!")
            imgui.text("This is some useful text.")
            imgui.button("Button")
            imgui.end()
    
            imgui.render()
    
            glfw.get_framebuffer_size(window)
            impl.render(imgui.get_draw_data())
    
            glfw.swap_buffers(window)
    
        impl.shutdown()
        glfw.terminate()
    
    if __name__ == "__main__":
        main()

    这段代码做了什么?

    • 初始化 GLFW (一个用于创建窗口和处理输入的库)。
    • 创建一个 GLFW 窗口。
    • 创建一个 imgui 上下文。
    • 创建一个 GLFW 渲染器,用于将 imgui 的输出绘制到窗口上。
    • 进入一个主循环,不断渲染界面。
    • imgui.begin()imgui.end() 之间,你可以添加各种 imgui 控件。

常用控件

imgui 提供了丰富的控件,可以满足你的各种需求。 下面是一些常用的控件:

控件 描述
text() 显示文本。
button() 创建一个按钮。
input_text() 创建一个文本输入框。
slider_int() 创建一个整数滑块。
checkbox() 创建一个复选框。
combo() 创建一个下拉列表。
color_edit_3() 创建一个颜色选择器。
plot_lines() 绘制折线图。
tree_node() 创建一个树形节点,用于组织层次结构的数据。
begin() / end() 用于创建窗口(Window), 每个窗口都需要用 begin()end() 包裹. imgui.begin("窗口标题"), imgui.end()

示例:一个简单的配置界面

让我们创建一个简单的配置界面,包含一个文本输入框、一个滑块和一个复选框。

import imgui
from imgui.integrations.glfw import GlfwRenderer
import glfw

def main():
    if not glfw.init():
        print("初始化 GLFW 失败")
        return

    glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
    glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
    glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
    glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, glfw.TRUE)

    window = glfw.create_window(1280, 720, "imgui 配置界面", None, None)
    if not window:
        print("创建窗口失败")
        glfw.terminate()
        return

    glfw.make_context_current(window)

    imgui.create_context()
    impl = GlfwRenderer(window)

    config = {
        "name": "默认名称",
        "age": 25,
        "enabled": True,
    }

    while not glfw.window_should_close(window):
        glfw.poll_events()

        impl.process_inputs()

        imgui.new_frame()

        imgui.begin("配置")

        # 文本输入框
        changed, config["name"] = imgui.input_text("名称", config["name"], 256) # 第二个参数是缓冲区
        if changed:
            print(f"名称已更改为: {config['name']}")

        # 滑块
        changed, config["age"] = imgui.slider_int("年龄", config["age"], 0, 100)
        if changed:
            print(f"年龄已更改为: {config['age']}")

        # 复选框
        changed, config["enabled"] = imgui.checkbox("启用", config["enabled"])
        if changed:
            print(f"启用状态已更改为: {config['enabled']}")

        imgui.end()

        imgui.render()
        glfw.get_framebuffer_size(window)
        impl.render(imgui.get_draw_data())

        glfw.swap_buffers(window)

    impl.shutdown()
    glfw.terminate()

if __name__ == "__main__":
    main()

在这个例子中,我们创建了一个包含文本输入框、滑块和复选框的窗口。 当用户修改这些控件的值时,我们会在控制台中打印出新的值。

更高级的用法

  • 自定义样式: imgui 允许你自定义界面的样式,包括颜色、字体、间距等等。
  • 布局: 你可以使用 imgui 的布局 API 来控制控件的位置和大小。
  • 窗口管理: imgui 支持创建多个窗口,并且可以控制窗口的显示和隐藏。
  • 与图形库集成: imgui 可以与 OpenGL, Vulkan, DirectX 等图形库集成,实现更复杂的渲染效果。
  • 使用字体: imgui 默认使用的字体可能不是你想要的,你可以加载自定义字体。

自定义样式示例

import imgui

def set_style():
    style = imgui.get_style()
    # 修改窗口圆角
    style.window_rounding = 5.0
    # 修改按钮颜色
    style.colors[imgui.COLOR_BUTTON] = (0.5, 0.0, 0.0, 1.0) #RGBA, 范围是0.0-1.0
    style.colors[imgui.COLOR_BUTTON_HOVERED] = (0.7, 0.0, 0.0, 1.0)
    style.colors[imgui.COLOR_BUTTON_ACTIVE] = (1.0, 0.0, 0.0, 1.0)

# 调用 set_style() 在 imgui.new_frame() 之前

使用字体示例

import imgui

def load_font(font_path, font_size):
    io = imgui.get_io()
    io.fonts.add_font_from_file_ttf(font_path, font_size)
    return io.fonts.get_tex_data_as_rgba32() #返回Texture数据,给renderer用

# 在初始化时调用 load_font(),并且在renderer初始化之后调用,并且renderer需要实现纹理更新的接口。

一些技巧和注意事项

  • 状态管理: 虽然 imgui 是即时模式,但你仍然需要管理一些状态,比如控件的值。 你可以使用 Python 的变量来存储这些状态。
  • 性能优化: 避免在 imgui 代码中执行耗时的操作。 尽量将计算密集型的任务放在后台线程中执行。
  • 布局: imgui 的布局是隐式的,控件会按照添加的顺序排列。 你可以使用 imgui.same_line() 将控件放在同一行。
  • 错误处理: imgui 不会抛出异常。 你需要检查函数的返回值来判断是否发生了错误。

imgui 的局限性

  • 事件处理: imgui 的事件处理机制相对简单,不如传统 GUI 框架灵活。
  • 可访问性: imgui 的可访问性支持有限,可能不适合需要支持屏幕阅读器的应用。
  • 学习曲线: 虽然 imgui 简单易用,但要掌握高级用法仍然需要一定的学习成本。

总结

imgui 是一个强大的即时模式 GUI 框架,非常适合在 Python 中创建高性能、用户友好的界面。 它的简单易用、高性能和跨平台特性,使得它成为游戏开发、工具开发和嵌入式系统等领域的理想选择。 通过学习 imgui,你可以为你的 Python 应用增添强大的图形界面功能,让你的代码更加易于使用和维护。

希望这篇文章能够帮助你入门 imgui。 祝你编程愉快!记住,编程的乐趣在于不断探索和创造! 多动手尝试,你会发现 imgui 比想象中更有趣!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注