【问题标题】:Don't set a Gtk.TreeView's selection when focusing?聚焦时不要设置 Gtk.TreeView 的选择?
【发布时间】:2015-01-27 15:04:27
【问题描述】:

以下代码显示一个带有按钮和树视图的窗口。 'clicked' 信号的句柄附加到按钮并聚焦树视图。最初显示窗口时,树形选择没有选定项,但当树形视图获得焦点时,会自动选择第一项。有没有办法在树视图获得焦点时不进行选择?

   
在点击之前,按钮有焦点,而树选择没有选中项。单击后,树视图有焦点,但已选择了一个项目。

由此产生的问题是,我有一个界面,通过附加到树视图的树选择上的“已更改”信号来使某些内容保持同步。当窗口显示时,根据树视图在界面中的位置,它们可能会默认获得焦点。这会导致“更改”信号,并发生意外同步。可以为所有树视图调用 set_can_focus(False),但是:

  1. 仅防止键盘循环焦点,而不是程序焦点,并且选择仍然以程序焦点打开;和
  2. 似乎禁用了取消选择选择的功能(例如,通过控制单击一行)。

同样,我可以使用 grab_default 来确保在显示窗口时首先获得焦点,但它不会阻止杂散焦点事件做出意外选择。

基于a posted answer 说选择模式 SINGLE “需要选择至少一个项目”,这解释了为什么在焦点上选择元素,我更多地研究了选择模式常量。其中,SINGLEBROWSE 似乎最相关。 pygtk 文档 GTK Selection Mode Constants 只说:

gtk.SELECTION_SINGLE通过单击允许单选。
gtk.SELECTION_BROWSE通过指针浏览允许单选。

GTK+3 文档enum GtkSelectionMode 更详细:

GTK_SELECTION_SINGLE 可以选择零个或一个元素。
GTK_SELECTION_BROWSE 恰好选择了一个元素。在一些 情况下,例如最初或在搜索操作期间,它是 可能无法使用 GTK_SELECTION_BROWSE 选择任何元素。什么 真正强制执行的是用户不能取消选择当前 选择的元素,除非选择另一个元素。

我在此处没有看到任何内容,建议在选择模式是单个选择模式时必须选择至少一个元素。

这里是重现窗口并作为示例的代码。

from gi.repository import Gtk

# A ListStore with some words
list_store = Gtk.ListStore(str)
for selection in "Can a machine think?".split():
    list_store.append([selection])

# A TreeView with a single column
tree_view = Gtk.TreeView(model=list_store)
cell_renderer = Gtk.CellRendererText()
tree_view_column = Gtk.TreeViewColumn(cell_renderer=cell_renderer,text=0,title='Words')
tree_view.append_column(tree_view_column)

# A button to focus the list
focus = Gtk.Button(label='Focus List')
focus.connect('clicked',lambda *_: tree_view.grab_focus())

# A Box to hold everything, and a Window for the Box.
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.add(focus)       # button on top gets initial focus
box.add(tree_view)   # tree_view below doesn't, and has no selected items 
window = Gtk.Window()
window.add(box)
window.show_all()

Gtk.main()

【问题讨论】:

  • 我想一种选择是连接和 connect_after 处理程序以获取“焦点”信号,并使用它们保存和恢复现有选择。这感觉有点笨拙,但也许它会同时工作,直到找到更好的解决方案。不过,如果这是最好的方法,那将是令人惊讶的。
  • 制作与‍VBoxButtonTreeView混合的新小部件,并将相关事件连接到用于控制焦点的操作。
  • 查看源代码:git.gnome.org/browse/gtk+/tree/gtk/… gtk_tree_view_focus_to_cursor 总是在调用 tree_view.grab_focus() 时被调用。我不知道你的用例,但也许你想记录一个错误来添加一个功能来防止这种情况发生。 bugzilla.gnome.org(您对选择模式常量的理解是正确的。使用 SINGLE,您可以按住 ctrl 单击返回零选择。)
  • @Mohsen 我不确定你想说什么。你的建议基本上是我已经做了来演示问题。问题是我不明白为什么要在树视图集中时设置选择。
  • 您可以使用处理独立焦点和选择的 cairo 库来制作新的TreeView 小部件,但这种方式非常困难。

标签: python python-3.x gtk pygtk gtk3


【解决方案1】:

查看root/gtk/gtktreeview.c for tree_view.grab_focus() 中的源代码,我们可以看到始终调用 gtk_tree_view_focus_to_cursor 并选择第一个元素。不过,在某些情况下,您可以解决此问题。

这是一个讨厌的黑客攻击。

它覆盖grab_focus方法,在调用grab_focus之前存储选择,如果之前没有选择,则在之后清除选择。

def tree_view_grab_focus():
    selection = tree_view.get_selection()
    _, selected = selection.get_selected()
    Gtk.TreeView.grab_focus(tree_view)
    if selected is None:
        selection.unselect_all()

tree_view.grab_focus = tree_view_grab_focus

不幸的是,它仅适用于从 Python 调用 grab_focus 时,其他调用者(例如 GTK 的键盘导航)不适用。

【讨论】:

  • 这似乎是I'd mentioned in the comments 的合理实现。我想知道是否可以将两个函数与connectconnect_after 连接,而不是覆盖grab_focus 方法,这在所有情况下都可以使用。最好将 your comment 中的内容添加到此答案中,因为它解释了行为。
猜你喜欢
  • 2015-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-05
  • 2021-12-10
  • 1970-01-01
  • 1970-01-01
  • 2016-05-30
相关资源
最近更新 更多