如何用Cairo在GTK4+LGI的GtkDrawingArea中绘图?
解决GTK4+LGI中GtkDrawingArea绘制无内容及资源管理问题
一、GtkDrawingArea绘制无内容的修复方案
在GTK4的LGI绑定中,set_draw_func的回调参数要求与GTK3不同,核心问题大概率是参数不匹配导致绘制逻辑未执行:
- 确保从Glade的
Gtk.Builder中正确获取GtkDrawingArea对象,比如builder:get_object("你的绘图区ID") set_draw_func的回调必须接收四个参数:widget, cr, width, height,少参数会直接导致回调不触发- 绘制前建议调用
cr:save()保存上下文状态,绘制完成后调用cr:restore()恢复,避免影响后续绘制
修复后的关键代码片段:
local lgi = require 'lgi' local Gtk = lgi.require 'Gtk' local Cairo = lgi.require 'Cairo' local builder = Gtk.Builder() builder:add_from_file('main.ui') local window = builder:get_object('main_window') local drawing_area = builder:get_object('drawing_area') -- 正确设置绘制回调 drawing_area:set_draw_func(function(widget, cr, width, height) -- 填充背景色 cr:set_source_rgb(0.05, 0.05, 0.1) cr:paint() -- 替换为你的地心说太阳系绘制逻辑 cr:set_source_rgb(1, 0.8, 0) cr:arc(width/2, height/2, 40, 0, 2*math.pi) cr:fill() end) window:show_all() Gtk.main()
二、Cairo资源管理说明
- Cairo上下文(cr):由GTK自动管理生命周期,绘制完成后无需手动调用销毁方法,GTK会自动回收资源
- 手动创建的Cairo.Surface:比如你生成PNG时创建的surface,需要调用
surface:finish()释放底层资源;如果是GTK传递的绘制surface,同样由GTK管理,无需手动处理
三、GTK4+LGI完整示例参考
以下是包含2×2布局、输入栏和绘图区的可运行示例:
local lgi = require 'lgi' local Gtk = lgi.require 'Gtk' local Cairo = lgi.require 'Cairo' -- 主窗口 local window = Gtk.Window { title = '地心说太阳系演示', default_width = 800, default_height = 600, } -- 顶部输入栏 local input_entry = Gtk.Entry { placeholder_text = '输入参数...', margin_start = 10, margin_end = 10, margin_top = 10, } -- 2×2布局结构:垂直布局嵌套两个水平布局 local main_vbox = Gtk.Box { orientation = Gtk.Orientation.VERTICAL, spacing = 15, margin = 10, } local hbox_row1 = Gtk.Box { orientation = Gtk.Orientation.HORIZONTAL, spacing = 10, } local hbox_row2 = Gtk.Box { orientation = Gtk.Orientation.HORIZONTAL, spacing = 10, } -- 填充布局占位组件 for i=1,2 do hbox_row1:append(Gtk.Frame { label = '面板1-'..i, child = Gtk.Label { label = '内容区域' }, valign = Gtk.Align.FILL, hexpand = true, }) hbox_row2:append(Gtk.Frame { label = '面板2-'..i, child = Gtk.Label { label = '内容区域' }, valign = Gtk.Align.FILL, hexpand = true, }) end -- 绘图区 local solar_draw_area = Gtk.DrawingArea { height_request = 300, valign = Gtk.Align.FILL, hexpand = true, } -- 太阳系绘制逻辑 solar_draw_area:set_draw_func(function(widget, cr, w, h) -- 绘制背景 cr:set_source_rgb(0.02, 0.02, 0.05) cr:paint() -- 绘制地球(中心) cr:set_source_rgb(0.2, 0.4, 0.8) cr:arc(w/2, h/2, 30, 0, 2*math.pi) cr:fill() -- 绘制轨道和行星 cr:set_source_rgba(0.5, 0.5, 0.5, 0.3) cr:set_line_width(2) cr:arc(w/2, h/2, 80, 0, 2*math.pi) cr:stroke() cr:set_source_rgb(1, 0.6, 0.2) cr:arc(w/2 + 80, h/2, 15, 0, 2*math.pi) cr:fill() end) -- 组装布局 main_vbox:append(input_entry) main_vbox:append(solar_draw_area) main_vbox:append(hbox_row1) main_vbox:append(hbox_row2) window:set_child(main_vbox) window:connect('destroy', Gtk.main_quit) window:show() Gtk.main()
内容的提问来源于stack exchange,提问作者aum hren
相关产品推荐
相关产品推荐

