`Gtk.Window.set_attached_to` 真的是在 Wayland 中相对于小部件定位弹出窗口的正确方法吗?
Is `Gtk.Window.set_attached_to` really the correct way to position a popup relative to a widget in wayland?
set_attached_to
似乎是相对于 Wayland 中的小部件定位弹出窗口 window 的正确方法:
Examples of places where specifying this relation is useful are for instance [...] a completion popup window created by Gtk.Entry [...]
不幸的是,这只会产生一个错误
Gdk-Message: 12:13:16.143: Window 0x1822340 is a temporary window without parent, application will not be able to position it on screen.
试图取消注释 popup.set_parent(entry)
行只会添加警告:
(try_entry_popup.py:4539): Gtk-WARNING **: 12:17:34.185: Can't set a parent on a toplevel widget
同样的错误。
这是一个最小的例子:
#!/usr/bin/env python
# stripped down from https://gitlab.gnome.org/GNOME/gtk/issues/1541#note_396391
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
entry = Gtk.Entry()
popup = Gtk.Window(type=Gtk.WindowType.POPUP)
#popup.set_parent(entry)
popup.set_attached_to(entry)
popup.show_all()
layout = Gtk.VBox()
layout.pack_start(entry, False, True, 0)
window = Gtk.Window()
window.connect("destroy", Gtk.main_quit)
window.add(layout)
window.show_all()
Gtk.main()
从 entry completion source 看来它确实应该有效。
它是否使用私人功能?或者我错过了什么?
嗯,不是真的:gtk_window_set_attached_to 与定位无关,它对可访问性 (a11y) 和以正确的方式应用主题很重要。如果你想定位你的弹出窗口 window 你可以按照它在 https://gitlab.gnome.org/GNOME/gtk/blob/075dcc142aa525778268165095de019b736f3efa/gtk/gtkentrycompletion.c#L1597
中所做的
这是一个非常简单的实现:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
def on_button_clicked(widget):
popup = Gtk.Window(type=Gtk.WindowType.POPUP)
# optionally you may set an appropriate type hint, but it's not required.
popup.set_attached_to(entry)
popup.set_transient_for(window)
gdk_window = entry.get_window()
gdk_window_origin = gdk_window.get_origin()
x = gdk_window_origin[1]
y = gdk_window_origin[2]
allocation = entry.get_allocation()
x += allocation.x
y += allocation.y + allocation.height
popup.move(x, y)
popup.show_all()
button = Gtk.Button()
button.connect('clicked', on_button_clicked)
entry = Gtk.Entry()
layout = Gtk.VBox()
layout.pack_start(button, False, True, 0)
layout.pack_start(entry, False, True, 0)
window = Gtk.Window()
window.connect("destroy", Gtk.main_quit)
window.add(layout)
window.show_all()
Gtk.main()
set_attached_to
似乎是相对于 Wayland 中的小部件定位弹出窗口 window 的正确方法:
Examples of places where specifying this relation is useful are for instance [...] a completion popup window created by Gtk.Entry [...]
不幸的是,这只会产生一个错误
Gdk-Message: 12:13:16.143: Window 0x1822340 is a temporary window without parent, application will not be able to position it on screen.
试图取消注释 popup.set_parent(entry)
行只会添加警告:
(try_entry_popup.py:4539): Gtk-WARNING **: 12:17:34.185: Can't set a parent on a toplevel widget
同样的错误。
这是一个最小的例子:
#!/usr/bin/env python
# stripped down from https://gitlab.gnome.org/GNOME/gtk/issues/1541#note_396391
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
entry = Gtk.Entry()
popup = Gtk.Window(type=Gtk.WindowType.POPUP)
#popup.set_parent(entry)
popup.set_attached_to(entry)
popup.show_all()
layout = Gtk.VBox()
layout.pack_start(entry, False, True, 0)
window = Gtk.Window()
window.connect("destroy", Gtk.main_quit)
window.add(layout)
window.show_all()
Gtk.main()
从 entry completion source 看来它确实应该有效。 它是否使用私人功能?或者我错过了什么?
嗯,不是真的:gtk_window_set_attached_to 与定位无关,它对可访问性 (a11y) 和以正确的方式应用主题很重要。如果你想定位你的弹出窗口 window 你可以按照它在 https://gitlab.gnome.org/GNOME/gtk/blob/075dcc142aa525778268165095de019b736f3efa/gtk/gtkentrycompletion.c#L1597
中所做的这是一个非常简单的实现:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
def on_button_clicked(widget):
popup = Gtk.Window(type=Gtk.WindowType.POPUP)
# optionally you may set an appropriate type hint, but it's not required.
popup.set_attached_to(entry)
popup.set_transient_for(window)
gdk_window = entry.get_window()
gdk_window_origin = gdk_window.get_origin()
x = gdk_window_origin[1]
y = gdk_window_origin[2]
allocation = entry.get_allocation()
x += allocation.x
y += allocation.y + allocation.height
popup.move(x, y)
popup.show_all()
button = Gtk.Button()
button.connect('clicked', on_button_clicked)
entry = Gtk.Entry()
layout = Gtk.VBox()
layout.pack_start(button, False, True, 0)
layout.pack_start(entry, False, True, 0)
window = Gtk.Window()
window.connect("destroy", Gtk.main_quit)
window.add(layout)
window.show_all()
Gtk.main()