Wir überprüfen jede Aussage auf unserer Website gründlich mit dem Ziel, Ihnen jederzeit wahre und aktuelle Informationen zu zeigen.
Lösung:
Um eine GtkEntry
zu fokussieren innerhalb eines GtkTreeView
Überschrift zu machen, musste ich das tun:
1) Die Überschrift finden 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) Die Überschrift button-press-event
Signal von der Kopfzeile GtkButton
an die 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) Übertragen Sie den Fokus (d.h., focus-in-event
Signal) von der Kopfzeile GtkButton
an die 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
Beispiel:
# 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)
Die API hat sich weiterentwickelt, seit diese Frage gestellt wurde, daher dachte ich, ich würde eine aktualisierte Antwort veröffentlichen. (Ich war darüber gestolpert, als ich mich mit einem ähnlichen Problem befasste, obwohl ich in meinem Fall versuchte, zwei Schaltflächen in die Spaltenüberschrift zu setzen, nicht einen Eintrag).
Zunächst einige Hintergrundinformationen. Wie in der Bearbeitung der Frage erwähnt, liegt das Problem in der Art und Weise, wie eine TreeViewColumn aufgebaut ist. Die Überschrift der Spalte ist ein Button, und wenn man set_widget
wird dieses Widget ein Nachkomme des Buttons. (Dies kann leicht übersehen werden, da die Kopfzeile nicht wie eine Schaltfläche reagiert, es sei denn, Sie legen fest, dass die Spalte anklickbar ist. Auch die Dokumentation hilft nicht weiter, da sie davon auszugehen scheint, dass jeder dies bereits weiß.) Eine weitere Ursache für das Problem ist die Art und Weise, wie Schaltflächen Ereignisse sammeln. Anders als die meisten Widgets, die auf Ereignisse reagieren, hat eine Schaltfläche keinen eigenen Platz in der Gdk.Window-Hierarchie. Stattdessen erstellt er ein spezielles Ereignisfenster, wenn er realisiert wird. Die Methode für den Zugriff auf dieses Fenster ist Button-spezifisch: get_event_window
(im Unterschied zu der allgemeineren get_window
und get_parent_window
). Dieses Ereignisfenster befindet sich unsichtbar über der Schaltfläche und sammelt die Ereignisse, bevor sie an die Nachkommen der Schaltfläche weitergegeben werden. Daher erhält das Widget, das Sie in der Spaltenüberschrift platzieren, nicht die für die Interaktivität erforderlichen Ereignisse.
Die akzeptierte Lösung ist eine Möglichkeit, dieses Hindernis zu umgehen, und sie war seinerzeit eine gute Lösung. Jetzt gibt es jedoch einen einfacheren Weg. (Ich sollte erwähnen, dass dies ein Problem von GTK+ ist, unabhängig von der verwendeten Sprachbindung. Ich persönlich habe die C++-Sprachbindung verwendet. Ich habe auch einen Blick in die GTK+-Quelldateien - in C - geworfen, um zu bestätigen, dass dies ein Kernverhalten von GTK+ ist und nicht ein Artefakt der Bindung).
1) Finden Sie den Header Button.
Wenn column
die betreffende TreeViewColumn ist, ist die API für das Erhalten des Buttons jetzt einfach:
header_button = column.get_button()
Die get_button
Methode wurde in Version 3.0 hinzugefügt, die etwa sechs Monate nach dieser Frage veröffentlicht wurde. So nah dran.
2) Ereignisse von der Schaltfläche an den Eintrag weiterleiten.
Es dauerte weitere vier Jahre (Version 3.18), bis dieser Schritt vereinfacht wurde. Die wichtigste Entwicklung war set_pass_through
die das Ereignisfenster anweisen kann, Ereignisse durchzulassen. In der Dokumentation heißt es dazu: "In der Web-Terminologie würde dies als 'pointer-events: none' bezeichnet."
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)
Der verbleibende Trick ist eine Frage des Timings. Das Ereignisfenster wird erst erstellt, wenn der Button realisiert wird, so dass eine Verbindung mit dem Button's realize
Signal des Buttons zu verbinden, ist in Ordnung.
header_button.connect('realize', pass_through_event_window)
Und das war's (es gibt keinen Schritt 3). Die Ereignisse werden nun an den Eintrag oder das Widget weitergegeben, das Sie in die Spaltenüberschrift setzen.
Ich entschuldige mich, wenn ich die Syntax durcheinander gebracht habe; ich übersetze aus der C++-Bindung. Wenn es Fehler gibt, würde ich einen freundlichen Python-Guru bitten, sie zu korrigieren.
Abschnitt Rezensionen und Bewertungen
Sie haben die Möglichkeit, unsere Informationen aufzuwerten, indem Sie Ihre Erfahrungen in Bewertungen einbringen.