如何用Glade和Python实现含自定义迷你窗口项的滚动列表?
实现方案与学习指引
一、Glade中完全可行
你要的这种带自定义“迷你界面”的滚动列表,用Gtk.ListBox就能实现,完全可以在Glade里完成布局设计:
- 在Glade中先设计单个列表项的布局(比如一个Gtk.Box,里面放剩余时间标签、暂停按钮、停止按钮),可以把这个布局存为单独模板,或直接在主窗口的ListBox里作为原型。
- 主界面的滚动区域内放置Gtk.ListBox,后续用Python代码动态生成你设计的列表项实例,添加到ListBox中即可。
Gtk.ListBox天生支持滚动(配合Gtk.ScrolledWindow),且允许每个列表项是任意复杂的Widget组合,完全能替代你不想用的GtkTreeView。
二、Python与多定时器的交互实现
核心思路是用类封装每个定时器的UI和逻辑,让每个列表项成为独立的功能单元:
- 定义一个
TimerItem类,继承自你在Glade中设计的列表项容器(比如Gtk.Box),在类中封装:- UI控件引用:剩余时间标签、暂停/停止按钮
- 定时器状态:剩余秒数、是否运行、Gtk超时回调的ID(用于暂停/取消)
- 类内部实现定时器逻辑:
- 启动定时器:用
GLib.timeout_add(1000, self.update_time)注册每秒更新剩余时间的回调 - 暂停/恢复:暂停时调用
GLib.source_remove(self.timeout_id)取消回调,恢复时重新注册 - 停止:取消回调后重置时间,并从ListBox中移除当前项
- 启动定时器:用
- 按钮信号绑定:在类的初始化方法中,把暂停/停止按钮的
clicked信号连接到类内部的对应方法,这样每个列表项的按钮只会触发自身的定时器逻辑,不会互相干扰。 - 新增定时器:当用户在设置区输入时间并点击启动时,实例化一个
TimerItem,传入设置的时间,然后调用list_box.append(timer_item)把它添加到滚动列表中。
示例代码片段(简化版):
import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk, GLib class TimerItem(Gtk.Box): def __init__(self, total_seconds): super().__init__(spacing=10) self.total_seconds = total_seconds self.remaining = total_seconds self.running = False self.timeout_id = None # 从Glade加载布局或者直接创建控件 self.time_label = Gtk.Label(label=self.format_time(self.remaining)) self.pause_btn = Gtk.Button(label="暂停") self.stop_btn = Gtk.Button(label="停止") self.append(self.time_label) self.append(self.pause_btn) self.append(self.stop_btn) # 绑定信号 self.pause_btn.connect("clicked", self.on_pause_clicked) self.stop_btn.connect("clicked", self.on_stop_clicked) # 启动定时器 self.start_timer() def format_time(self, seconds): mins = seconds // 60 secs = seconds % 60 return f"{mins:02d}:{secs:02d}" def start_timer(self): self.running = True self.timeout_id = GLib.timeout_add(1000, self.update_time) def update_time(self): self.remaining -= 1 self.time_label.set_label(self.format_time(self.remaining)) if self.remaining <= 0: self.on_stop_clicked(None) return False return True def on_pause_clicked(self, widget): if self.running: GLib.source_remove(self.timeout_id) self.pause_btn.set_label("恢复") else: self.start_timer() self.pause_btn.set_label("暂停") self.running = not self.running def on_stop_clicked(self, widget): if self.timeout_id: GLib.source_remove(self.timeout_id) # 从父容器中移除自己 parent = self.get_parent() if parent: parent.remove(self)
三、学习资料方向
- Gtk官方文档:重点看
Gtk.ListBox和GLib.Timeout相关章节,了解列表项的动态管理和定时器回调机制;如果用Glade,重点学习Gtk复合控件的设计与加载方法。 - Python-GObject绑定文档:学习如何用Python继承Gtk控件、处理信号、管理GLib的异步回调,这是Python操作Gtk的核心基础。
- 自定义列表项教程:搜索“Gtk ListBox custom widget”相关内容,找分步实现的例子,学习如何将UI和逻辑封装到自定义控件中。
- Gtk4入门教程:如果你用的是Gtk4,找一套完整的入门教程,熟悉窗口布局、控件生命周期、信号系统这些基础概念,对你理解整体实现至关重要。
内容的提问来源于stack exchange,提问作者francescoe
相关产品推荐
相关产品推荐

