You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从G_DEFINE_TYPE声明的自定义类型中获取GtkWindow或顶级部件?

问题:从G_DEFINE_TYPE声明的自定义类型中获取GtkWindow/顶级部件

我需要从使用G_DEFINE_TYPE声明的自定义类型中获取GtkWindow或顶级部件,以下是我的代码实现:

MyAppWindow.c

#include "MyAppWindow.h"

struct _MyAppWindow
{
    GtkApplicationWindow parent;
};

G_DEFINE_TYPE (MyAppWindow, my_app_window, GTK_TYPE_APPLICATION_WINDOW);

void my_app_window_init (MyAppWindow *app)
{
}

void my_app_window_class_init (MyAppWindowClass *class)
{
}

MyAppWindow * my_app_window_new (MyApp *app)
{
    return g_object_new (MY_APP_WINDOW_TYPE, "application", app, NULL);
}

MyAppWindow.h

#ifndef _MY_APP_WINDOW_H_INCLUDED
#define _MY_APP_WINDOW_H_INCLUDED

#include "MyApp.h"

#define MY_APP_WINDOW_TYPE (my_app_window_get_type ())
G_DECLARE_FINAL_TYPE (MyAppWindow, my_app_window, MY, APP_WINDOW, GtkApplicationWindow)

MyAppWindow * my_app_window_new (MyApp *);

#endif

MyApp.c

struct _MyApp
{
    GtkApplication parent;
};

G_DEFINE_TYPE (MyApp, my_app, GTK_TYPE_APPLICATION);

void my_app_init (MyApp *app)
{
}

void my_app_activate (GApplication *app)
{
    MyAppWindow *win;

// 创建窗口:
    win = my_app_window_new (MY_APP (app));
}

void my_app_class_init (MyAppClass *class)
{
    G_APPLICATION_CLASS (class)->activate = my_app_activate;
}

MyApp *my_app_new (AppData *pad)
{
    MyApp *obj = g_object_new (MY_APP_TYPE, "application-id", PROJECT_APPID, "flags", G_APPLICATION_DEFAULT_FLAGS, NULL);
    return obj;
}

activate函数补充实现

void my_app_activate (GApplication *app)
{
     MyAppWindow *win = my_app_window_new (MY_APP (app));
     // .. 更多代码
     g_action_map_add_action_entries (G_ACTION_MAP (app), entries, G_N_ELEMENTS (entries), app);
}

回调函数cb_showmsg

void cb_showmsg (GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
     // user_data: 需要同时访问GApplication和MyAppWindow
    // 用户Holger提供的一种方案:
    GtkWindow* toplevel = gtk_application_get_active_window (user_data);
   // 
}

我需要获取MyAppWindow来显示或隐藏顶级窗口,请问有什么可行的解决思路?


可行解决思路
  • 类型转换直接获取:因为MyAppWindow是GtkApplicationWindow的子类,而GtkApplicationWindow本身就是GtkWindow的子类,可直接用类型宏转换。注意先做类型检查避免错误:

    void cb_showmsg (GSimpleAction *action, GVariant *parameter, gpointer user_data)
    {
        GtkWindow* toplevel = gtk_application_get_active_window (GTK_APPLICATION(user_data));
        if (GTK_IS_APPLICATION_WINDOW(toplevel) && MY_IS_APP_WINDOW(toplevel)) {
            MyAppWindow *win = MY_APP_WINDOW(toplevel);
            // 执行显示/隐藏操作,如gtk_widget_show(GTK_WIDGET(win))或gtk_widget_hide(GTK_WIDGET(win))
        }
    }
    
  • 保存窗口引用到App实例:在MyApp结构体中添加成员存储窗口指针,后续通过App实例直接获取:

    1. 修改MyApp结构体(需在头文件声明):
      struct _MyApp
      {
          GtkApplication parent;
          MyAppWindow *window; // 新增窗口成员
      };
      
    2. 在my_app_activate中赋值:
      void my_app_activate (GApplication *app)
      {
          MyApp *my_app = MY_APP(app);
          my_app->window = my_app_window_new (my_app);
          gtk_widget_show(GTK_WIDGET(my_app->window)); // 显示窗口
          g_action_map_add_action_entries (G_ACTION_MAP (app), entries, G_N_ELEMENTS (entries), app);
      }
      
    3. 在回调中直接调用:
      void cb_showmsg (GSimpleAction *action, GVariant *parameter, gpointer user_data)
      {
          MyApp *my_app = MY_APP(user_data);
          if (my_app->window != NULL) {
              gtk_widget_hide(GTK_WIDGET(my_app->window)); // 示例:隐藏窗口
          }
      }
      
  • 封装结构体作为user_data传递:如果需要同时访问App和窗口,可封装一个结构体作为回调的user_data:

    1. 定义结构体:
      typedef struct {
          MyApp *app;
          MyAppWindow *window;
      } CallbackData;
      
    2. 在my_app_activate中创建并传递:
      void my_app_activate (GApplication *app)
      {
          MyAppWindow *win = my_app_window_new (MY_APP(app));
          CallbackData *data = g_new(CallbackData, 1);
          data->app = MY_APP(app);
          data->window = win;
          g_action_map_add_action_entries (G_ACTION_MAP (app), entries, G_N_ELEMENTS (entries), data);
          // 记得在App退出时释放data,例如在my_app_shutdown函数中处理
      }
      
    3. 在回调中使用:
      void cb_showmsg (GSimpleAction *action, GVariant *parameter, gpointer user_data)
      {
          CallbackData *data = user_data;
          if (data->window != NULL) {
              gtk_widget_show(GTK_WIDGET(data->window)); // 示例:显示窗口
          }
      }
      

内容的提问来源于stack exchange,提问作者Joel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 22:10:02