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

GTK4 ColumnView如何在单个单元格修改时更新整行?

如何让GTK4的ColumnView在单元格修改时实时更新整行显示

当前代码中,修改字符串或ASCII码单元格时,模型数据已经同步更新,但ColumnView只有在切换行时才会刷新显示。要实现无需切换行就实时更新,核心在于让DataObject的属性变更能够通知到Gio.ListStore,进而触发ColumnView的实时刷新。

解决方案

问题出在属性绑定的方向和模型通知机制上:默认的属性绑定只处理单向同步,且当你直接修改DataObject的属性时,需要确保模型能够感知到对象的属性变化并触发视图更新。我们需要做两处关键修改:

  • 在bind_property时添加GObject.BindingFlags.BIDIRECTIONAL,实现双向绑定,确保视图和模型的实时同步。
  • 在修改DataObject的属性后,手动触发Gio.ListStore的items_changed信号,通知视图更新对应行的内容。

修改后的完整代码

import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gio, GObject

class DataObject(GObject.GObject):

    __gtype_name__ = 'DataObject'

    text = GObject.Property(type=str, default=None)
    number = GObject.Property(type=str, default=None)
    
    def __init__(self, text, number):
        super().__init__()
        self.text = text
        self.number = number

def setup_c1(widget, item):
    """Setup the widget to show in the Gtk.Listview"""
    cell = Gtk.EditableLabel()
    item.set_child(cell)
    cell.connect('changed', on_c1_change, item)

def bind_c1(widget, item):
    """bind data from the store object to the widget"""
    label = item.get_child()
    obj = item.get_item()
    # 添加双向绑定,确保模型变更也能同步回视图
    label.bind_property(
        "text", obj, "text",
        GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL
    )
    
def setup_c2(widget, item):
    """Setup the widget to show in the Gtk.Listview"""
    cell = Gtk.EditableLabel()    
    item.set_child(cell)
    cell.connect('changed', on_c2_change, item)

def bind_c2(widget, item):
    """bind data from the store object to the widget"""
    label = item.get_child()
    obj = item.get_item()
    # 添加双向绑定
    label.bind_property(
        "text", obj, "number",
        GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL
    )

def on_c1_change(self, item):
    obj = item.get_item()
    obj.number = str(ord(obj.text))
    # 获取对象在store中的位置,触发items_changed信号
    store = item.get_list_item_factory().get_list_model()
    idx = store.find(obj)
    if idx != -1:
        store.items_changed(idx, 1, 1)

def on_c2_change(self, item):
    obj = item.get_item()
    if not obj.number == '' and int(obj.number) >= 65:
        obj.text = chr(int(obj.number))
        # 获取对象在store中的位置,触发items_changed信号
        store = item.get_list_item_factory().get_list_model()
        idx = store.find(obj)
        if idx != -1:
            store.items_changed(idx, 1, 1)

def on_activate(app):
    win = Gtk.ApplicationWindow(
        application=app,
        title="GTK 4 ColumnView实时更新示例",
        default_height=400,
        default_width=400,
    )
    
    list_view = Gtk.ColumnView()  
    factory_c1 = Gtk.SignalListItemFactory()
    factory_c1.connect("setup", setup_c1)
    factory_c1.connect("bind", bind_c1)
    
    factory_c2 = Gtk.SignalListItemFactory()
    factory_c2.connect("setup", setup_c2)
    factory_c2.connect("bind", bind_c2)    
    
    selection = Gtk.SingleSelection()
    store = Gio.ListStore.new(DataObject)  
    selection.set_model(store)
    list_view.set_model(selection)
    
    # 给工厂绑定list_model,方便后续获取store
    factory_c1.set_list_model(store)
    factory_c2.set_list_model(store)
    
    column1 = Gtk.ColumnViewColumn.new("String", factory_c1)
    column2 = Gtk.ColumnViewColumn.new("ASCII Code", factory_c2)
    
    list_view.append_column(column1)
    list_view.append_column(column2)

    for i in range(65, 91):
        store.append(DataObject(chr(i), str(i)))
    
    sw = Gtk.ScrolledWindow()
    sw.set_child(list_view)
    win.set_child(sw)
    win.present()

app = Gtk.Application(application_id="org.gtk.Example")
app.connect("activate", on_activate)
app.run(None)

关键修改说明

  1. 双向属性绑定:在bind_c1和bind_c2中,添加GObject.BindingFlags.BIDIRECTIONAL,这样当模型的text或number属性变更时,视图的EditableLabel会自动同步更新内容。
  2. 触发模型更新信号:在on_c1_change和on_c2_change回调中,通过store.find(obj)找到当前对象在ListStore中的索引,然后调用store.items_changed(idx, 1, 1)通知视图:该位置的1个条目发生了变化,需要重新渲染。
  3. 绑定ListModel到工厂:通过factory_c1.set_list_model(store)将ListStore绑定到工厂,方便在回调中直接获取到模型对象,避免额外的传递逻辑。

这样修改后,修改任意一个单元格时,另一列的内容会立即更新,无需切换行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 10:52:36