TreeViewColumn标头中的PyGTK Entry小部件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TreeViewColumn标头中的PyGTK Entry小部件相关的知识,希望对你有一定的参考价值。
如何在gtk.Entry
标题/标题中制作可调焦或可编辑的gtk.TreeViewColumn
小部件?我试过这个:
# Create tree-view.
treeview = gtk.TreeView()
#...
# Create column.
renderer = gtk.CellRendererText()
column = gtk.TreeViewColumn(None, renderer, text=0)
# Set column header.
header = gtk.VBox()
title = gtk.Label("Column")
header.pack_start(title)
filter = gtk.Entry()
#...
header.pack_start(filter)
header.show_all()
column.set_widget(header)
# Add column
treeview.append_column(column)
但是列标题中的Entry小部件不可编辑且不会聚焦。我已经尝试将'clickable'设置为True
和False
。我在Ubuntu 10.04上使用pygtk 2.21.0-0ubuntu1和libgtk 2.22.0-0ubuntu1。任何帮助将不胜感激。
编辑:
问题源于如何显示GtkTreeViewColumn
标头。标题小部件放在GtkAlignment
内,其父级是GtkHBox
,其父级是GtkButton
,其父级最终是GtkTreeView
。 GtkButton
正在拦截并阻止我的GtkEntry
被聚焦并接收鼠标输入。
为了使GtkEntry
可以在GtkTreeView
标题内集中,我不得不:
1)找到标题GtkButton
。
def find_closest_ancestor(widget, ancestor_class):
if not isinstance(widget, gtk.Widget):
raise TypeError("%r is not a gtk.Widget" % widget)
ancestor = widget.get_parent()
while ancestor is not None:
if isinstance(ancestor, ancestor_class):
break;
ancestor = ancestor.get_parent() if hasattr(ancestor, 'get_parent') and callable(ancestor.get_parent) else None
return ancestor
2)将button-press-event
信号从标题GtkButton
传播到GtkEntry
。
def propagate_button_press_event(parent, event, *data):
parent_alloc = parent.get_allocation()
x = parent_alloc.x + int(event.x)
y = parent_alloc.y + int(event.y)
children = parent.get_children()
print "Propagating event:%r" % event
print "- from parent:%r" % parent
while children:
for child in children:
child_alloc = child.get_allocation()
if child_alloc.x <= x <= child_alloc.x + child_alloc.width and child_alloc.y <= y <= child_alloc.y + child_alloc.height:
print "- to child:%r" % child
if child.get_property('can-focus'):
event.send_event = True
child.grab_focus()
child.emit('button-press-event', event, *data)
return True
else:
children = child.get_children() if hasattr(child, 'get_children') and callable(child.get_children) else None
break;
else:
children = None
return False
3)将焦点(即focus-in-event
信号)从标题GtkButton
传播到GtkEntry
。
def propagate_focus_in_event(parent, event, *data):
print 'focus-in', parent, event
child = parent.get_child()
if child.get_property('can-focus'):
child.grab_focus()
else:
if not child.child_focus(gtk.DIR_TAB_FORWARD):
parent.get_toplevel().child_focus(gtk.DIR_TAB_FORWARD)
return True
例:
# Fix style glitches
_gtk_styles = """
# Use the default GtkEntry style for GtkEntry widgets in treeview headers.
widget "*.treeview-header-entry" style "entry"
"""
gtk.rc_parse_string(_gtk_styles)
# Columns
_columns = [
(0, "Title"),
(1, "Description")
# etc.
]
# Create tree-view.
items_view = gtk.TreeView(self.items_store)
items_view.show()
# Setup treeview columns.
renderer = gtk.CellRendererText()
for column in _columns:
column_index, column_title, column_filter = column
column_view = gtk.TreeViewColumn(None, renderer, text=column_index)
column_view.set_clickable(True)
column_widget = gtk.VBox()
column_widget.show()
column_align = gtk.Alignment(0, 0, 0, 0)
column_align.show()
column_widget.pack_start(column_align)
column_label = gtk.Label(column_title)
column_label.show()
column_align.add(column_label)
column_entry = gtk.Entry()
column_entry.set_name('treeview-header-entry')
column_entry.show()
column_widget.pack_start(column_entry)
column_view.set_widget(column_widget)
items_view.append_column(column_view)
# Setup column headers.
columns = items_view.get_columns()
for column in columns:
column_widget = column.get_widget()
column_header = find_closest_ancestor(column_widget, gtk.Button)
if column_header:
column_header.connect('focus-in-event', propagate_focus_in_event)
column_header.connect('button-press-event', propagate_button_press_event)
column_header.set_focus_on_click(False)
自问这个问题以来,API已经发展,所以我想我会发布一个更新的答案。 (虽然在我的情况下,我试图在列标题中放入两个按钮而不是条目,但我在遇到类似问题时偶然发现了这一点。)
首先,一些背景。正如问题编辑中所提到的,问题源于TreeViewColumn的结构方式。该列的标题是一个Button,当您使用set_widget
时,该小部件将成为Button的后代。 (这很容易被忽略,因为标题不像按钮那样响应,除非你将列设置为可点击。此外,文档没有帮助,因为它似乎假设每个人都已经知道这一点。)问题的另一个原因是按钮收集事件的方式。与大多数响应事件的小部件不同,Button在Gdk.Window层次结构中没有自己的位置。相反,它在实现时会创建一个特殊的事件窗口。访问此窗口的方法是按钮特定的:get_event_window
(与更通用的get_window
和get_parent_window
不同)。此事件窗口隐藏在Button上方,在它们向下流入Button的任何后代之前收集事件。因此,您放置在列标题中的窗口小部件不会接收交互所需的事件。
接受的解决方案是绕过这个障碍的一种方式,当时它是一个值得回答的答案。但是,现在有一种更简单的方法。 (我应该提一下,这是一个GTK +问题,独立于使用的语言绑定。个人而言,我使用的是C ++绑定。我还偷看了GTK +源文件 - 在C中 - 以确认这是核心GTK +行为而不是一些装订的神器。)
1)找到标题按钮。
如果column
是有问题的TreeViewColumn,那么获取按钮的API现在就是:
header_button = column.get_button()
在3.0版本中添加了get_button
方法,该问题在提出此问题后约六个月被标记。很近。
2)将事件从Button传播到Entry。
为简化此步骤花了四年时间(版本3.18)。关键的发展是set_pass_through
,它可以告诉事件窗口让事件通过。正如文档所述:“在网络术语中,这将被称为'指针 - 事件:无'。”
def pass_through_event_window(button, event):
if not isinstance(button, gtk.Button):
raise TypeError("%r is not a gtk.Button" % button)
event_window = button.get_event_window()
event_window.set_pass_through(True)
剩下的技巧是计时之一。在实现Button之前不会创建事件窗口,因此按顺序连接到Button的realize
信号。
header_button.connect('realize', pass_through_event_window)
就是这样(没有第3步)。事件现在将传播到Entry或列在列标题中的任何窗口小部件。
如果我搞砸了语法,我很抱歉;我正在翻译C ++绑定。如果有错误,我会请求一位善意的Python大师来纠正它们。
除非这不是你的答案,但我建议你使用标准和常用方法:使用treeview.set_search_column(COLUMN_INDEX)
,默认情况下不会显示任何条目(并使UI更清晰)但是当用户开始输入时(重点关注该树视图)弹出窗口输入条目将被显示,搜索和过滤将由GTK自动完成。
如果您坚持搜索条目应始终可见,请使用treeview.set_headers_visible(False)
删除treeview标头,并在树视图上方添加自定义HBox(包含标签和条目)。
以上是关于TreeViewColumn标头中的PyGTK Entry小部件的主要内容,如果未能解决你的问题,请参考以下文章