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

GTK中如何防止线程多实例运行解决TreeView重复条目问题

解决GTK多线程操作ListStore导致重复条目的问题

针对快速点击按钮触发多线程并行操作ListStore,导致TreeView出现重复条目的问题,以下是两种可行的解决方案:

方案1:当前线程运行时禁止启动新线程

给窗口类添加线程状态标记,每次点击按钮时先检查是否已有活跃线程,仅当无活跃线程时才启动新线程,线程执行完毕后重置状态标记。

修改后的代码示例:

import threading
import time
import Gtk

class Main(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("destroy", Gtk.main_quit)

        self.liststore = Gtk.ListStore(str)
        self.treeview = Gtk.TreeView()
        self.treeview.set_model(self.liststore)
        cellrenderertext = Gtk.CellRendererText()
        treeviewcolumn = Gtk.TreeViewColumn("Items", cellrenderertext, text=0)
        self.treeview.append_column(treeviewcolumn)

        self.button = Gtk.Button(label='Button')

        box = Gtk.Box()
        box.set_orientation(Gtk.Orientation.VERTICAL)

        box.add(self.button)
        box.add(self.treeview)
        self.add(box)

        self.button.connect('clicked', self.button_clicked)
        # 初始化线程状态标记
        self.active_thread = None

    def button_clicked(self, widget):
        # 检查是否已有活跃线程
        if self.active_thread and self.active_thread.is_alive():
            return
        
        def threaded():
            self.liststore.clear()
            self.liststore.append(['first_item'])
            time.sleep(0.1)
            self.liststore.append(['second_item'])
            time.sleep(0.1)
            self.liststore.append(['third_item'])
            # 线程结束后重置标记
            self.active_thread = None

        self.active_thread = threading.Thread(target=threaded, daemon=True)
        self.active_thread.start()


if __name__ == '__main__':
    window = Main()
    window.show_all()
    Gtk.main()

方案2:终止已运行的线程再启动新线程

Python原生线程无法强制终止,因此可以通过threading.Event实现线程的优雅退出。每次点击按钮时,先触发停止事件让旧线程退出,再启动新线程。

修改后的代码示例:

import threading
import time
import Gtk

class Main(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("destroy", Gtk.main_quit)

        self.liststore = Gtk.ListStore(str)
        self.treeview = Gtk.TreeView()
        self.treeview.set_model(self.liststore)
        cellrenderertext = Gtk.CellRendererText()
        treeviewcolumn = Gtk.TreeViewColumn("Items", cellrenderertext, text=0)
        self.treeview.append_column(treeviewcolumn)

        self.button = Gtk.Button(label='Button')

        box = Gtk.Box()
        box.set_orientation(Gtk.Orientation.VERTICAL)

        box.add(self.button)
        box.add(self.treeview)
        self.add(box)

        self.button.connect('clicked', self.button_clicked)
        # 初始化停止事件和线程对象
        self.stop_event = threading.Event()
        self.active_thread = None

    def button_clicked(self, widget):
        # 如果有活跃线程,触发停止事件并等待其退出
        if self.active_thread and self.active_thread.is_alive():
            self.stop_event.set()
            self.active_thread.join()
            self.stop_event.clear()
        
        def threaded():
            self.liststore.clear()
            # 每次操作前检查是否需要停止
            if self.stop_event.is_set():
                return
            self.liststore.append(['first_item'])
            
            time.sleep(0.1)
            if self.stop_event.is_set():
                return
            self.liststore.append(['second_item'])
            
            time.sleep(0.1)
            if self.stop_event.is_set():
                return
            self.liststore.append(['third_item'])

        self.active_thread = threading.Thread(target=threaded, daemon=True)
        self.active_thread.start()


if __name__ == '__main__':
    window = Main()
    window.show_all()
    Gtk.main()

补充说明:GTK的UI操作规范上应在主线程执行,虽然ListStore多线程操作有时能正常工作,但更严谨的做法是用Gtk.idle_add或GObject信号机制将UI更新逻辑放到主线程中执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 03:10:25