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

好的,各位观众老爷们,欢迎来到今天的“Python GUI奇妙夜”!今天咱们不聊那些个“高大上”的框架,什么Qt啦,Tkinter啦,统统靠边站!今天咱们来点刺激的——imgui

啥是imgui

简单来说,imgui就是一个“即时模式GUI”。啥叫“即时模式”?别慌,我来解释。

传统的GUI框架,比如Qt或者Tkinter,它们是“保留模式”。啥意思呢?就是说,你创建了一个按钮,这个按钮会一直存在,直到你手动把它销毁。框架会负责管理这些UI元素的生命周期,给你提供信号和槽机制,让你轻松响应用户的操作。

imgui就不一样了,它信奉“用完就扔”的哲学。每一帧,它都会重新绘制整个GUI。你没听错,是每一帧!听起来是不是很疯狂?但是,正是这种疯狂,带来了意想不到的性能和灵活性。

你可以把imgui想象成一个画家,每一帧都在一张新的画布上重新画一遍。画完之后,就把画布扔掉,开始画下一张。

imgui的优势

  • 高性能: 听起来“每一帧都重绘”好像很耗性能,但实际上,imgui非常高效。它使用低级渲染API,避免了大量的状态切换,而且只绘制需要绘制的部分。
  • 易于集成: imgui只需要几个文件,就可以轻松集成到你的项目中。它没有复杂的依赖关系,也不需要编译。
  • 跨平台: imgui可以在各种平台上运行,包括Windows、macOS、Linux、Web等等。
  • 灵活性: imgui提供了大量的UI元素,你可以自由组合它们,创建出各种各样的界面。
  • 即时性: 因为是即时模式,所以你可以非常方便地调试和修改UI。你只需要修改代码,然后重新运行程序,就可以看到效果。

imgui的劣势

  • 状态管理: 因为每一帧都会重新绘制,所以你需要自己管理UI的状态。这可能会增加一些复杂性。
  • 可访问性: imgui在可访问性方面做得不太好,因为它主要关注的是性能和灵活性。
  • 学习曲线: 虽然imgui很简单,但是要熟练掌握它,还是需要花一些时间的。

Python中的imguiimgui

在Python中,我们使用imgui库来使用imgui。这个库是imgui的Python绑定。

安装imgui

首先,你需要安装imgui库。打开你的终端,然后输入以下命令:

pip install imgui

搞定!

第一个imgui程序

现在,让我们来写一个简单的imgui程序,看看它长什么样。

import imgui
import glfw
from OpenGL.GL import *

def main():
    # 初始化glfw
    if not glfw.init():
        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, GL_TRUE)

    window = glfw.create_window(1280, 720, "Imgui Example", None, None)
    if not window:
        glfw.terminate()
        return

    glfw.make_context_current(window)

    # 初始化imgui
    imgui.create_context()
    impl = imgui.backends.glfw_init_for_opengl(window, enable_callbacks=True)
    imgui.backends.opengl_init()

    # 主循环
    running = True
    while running and not glfw.window_should_close(window):
        glfw.poll_events()

        imgui.backends.opengl_new_frame()
        imgui.backends.glfw_new_frame()
        imgui.new_frame()

        # imgui代码
        imgui.begin("Hello, world!")
        imgui.text("This is some useful text.")
        imgui.button("Button")
        imgui.end()

        glViewport(0, 0, int(imgui.get_io().display_size[0]), int(imgui.get_io().display_size[1]))
        glClearColor(0.4, 0.4, 0.4, 1.0)
        glClear(GL_COLOR_BUFFER_BIT)

        imgui.render()
        imgui.backends.opengl_render_draw_data(imgui.get_draw_data())

        glfw.swap_buffers(window)

    # 清理
    imgui.backends.opengl_shutdown()
    imgui.backends.glfw_shutdown()
    imgui.destroy_context()
    glfw.terminate()

if __name__ == "__main__":
    main()

运行这段代码,你应该会看到一个窗口,上面显示着一个简单的imgui界面。

代码解释

  • glfw.init() 初始化GLFW,GLFW是一个用于创建窗口和处理输入的库。
  • glfw.create_window() 创建一个窗口。
  • imgui.create_context() 创建一个imgui上下文。
  • imgui.backends.glfw_init_for_opengl() 初始化imgui的GLFW后端。
  • imgui.backends.opengl_init() 初始化imgui的OpenGL后端。
  • imgui.new_frame() 开始一个新的帧。
  • imgui.begin() 开始一个窗口。
  • imgui.text() 添加一段文本。
  • imgui.button() 添加一个按钮。
  • imgui.end() 结束一个窗口。
  • imgui.render() 渲染imgui界面。
  • imgui.backends.opengl_render_draw_data() 使用OpenGL渲染imgui的绘制数据。
  • glfw.swap_buffers() 交换前后缓冲区,显示渲染结果。
  • glfw.poll_events() 处理事件,例如键盘输入和鼠标移动。

imgui的常用组件

imgui提供了大量的UI组件,你可以使用它们来创建各种各样的界面。

组件类型 描述 示例代码
imgui.text 显示文本 imgui.text("Hello, world!")
imgui.button 创建一个按钮 if imgui.button("Click me!"): print("Button clicked!")
imgui.input_text 创建一个文本输入框 python text_value = "" changed, text_value = imgui.input_text("Text", text_value, 256) if changed: print(f"Text changed to: {text_value}")
imgui.slider_int 创建一个整数滑块 python slider_value = 0 changed, slider_value = imgui.slider_int("Slider", slider_value, 0, 100) if changed: print(f"Slider value changed to: {slider_value}")
imgui.checkbox 创建一个复选框 python checkbox_value = False changed, checkbox_value = imgui.checkbox("Checkbox", checkbox_value) if changed: print(f"Checkbox value changed to: {checkbox_value}")
imgui.combo 创建一个下拉列表 python items = ["Item 1", "Item 2", "Item 3"] current_item = 0 changed, current_item = imgui.combo("Combo", current_item, items) if changed: print(f"Selected item: {items[current_item]}")
imgui.color_edit3 创建一个颜色选择器 python color = [1.0, 0.0, 0.0] changed, color = imgui.color_edit3("Color", *color) if changed: print(f"Color changed to: {color}")
imgui.begin_child 创建一个子窗口,用于组织UI元素 python with imgui.begin_child("Child", width=200, height=100, border=True): imgui.text("This is a child window.") imgui.end_child()
imgui.plot_lines 绘制折线图 python values = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9] imgui.plot_lines("Plot", values)
imgui.tree_node 创建一个树形结构的节点 python if imgui.tree_node("Node 1"): imgui.text("Content of Node 1") if imgui.tree_node("Node 2"): imgui.text("Content of Node 2") imgui.tree_pop() imgui.tree_pop()
imgui.menu_barimgui.menu 创建菜单栏和菜单项 python if imgui.begin_main_menu_bar(): if imgui.begin_menu("File"): if imgui.menu_item("Open"): print("Open menu item clicked") imgui.end_menu() imgui.end_main_menu_bar()
imgui.table 创建表格 python if imgui.begin_table("Table1", 3): imgui.table_header("Name") imgui.table_header("Age") imgui.table_header("City") imgui.table_next_row() imgui.table_next_column() imgui.text("John") imgui.table_next_column() imgui.text("30") imgui.table_next_column() imgui.text("New York") imgui.end_table()

一个更完整的例子

让我们来写一个更完整的例子,展示如何使用imgui来创建一个简单的程序。这个程序将显示一个窗口,其中包含一个文本输入框、一个滑块和一个复选框。

import imgui
import glfw
from OpenGL.GL import *

def main():
    # 初始化glfw
    if not glfw.init():
        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, GL_TRUE)

    window = glfw.create_window(1280, 720, "Imgui Example", None, None)
    if not window:
        glfw.terminate()
        return

    glfw.make_context_current(window)

    # 初始化imgui
    imgui.create_context()
    impl = imgui.backends.glfw_init_for_opengl(window, enable_callbacks=True)
    imgui.backends.opengl_init()

    # 状态变量
    text_value = ""
    slider_value = 0
    checkbox_value = False

    # 主循环
    running = True
    while running and not glfw.window_should_close(window):
        glfw.poll_events()

        imgui.backends.opengl_new_frame()
        imgui.backends.glfw_new_frame()
        imgui.new_frame()

        # imgui代码
        imgui.begin("My Window")

        changed, text_value = imgui.input_text("Text", text_value, 256)
        if changed:
            print(f"Text changed to: {text_value}")

        changed, slider_value = imgui.slider_int("Slider", slider_value, 0, 100)
        if changed:
            print(f"Slider value changed to: {slider_value}")

        changed, checkbox_value = imgui.checkbox("Checkbox", checkbox_value)
        if changed:
            print(f"Checkbox value changed to: {checkbox_value}")

        if imgui.button("Click me!"):
            print("Button clicked!")

        imgui.end()

        glViewport(0, 0, int(imgui.get_io().display_size[0]), int(imgui.get_io().display_size[1]))
        glClearColor(0.4, 0.4, 0.4, 1.0)
        glClear(GL_COLOR_BUFFER_BIT)

        imgui.render()
        imgui.backends.opengl_render_draw_data(imgui.get_draw_data())

        glfw.swap_buffers(window)

    # 清理
    imgui.backends.opengl_shutdown()
    imgui.backends.glfw_shutdown()
    imgui.destroy_context()
    glfw.terminate()

if __name__ == "__main__":
    main()

代码解释

  • 我们定义了三个状态变量:text_valueslider_valuecheckbox_value,分别用于存储文本输入框、滑块和复选框的值。
  • imgui.begin()imgui.end()之间,我们添加了三个UI组件:imgui.input_text()imgui.slider_int()imgui.checkbox()
  • 每个组件都会返回一个changed标志,用于指示组件的值是否发生了改变。如果发生了改变,我们就可以打印出新的值。

总结

imgui是一个高性能、易于集成、跨平台、灵活和即时的GUI库。虽然它有一些缺点,例如需要自己管理状态,但是在很多情况下,它仍然是一个非常好的选择。

今天我们学习了imgui的基本概念和用法,包括如何安装imgui库,如何创建一个简单的imgui程序,以及如何使用imgui的常用组件。

希望今天的讲座对你有所帮助。下次再见!

发表回复

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