简体   繁体   English

与可编辑的Gtk.TreeView及其ListStore同步

[英]Synchoronize editable Gtk.TreeView with its ListStore

I'm building an interface in Gtk3/Python3, using Glade, showing data from a ListStore in a TreeView, and letting the user edit the values in one of the columns. 我正在使用Glade在Gtk3 / Python3中构建一个接口,在TreeView中显示来自ListStore的数据,并允许用户编辑其中一列中的值。

As said, I'm using glade, and in the glade file it's written which ListStore column serves what data for each GtkCellRenderer . 如前所述,我正在使用林间空地,并且在林间空地文件中写入了哪个ListStore每个GtkCellRenderer提供哪些数据。 The first funny thing is that I do not know how to get to this information, and I'm introducing redundancy in order to keep things working. 第一个有趣的事情是我不知道如何获取此信息,并且我正在引入冗余以使事情正常进行。

Next more interesting trouble: when an edited cell loses focus, but focus stays in the TreeView, my callback for the edited signal is invoked and I can store the edited value in the ListStore. 下一个更有趣的麻烦:当一个已编辑的单元格失去焦点,但焦点仍停留在TreeView中时,将调用我对已edited信号的回调,并将已编辑的值存储在ListStore中。

When an edited cell loses focus, and focus goes to a different widget (like in the further useless Button in the example), the registered callback is not invoked. 当一个已编辑的单元格失去焦点,并且焦点转到另一个小部件时(如示例中另一个无用的Button一样),则不会调用已注册的回调。 Also if the window loses focus, the previous value is restored. 同样,如果窗口失去焦点,则将恢复先前的值。 This last one is particularly unpractical in the case 'focus-follows-mouse'. 在“焦点跟随鼠标”的情况下,最后一个特别不切实际。

What's the deal? 这是怎么回事?

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk


class TestWindow:

    def __init__(self, builder):
        import os.path
        path, name = os.path.split(__file__)
        builder.add_from_file(os.path.join(path, "treeedit.glade"))
        builder.connect_signals(self)
        self.window = builder.get_object("window1")
        self.window.connect("destroy", Gtk.main_quit)
        self.notes_list = builder.get_object("notes_list")
        self.notes_list.append(('a',))
        self.notes_list.append(('b',))
        self.notes_list.append(('c',))
        self.notes_list.append(('d',))

    def on_cell_edited(self, widget, path, text):
        self.notes_list[path][0] = text

    def show_all(self):
        self.window.show_all()


builder = Gtk.Builder()
win = TestWindow(builder)
win.show_all()
Gtk.main()

and this is the glade file: 这是林间空地文件:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkListStore" id="notes_list">
    <columns>
      <!-- column-name content -->
      <column type="gchararray"/>
    </columns>
  </object>
  <object class="GtkDialog" id="window1">
    <property name="can_focus">False</property>
    <property name="type_hint">dialog</property>
    <child internal-child="vbox">
      <object class="GtkBox">
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child>
          <object class="GtkButton">
            <property name="label" translatable="yes">button</property>
          </object>
        </child>
        <child>
          <object class="GtkFrame">
            <property name="visible">True</property>
            <child>
              <object class="GtkAlignment">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="left_padding">12</property>
                <child>
                  <object class="GtkTreeView" id="notes_tree">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="hexpand">True</property>
                    <property name="vexpand">True</property>
                    <property name="model">notes_list</property>
                    <property name="headers_clickable">False</property>
                    <child internal-child="selection">
                      <object class="GtkTreeSelection"/>
                    </child>
                    <child>
                      <object class="GtkTreeViewColumn">
                        <property name="resizable">True</property>
                        <property name="title" translatable="yes">value</property>
                        <child>
                          <object class="GtkCellRendererText" id="prefs_cellrenderertext1">
                            <property name="editable">True</property>
                            <signal name="edited" handler="on_cell_edited" swapped="no"/>
                          </object>
                          <attributes>
                            <attribute name="text">0</attribute>
                          </attributes>
                        </child>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
            <child type="label">
              <object class="GtkLabel">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">Notes</property>
              </object>
            </child>
          </object>
        </child>
      </object>
    </child>
  </object>
</interface>

My own answer is just a partial answer, because what if I need to edit multiple columns? 我自己的答案只是部分答案,因为如果我需要编辑多列怎么办? as of now, I've resorted to writing multiple callbacks to the editing-started signal, like this: 截至目前,我已经诉诸于将多个回调写入到editing-started信号中,如下所示:

def on_cell_editing_started_col0(self, *args):
    self.column = 0

def on_cell_editing_started_col1(self, *args):
    self.column = 1

then I'm using the self.column value in both callbacks, for Gtk.CellRendererText edited signal, and Gtk.TreeView set-focus-child signal. 然后我在两个回调中都使用self.column值,分别用于Gtk.CellRendererText edited信号和Gtk.TreeView set-focus-child信号。

Looks like I can register a callback to the signal set-focus-child for the container TreeView . 看来我可以为容器TreeView的信号set-focus-child注册一个回调。 This gets called when an editable child starts being edited, and when editing is finished. 当可编辑的子项开始被编辑时,以及编辑完成时,将调用此方法。 In both cases the callback receives two parameters, the first of which is the TreeView itself. 在这两种情况下,回调都接收两个参数,第一个是TreeView本身。

When editing starts, the second parameter is a temporary Gtk.Entry , with which the user interacts. 当编辑开始时,第二个参数是用户与之交互的临时Gtk.Entry When editing ends, the second parameter is a None . 编辑结束后,第二个参数为None

I might use this code, and I'm sure I do not know how robust this might be: 我可能会使用此代码,而且我确定我不知道这可能有多强大:

def on_focus_child(self, tree, entry):
    if entry is not None:
        self.last_entry = entry
    else:
        tv, path = tree.get_selection().get_selected()
        self.notes_list[path][0] = self.last_entry.get_text()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM