GTK3窗口添加图片背景遮挡布局及控件问题咨询
问题现象
- 基于GTK3编写带多层嵌套布局的窗口,主布局下的子布局均挂载了对应业务控件,尝试给窗口添加图片背景时,背景图片会遮挡主布局内所有其他布局与控件。
- 同一份代码在GTK2环境下运行表现符合预期:子布局与控件均可正常显示在pixmap图层上方。
测试复现代码
GtkWidget* create_wndmain (void) { GtkWidget *wndmain; GtkWidget *lytmain; GtkWidget *lytpreview; GtkWidget *txtpreview; GtkWidget *lytutils; GtkWidget *txtutils; GtkWidget *lytfsys; GtkWidget *txtfsys; GtkWidget *pixmap; wndmain = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (wndmain), _("Window")); gtk_window_set_position (GTK_WINDOW (wndmain), GTK_WIN_POS_CENTER); gtk_window_set_default_size (GTK_WINDOW (wndmain), 1024, 720); lytmain = gtk_layout_new (NULL, NULL); gtk_widget_show (lytmain); gtk_container_add (GTK_CONTAINER (wndmain), lytmain); pixmap = gtk_image_new_from_file("pixmaps/layout-1920x1080.png"); gtk_container_add (GTK_CONTAINER (lytmain), pixmap); gtk_widget_show (pixmap); lytpreview = gtk_layout_new (NULL, NULL); gtk_widget_show (lytpreview); gtk_layout_put (GTK_LAYOUT (lytmain), lytpreview, 848, 88); gtk_widget_set_size_request (lytpreview, 168, 480); gtk_layout_set_size (GTK_LAYOUT (lytpreview), 400, 400); pixmap = gtk_image_new_from_file("pixmaps/layout-1920x1080.png"); gtk_container_add (GTK_CONTAINER (lytpreview), pixmap); gtk_widget_show (pixmap); txtpreview = gtk_text_view_new (); gtk_widget_show (txtpreview); gtk_layout_put (GTK_LAYOUT (lytpreview), txtpreview, 8, 376); gtk_widget_set_size_request (txtpreview, 144, 80); gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (txtpreview)), _("\n\n Preview Area"), -1); lytutils = gtk_layout_new (NULL, NULL); gtk_widget_show (lytutils); gtk_layout_put (GTK_LAYOUT (lytmain), lytutils, 664, 8); gtk_widget_set_size_request (lytutils, 344, 72); gtk_layout_set_size (GTK_LAYOUT (lytutils), 400, 400); txtutils = gtk_text_view_new (); gtk_widget_show (txtutils); gtk_layout_put (GTK_LAYOUT (lytutils), txtutils, 16, 8); gtk_widget_set_size_request (txtutils, 312, 56); gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (txtutils)), _("\n \tUtility Area"), -1); lytfsys = gtk_layout_new (NULL, NULL); gtk_widget_show (lytfsys); gtk_layout_put (GTK_LAYOUT (lytmain), lytfsys, 8, 88); gtk_widget_set_size_request (lytfsys, 192, 480); gtk_layout_set_size (GTK_LAYOUT (lytfsys), 400, 400); txtfsys = gtk_text_view_new (); gtk_widget_show (txtfsys); gtk_layout_put (GTK_LAYOUT (lytfsys), txtfsys, 32, 72); gtk_widget_set_size_request (txtfsys, 128, 328); gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (txtfsys)), _("\n\n\n File system Area"), -1); return wndmain; } int main (int argc, char *argv[]) { GtkWidget *wndmain; gtk_init (&argc, &argv); wndmain = create_wndmain (); gtk_widget_show (wndmain); gtk_main (); return 0; }
问题原因
GTK2与GTK3的控件绘制逻辑存在本质差异:
- GTK2版本的GtkLayout严格按照子控件添加顺序从底层到顶层绘制,先添加的pixmap处在最底层,后续添加的子布局、控件自然会叠加显示在背景上方。
- GTK3重构了整个绘制栈与Z序排序规则,通过
gtk_container_add添加到GtkLayout的子项,会被默认放置在Z序顶层,因此后添加的子布局、控件反而会被先加的背景图遮挡。
解决方案
提供两种可直接落地的修复方式:
- 方案一:调整背景图添加逻辑
不要用gtk_container_add添加背景图,统一用gtk_layout_put将背景图放置在布局的(0,0)坐标处,保证背景图是对应布局第一个通过gtk_layout_put添加的子项,同时设置背景图尺寸匹配布局大小即可。
主布局背景的修改示例:
子布局// 注释掉原有错误写法 // gtk_container_add (GTK_CONTAINER (lytmain), pixmap); // 替换为以下代码 gtk_layout_put(GTK_LAYOUT(lytmain), pixmap, 0, 0); gtk_widget_set_size_request(pixmap, 1024, 720);lytpreview内的背景图也做相同修改即可。 - 方案二:使用GTK3官方推荐的CSS方式设置背景
不需要额外创建GtkImage控件,直接通过CSS给布局设置背景属性,背景会自动作为容器底层绘制,完全不会出现Z序遮挡问题,是更规范的实现方式。示例代码:GtkCssProvider *bg_provider = gtk_css_provider_new(); gtk_css_provider_load_from_data(bg_provider, "GtkLayout {" " background-image: url('pixmaps/layout-1920x1080.png');" " background-size: 100% 100%;" " background-repeat: no-repeat;" "}", -1, NULL); gtk_style_context_add_provider(gtk_widget_get_style_context(lytmain), GTK_STYLE_PROVIDER(bg_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); g_object_unref(bg_provider);
内容的提问来源于stack exchange,提问作者Kirubakaran
相关产品推荐
相关产品推荐

