Gtk.TreeView 按键事件的奇怪行为
Strange behaviour for Gtk.TreeView keypress events
我有一个 Gtk.Treeview
显示带有项目的行。我想要 select 带有按钮 1 的行(默认行为),并且在单击按钮 3(右)时,应该会出现一个上下文菜单。这是我得到的结果:
1 - 使用 connect
连接到 button-press-event
,工作正常,但是,由于在默认(树视图)处理程序之前调用此处理程序,行 selection 是尚未更改,阅读 selected 行会给出先前 selected 行。
2 - 使用 connect-after
连接到 button-press-event
。但是现在 my 处理程序不再被调用......就好像内部处理程序以 return True
退出一样。奇怪的是,双击 确实调用了我的处理程序。
如何让 button-3 先更改 selection,然后调用我的处理程序?
这是该程序的简短版本,取消注释标记行之一以测试 1 或 2。
顺便说一句:我想也许 set_activate_on_single_click
可能会有所帮助 - 运气不好。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# test_keypress.py
#
# Copyright 2021 John Coppens <john@jcoppens.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GooCanvas', '2.0')
from gi.repository import Gtk, GooCanvas
class MainWindow(Gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.connect("destroy", lambda x: Gtk.main_quit())
self.set_default_size(400, 300)
store = Gtk.ListStore(str)
view = Gtk.TreeView(model = store)
view.connect('button-press-event', self.on_button_pressed) # Select one of these
# view.connect_after('button-press-event', self.on_button_pressed) # ....
renderer = Gtk.CellRendererText()
col = Gtk.TreeViewColumn('Column', renderer, text = 0)
view.append_column(col)
store.append(('Alpha', ))
store.append(('Beta', ))
store.append(('Gamma', ))
scroller = Gtk.ScrolledWindow()
scroller.add(view)
self.add(scroller)
self.show_all()
def on_button_pressed(self, view, event):
sel = view.get_selection()
store, selected = sel.get_selected()
item = store[selected]
print(event.button, item[0])
def run(self):
Gtk.main()
def main(args):
mainwdw = MainWindow()
mainwdw.run()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
你需要使用button-release-event
事件,这样Gtk才能处理第一个事件。示例:
view.connect('button-release-event', self.on_button_pressed)
谢谢 @theGtknerd
- 我注意到这个方法被用在几个程序中,但不知何故感觉并不完全正确。我喜欢事情在我采取行动时发生,而不是在我完成它时发生。
总之,感谢IRC上@Company
的建议,我这样解决了这个问题(而且代码长度差不多):
- 使用
button-press-event
中的 x, y
坐标可以轻松识别 Gtk.TreeView
中的正确行。处理事件后,我让默认处理程序更改选择。代码类似于:
def on_button_pressed(self, view, event):
path, _, _, _ = view.get_path_at_pos(int(event.x), int(event.y))
if path:
item = self.store[self.store.get_iter(path)]
print(event.button, item[0])
(不确定 int()
是否必要,但 get_path_at_pos
指定了 int
个参数。
_
是虚拟变量,因为 get_path_at_pos
returns 一个 4 元组,我只需要第一个元素。
我有一个 Gtk.Treeview
显示带有项目的行。我想要 select 带有按钮 1 的行(默认行为),并且在单击按钮 3(右)时,应该会出现一个上下文菜单。这是我得到的结果:
1 - 使用 connect
连接到 button-press-event
,工作正常,但是,由于在默认(树视图)处理程序之前调用此处理程序,行 selection 是尚未更改,阅读 selected 行会给出先前 selected 行。
2 - 使用 connect-after
连接到 button-press-event
。但是现在 my 处理程序不再被调用......就好像内部处理程序以 return True
退出一样。奇怪的是,双击 确实调用了我的处理程序。
如何让 button-3 先更改 selection,然后调用我的处理程序?
这是该程序的简短版本,取消注释标记行之一以测试 1 或 2。
顺便说一句:我想也许 set_activate_on_single_click
可能会有所帮助 - 运气不好。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# test_keypress.py
#
# Copyright 2021 John Coppens <john@jcoppens.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GooCanvas', '2.0')
from gi.repository import Gtk, GooCanvas
class MainWindow(Gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.connect("destroy", lambda x: Gtk.main_quit())
self.set_default_size(400, 300)
store = Gtk.ListStore(str)
view = Gtk.TreeView(model = store)
view.connect('button-press-event', self.on_button_pressed) # Select one of these
# view.connect_after('button-press-event', self.on_button_pressed) # ....
renderer = Gtk.CellRendererText()
col = Gtk.TreeViewColumn('Column', renderer, text = 0)
view.append_column(col)
store.append(('Alpha', ))
store.append(('Beta', ))
store.append(('Gamma', ))
scroller = Gtk.ScrolledWindow()
scroller.add(view)
self.add(scroller)
self.show_all()
def on_button_pressed(self, view, event):
sel = view.get_selection()
store, selected = sel.get_selected()
item = store[selected]
print(event.button, item[0])
def run(self):
Gtk.main()
def main(args):
mainwdw = MainWindow()
mainwdw.run()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
你需要使用button-release-event
事件,这样Gtk才能处理第一个事件。示例:
view.connect('button-release-event', self.on_button_pressed)
谢谢 @theGtknerd
- 我注意到这个方法被用在几个程序中,但不知何故感觉并不完全正确。我喜欢事情在我采取行动时发生,而不是在我完成它时发生。
总之,感谢IRC上@Company
的建议,我这样解决了这个问题(而且代码长度差不多):
- 使用
button-press-event
中的x, y
坐标可以轻松识别Gtk.TreeView
中的正确行。处理事件后,我让默认处理程序更改选择。代码类似于:
def on_button_pressed(self, view, event):
path, _, _, _ = view.get_path_at_pos(int(event.x), int(event.y))
if path:
item = self.store[self.store.get_iter(path)]
print(event.button, item[0])
(不确定 int()
是否必要,但 get_path_at_pos
指定了 int
个参数。
_
是虚拟变量,因为 get_path_at_pos
returns 一个 4 元组,我只需要第一个元素。