在GTK应用开发过程中,经常需要获取当前所有已打开的顶层窗口实例,用于实现窗口状态同步、批量修改窗口属性、统一处理窗口事件等功能。GTK框架本身提供了获取顶层窗口列表的接口,我们可以通过这些接口完成窗口遍历操作。

GTK顶层窗口的存储逻辑
GTK中所有顶层窗口(即Gtk.Window类的实例)都会被框架统一管理,存储在一个全局的顶层窗口列表中。我们可以通过Gtk.Window类的类方法获取这个列表,再对列表中的每个元素进行判断和操作。
需要注意的是,GTK的顶层窗口列表包含的是所有当前存在的顶层窗口对象,无论窗口是显示还是隐藏状态,只要窗口实例没有被销毁,就会存在于这个列表中。
Python语言实现遍历
使用Python的PyGObject绑定开发GTK应用时,可以通过Gtk.Window.list_toplevels()方法获取所有顶层窗口,之后遍历返回的列表即可。
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
def traverse_all_windows():
# 获取所有顶层窗口列表
toplevel_windows = Gtk.Window.list_toplevels()
print(f"当前共有 {len(toplevel_windows)} 个顶层窗口")
for window in toplevel_windows:
# 判断是否为Gtk.Window实例,避免其他顶层组件干扰
if isinstance(window, Gtk.Window):
title = window.get_title()
is_visible = window.get_visible()
print(f"窗口标题: {title}, 是否可见: {is_visible}")
return toplevel_windows
# 示例:创建一个简单窗口后调用遍历函数
if __name__ == "__main__":
win1 = Gtk.Window(title="窗口1")
win1.connect("destroy", Gtk.main_quit)
win1.show_all()
win2 = Gtk.Window(title="窗口2")
win2.show_all()
# 调用遍历函数
traverse_all_windows()
Gtk.main()
C语言实现遍历
使用C语言开发GTK应用时,同样通过gtk_window_list_toplevels()函数获取顶层窗口列表,该函数返回的是一个GList类型的链表,遍历链表即可拿到每个窗口实例。
#include <gtk/gtk.h>
// 遍历所有打开的GtkWindow实例
void traverse_all_windows() {
// 获取所有顶层窗口链表
GList *windows = gtk_window_list_toplevels();
GList *iter = windows;
int count = 0;
printf("开始遍历所有顶层窗口:n");
while (iter != NULL) {
// 判断当前元素是否为GtkWindow类型
if (GTK_IS_WINDOW(iter->data)) {
GtkWindow *window = GTK_WINDOW(iter->data);
const gchar *title = gtk_window_get_title(window);
gboolean is_visible = gtk_widget_get_visible(GTK_WIDGET(window));
printf("窗口%d: 标题=%s, 可见=%sn",
count + 1,
title ? title : "无标题",
is_visible ? "是" : "否");
count++;
}
iter = iter->next;
}
printf("总计找到 %d 个GtkWindow实例n", count);
// 释放链表内存,注意不释放窗口对象本身
g_list_free(windows);
}
int main(int argc, char *argv[]) {
gtk_init(&argc, &argv);
// 创建两个测试窗口
GtkWidget *win1 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(win1), "C语言窗口1");
g_signal_connect(win1, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(win1);
GtkWidget *win2 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(win2), "C语言窗口2");
gtk_widget_show_all(win2);
// 调用遍历函数
traverse_all_windows();
gtk_main();
return 0;
}
注意事项
- 遍历得到的窗口列表是动态的,如果在遍历过程中有窗口被创建或销毁,需要重新获取列表保证数据准确性。
- 如果只需要处理当前显示的窗口,可以在遍历时增加
get_visible()(Python)或gtk_widget_get_visible()(C)的判断过滤隐藏窗口。 - 不要随意销毁遍历得到的窗口实例,除非你明确知道业务需要,避免造成应用异常。
- GTK4版本中相关接口有调整,
gtk_window_list_toplevels()被替换为gtk_application_get_windows(),如果是GTK4应用需要适配对应接口。
常见问题
为什么遍历到的窗口数量和实际打开的不一致
可能是部分窗口已经被销毁但还未从列表中移除,或者存在非Gtk.Window类型的顶层组件被计入了列表。可以在遍历时增加类型判断,只处理Gtk.Window实例。
遍历操作会影响应用性能吗
正常情况下顶层窗口数量不会太多,单次遍历的性能开销可以忽略。如果需要在高频场景(比如定时每秒遍历一次)下使用,建议增加缓存机制,避免频繁获取列表。