golang基于Dear ImGui的GUI界面开发插件库cimgui-go的使用

Golang基于Dear ImGui的GUI界面开发插件库cimgui-go的使用

cimgui-go是一个为Dear ImGui生成Go语言绑定的项目,它提供了多个默认的后端实现,支持macOS(arm64/x86)、Windows(x64)和多种Linux发行版。

项目状态

Go Report Card Build Status Linter Status GoDoc Mentioned in Awesome Go

模块概览

包名 描述
imgui, implot, imnodes Dear ImGui(及其插件)的实际绑定,用于显示控件和其他UI元素
examples 展示如何使用cimgui-go的示例
cmd/codegen 生成Go绑定的代码生成器
backend 各种后端的抽象层(glfw, sdl, ebiten等)
backend/* 使用系统库渲染ImGui的特定后端实现
impl 负责imgui与后端交互的包

支持的Backend

cimgui-go实现了几个imgui后端,都放在backend/子包中:

  • GLFW (GLFW 3.3 + OpenGL)
  • SDL2 (SDL 2 + OpenGL)
  • Ebitengine

重要提示:不同的解决方案使用不同的C库,可能会相互冲突。建议不要同时导入GLFW和SDL后端,可能会导致链接器崩溃。

完整示例Demo

下面是一个使用GLFW后端的完整示例代码:

package main

import (
	"github.com/AllenDang/cimgui-go"
	"github.com/AllenDang/cimgui-go/backend/glfwbackend"
	"github.com/go-gl/glfw/v3.3/glfw"
)

func main() {
	// 初始化GLFW
	if err := glfw.Init(); err != nil {
		panic(err)
	}
	defer glfw.Terminate()

	// 创建窗口
	window, err := glfw.CreateWindow(1280, 720, "cimgui-go GLFW example", nil, nil)
	if err != nil {
		panic(err)
	}
	
	// 创建imgui上下文
	context := cimgui.CreateContext()
	defer context.Destroy()
	
	// 初始化GLFW后端
	backend := glfwbackend.NewBackend(window)
	backend.SetAfterCreateContextHook(func() {
		// 设置imgui样式
		style := cimgui.CurrentStyle()
		style.ScaleAllSizes(1.5)
	})
	
	// 初始化imgui IO
	io := cimgui.CurrentIO()
	io.SetConfigFlags(io.ConfigFlags() | cimgui.ConfigFlagsNavEnableKeyboard)
	
	// 主循环
	for !window.ShouldClose() {
		glfw.PollEvents()
		
		// 开始新帧
		backend.NewFrame()
		cimgui.NewFrame()
		
		// 创建imgui窗口和控件
		cimgui.Begin("Hello, world!")
		cimgui.Text("This is some useful text.")
		if cimgui.Button("Click me!") {
			// 按钮点击处理
			cimgui.OpenPopup("Popup")
		}
		
		if cimgui.BeginPopup("Popup") {
			cimgui.Text("You clicked the button!")
			cimgui.EndPopup()
		}
		cimgui.End()
		
		// 渲染
		cimgui.Render()
		backend.Render(cimgui.RenderedDrawData())
		
		window.SwapBuffers()
	}
}

命名约定

  • 对于函数,'Im/ImGui/ig’前缀被移除
  • Get前缀也被移除(有一些例外)
  • 如果函数来自imgui_internal.h,则添加Internal前缀

指针和切片

在C中无法区分指针和切片,我们的代码默认为指针,但你可以通过&(slice[0])轻松将切片转换为指针。

小技巧utils包中有一些实用函数:

  • utils.SliceToPtr(slice []T) *T - 将切片转换为指针
  • utils.PtrToSlice(ptr *T, size int) []T - 将指针转换为给定大小的切片

回调函数

目前Go(1.24)不支持通过CGO将匿名函数传递给C。我们有一个解决方案-预生成大量全局函数和一个池。

应用截图

App demo

贡献指南

所有类型的贡献都受欢迎!但请注意:

警告:你永远不应该手动修改自动生成的文件!所有违反此规则的Pull Request都不会通过自动检查,也不会被合并。

当前解决方案是:

  1. 使用cimgui的lua生成器将函数和结构定义生成为json
  2. 通过手动编写的Go程序从定义生成正确的Go代码
  3. 使用imgui的后端实现
  4. 使用GitHub工作流编译cimgui、glfw和其他C依赖项为静态库

更多关于golang基于Dear ImGui的GUI界面开发插件库cimgui-go的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于Dear ImGui的GUI界面开发插件库cimgui-go的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用cimgui-go进行Golang GUI开发

cimgui-go是Go语言对Dear ImGui的绑定库,允许你在Go中创建轻量级、高效的即时模式GUI界面。下面我将详细介绍如何使用这个库。

安装和基本设置

首先需要安装cimgui-go:

go get github.com/inkyblackness/imgui-go/v4

基本示例

下面是一个简单的使用cimgui-go创建窗口的示例:

package main

import (
	"github.com/inkyblackness/imgui-go/v4"
	"github.com/veandco/go-sdl2/sdl"
	"github.com/veandco/go-sdl2/sdlrenderer"
)

func main() {
	// 初始化SDL
	if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
		panic(err)
	}
	defer sdl.Quit()

	// 创建窗口
	window, err := sdl.CreateWindow("cimgui-go示例", 
		sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		800, 600, sdl.WINDOW_OPENGL|sdl.WINDOW_RESIZABLE)
	if err != nil {
		panic(err)
	}
	defer window.Destroy()

	// 创建渲染器
	renderer, err := sdlrenderer.NewRenderer(window)
	if err != nil {
		panic(err)
	}
	defer renderer.Destroy()

	// 初始化ImGui
	context := imgui.CreateContext(nil)
	defer context.Destroy()
	io := imgui.CurrentIO()

	// 初始化ImGui SDL2绑定
	impl := sdlrenderer.New(renderer)
	defer impl.Dispose()
	impl.SetWindow(window)

	// 主循环
	running := true
	for running {
		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
			switch event.(type) {
			case *sdl.QuitEvent:
				running = false
			}
			impl.ProcessEvent(event)
		}

		// 开始新帧
		impl.NewFrame()
		imgui.NewFrame()

		// 创建GUI界面
		imgui.Begin("Hello, world!")
		imgui.Text("This is some useful text.")
		if imgui.Button("Click me!") {
			// 按钮点击处理
		}
		imgui.End()

		// 渲染
		imgui.Render()
		impl.Render(imgui.RenderedDrawData())
		renderer.Present()
		sdl.Delay(16) // 约60FPS
	}
}

常用组件使用

按钮和文本

imgui.Button("Click me")
imgui.Text("Simple text")
imgui.TextColored(imgui.Vec4{X: 1, Y: 0, Z: 0, W: 1}, "Red text")

输入框

var text string
imgui.InputText("Input", &text)

滑块和数值输入

var value float32 = 0.5
imgui.SliderFloat("Slider", &value, 0, 1)
imgui.InputFloat("Input float", &value)

复选框

var checked bool
imgui.Checkbox("Checkbox", &checked)

下拉菜单

var currentItem int32
items := []string{"Option 1", "Option 2", "Option 3"}
imgui.Combo("Combo", &currentItem, items)

颜色选择器

var color [4]float32 = [4]float32{1, 0, 0, 1}
imgui.ColorEdit4("Color", &color)

布局控制

窗口

imgui.Begin("Window Title")
// 窗口内容
imgui.End()

子窗口

imgui.BeginChild("Child", imgui.Vec2{X: 200, Y: 100}, true)
// 子窗口内容
imgui.EndChild()

分组

imgui.BeginGroup()
// 分组内容
imgui.EndGroup()

表格

if imgui.BeginTable("table", 3, 0, imgui.Vec2{}, 0) {
    imgui.TableSetupColumn("Column 1")
    imgui.TableSetupColumn("Column 2")
    imgui.TableSetupColumn("Column 3")
    imgui.TableHeadersRow()
    
    for i := 0; i < 5; i++ {
        imgui.TableNextRow()
        for j := 0; j < 3; j++ {
            imgui.TableSetColumnIndex(j)
            imgui.Text(fmt.Sprintf("Row %d, Col %d", i, j))
        }
    }
    imgui.EndTable()
}

样式定制

你可以自定义ImGui的样式:

style := imgui.CurrentStyle()
style.SetColor(imgui.StyleColorText, imgui.Vec4{X: 1, Y: 1, Z: 1, W: 1}) // 白色文本
style.SetWindowRounding(0) // 无圆角窗口

高级功能

自定义字体

io := imgui.CurrentIO()
fontConfig := imgui.NewFontConfig()
defer fontConfig.Destroy()
fontConfig.SetSize(20) // 20px字体

// 加载TTF字体
font := io.Fonts().AddFontFromFileTTF("arial.ttf", 16, fontConfig)

绘图API

drawList := imgui.GetWindowDrawList()
pos := imgui.CursorScreenPos()
drawList.AddLine(
    imgui.Vec2{X: pos.X, Y: pos.Y},
    imgui.Vec2{X: pos.X + 100, Y: pos.Y + 100},
    imgui.PackedColorFromVec4(imgui.Vec4{X: 1, Y: 0, Z: 0, W: 1}),
    2.0, // 线宽
)

性能优化建议

  1. 避免在每帧创建临时字符串,尽量重用变量
  2. 对于不常变化的内容,使用imgui.BeginChild()imgui.EndChild()限制更新区域
  3. 对于复杂界面,考虑使用imgui.SetNextWindowSizeConstraints()限制窗口大小
  4. 使用imgui.BeginDisabled()imgui.EndDisabled()来禁用不需要交互的部分

总结

cimgui-go为Go开发者提供了使用Dear ImGui的便捷方式,可以创建高性能的GUI应用程序。它的即时模式设计使得UI开发变得直观简单,特别适合工具、编辑器等需要频繁更新的界面。

要了解更多细节,可以参考cimgui-go的GitHub仓库和Dear ImGui的官方文档。

回到顶部