剪切、复制、粘贴、Select 所有功能 - 如何在单击菜单项后简单地允许默认处理?
Cut, Copy, Paste, Select All Functions - How to simply allow default handling after clicking on menu item?
默认情况下,"Ctrl+C" 和 "Ctrl+V" 快捷方式(以及 "right click menu")在任何 GTK 应用程序中都可用,例如只有一个 SourceView (见下文)。
但是如果我添加一个菜单项 "Edit->Copy" 并为其分配 "Ctrl+C" 加速器和相应的回调函数,那么它显然会停止工作,因为我正在用我自己的方法拦截信号。那么,如何在我的自定义方法中触发默认的 cut/copy/paste/select_all 功能?
注意:返回 False
适用于粘贴功能,但不适用于 Copy/Cut/Select 全部
简单示例 - 在这种情况下,所有功能(cut/copy/paste/select 全部)都可以正常工作。
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '3.0')
from gi.repository import Gtk, Gdk, Pango, GObject, GtkSource
class MyOwnApp(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.set_default_size(500, 500)
self.vbox = Gtk.VBox()
editor = GtkSource.View.new()
editor.set_show_line_numbers(True)
editor.set_auto_indent(True)
editor_buffer = editor.get_buffer()
self.vbox.pack_start(editor, False, False, 0)
self.add(self.vbox)
win = MyOwnApp()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
如果我添加带有回调的菜单项,它们将不再起作用。
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '3.0')
from gi.repository import Gtk, Gdk, Pango, GObject, GtkSource
class MyOwnApp(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.set_default_size(900, 900)
box_outer = Gtk.VBox()
# MENUBAR setup
menuBar = Gtk.MenuBar()
# Set accelerators
agr = Gtk.AccelGroup()
self.add_accel_group(agr)
# File menu
file_menu_dropdown = Gtk.MenuItem("File")
menuBar.append(file_menu_dropdown)
file_menu = Gtk.Menu()
file_menu_dropdown.set_submenu(file_menu)
# File menu Items
file_exit = Gtk.MenuItem("Exit")
key, mod = Gtk.accelerator_parse("<Control>Q")
file_exit.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
file_exit.connect("activate", self.quit)
file_menu.append(file_exit)
# Edit menu
edit_menu_dropdown = Gtk.MenuItem("Edit")
menuBar.append(edit_menu_dropdown)
edit_menu = Gtk.Menu()
edit_menu_dropdown.set_submenu(edit_menu)
# Edit menu Items
edit_cut = Gtk.MenuItem("Cut")
key, mod = Gtk.accelerator_parse("<Control>X")
edit_cut.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_cut.connect("activate", self.on_toolbutton_cut_clicked)
edit_copy = Gtk.MenuItem("Copy")
key, mod = Gtk.accelerator_parse("<Control>C")
edit_copy.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_copy.connect("activate", self.on_toolbutton_copy_clicked)
edit_paste = Gtk.MenuItem("Paste")
key, mod = Gtk.accelerator_parse("<Control>V")
edit_paste.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_paste.connect("activate", self.on_toolbutton_paste_clicked)
edit_select_all = Gtk.MenuItem("Select All")
key, mod = Gtk.accelerator_parse("<Control>A")
edit_select_all.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_select_all.connect("activate", self.on_toolbutton_select_all_clicked)
edit_menu.append(edit_select_all)
edit_menu.append(edit_cut)
edit_menu.append(edit_copy)
edit_menu.append(edit_paste)
box_outer.pack_start(menuBar, False, False, 0)
# SourceView
editor = GtkSource.View.new()
editor.set_show_line_numbers(True)
editor.set_auto_indent(True)
editor_buffer = editor.get_buffer()
box_outer.pack_start(editor, True, True, 0)
self.add(box_outer)
def quit(self,widget=None):
Gtk.main_quit()
def on_toolbutton_select_all_clicked(self, widget):
return False
def on_toolbutton_cut_clicked(self, widget):
return False
def on_toolbutton_copy_clicked(self, widget):
return False
def on_toolbutton_paste_clicked(self, widget):
return False
win = MyOwnApp()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
。在 editor_buffer(GtkSourceBuffer) 中调用特定于操作的函数,模拟默认处理 (cut/copy/paste/select all).
def on_toolbutton_select_all_clicked(self, widget):
print("Select all")
if self.editor.is_focus():
self.editor_buffer.select_range(self.editor_buffer.get_start_iter(), self.editor_buffer.get_end_iter())
else:
self.entry.select_region(0,-1)
return True
def on_toolbutton_cut_clicked(self, widget):
print("Cut")
if self.editor.is_focus():
self.editor_buffer.cut_clipboard(self.clipboard,self.editor_buffer)
else:
self.entry.emit("cut-clipboard")
return True
def on_toolbutton_copy_clicked(self, widget):
if self.editor.is_focus():
self.editor_buffer.copy_clipboard(self.clipboard)
else:
self.entry.emit("copy-clipboard")
return True
def on_toolbutton_paste_clicked(self, widget):
if self.editor.is_focus():
self.editor_buffer.paste_clipboard(self.clipboard, None, self.editor_buffer)
else:
self.entry.emit("paste-clipboard")
return True
有关详细信息,您可以查看此 (https://developer.gnome.org/pygtk/stable/class-gtktextbuffer.html)。对于其他发出信号的小部件,此实现也适用于 SourceView。
经过数小时的研究,我很高兴 post 为所有 GTK 爱好者提供此解决方案!
感谢@SivaGuru 的贡献!!
使用此解决方案,您可以在 window(Gtk.Entry
和 GtkSource.View
)中跨多个小部件使用 cut/copy/paste/selectAll 函数。
关键是这两个小部件对 cut/copy/paste/selectAll 功能使用不同的方法,但是 (正如预期的那样)它们都有默认方法来管理这些基本功能。无需重新发明轮子。
注意:Gtk.Entry
小部件继承自 Gtk.Editable
接口,它具有回退到 cut/copy/past/selectAll 默认处理的所有必要功能。
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '3.0')
from gi.repository import Gtk, Gdk, GtkSource
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.set_default_size(900, 900)
box_outer = Gtk.VBox()
# MENUBAR setup
menuBar = Gtk.MenuBar()
# Set accelerators
agr = Gtk.AccelGroup()
self.add_accel_group(agr)
# File menu
file_menu_dropdown = Gtk.MenuItem("File")
menuBar.append(file_menu_dropdown)
file_menu = Gtk.Menu()
file_menu_dropdown.set_submenu(file_menu)
#File menu Items
file_exit = Gtk.MenuItem("Exit")
key, mod = Gtk.accelerator_parse("<Control>Q")
file_exit.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
file_exit.connect("activate", self.quit)
file_menu.append(file_exit)
# Edit menu
edit_menu_dropdown = Gtk.MenuItem("Edit")
menuBar.append(edit_menu_dropdown)
edit_menu = Gtk.Menu()
edit_menu_dropdown.set_submenu(edit_menu)
# Edit menu Items
edit_cut = Gtk.MenuItem("Cut")
key, mod = Gtk.accelerator_parse("<Control>X")
edit_cut.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_cut.connect("activate", self.on_toolbutton_cut_clicked)
edit_copy = Gtk.MenuItem("Copy")
key, mod = Gtk.accelerator_parse("<Control>C")
edit_copy.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_copy.connect("activate", self.on_toolbutton_copy_clicked)
edit_paste = Gtk.MenuItem("Paste")
key, mod = Gtk.accelerator_parse("<Control>V")
edit_paste.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_paste.connect("activate", self.on_toolbutton_paste_clicked)
edit_select_all = Gtk.MenuItem("Select All")
key, mod = Gtk.accelerator_parse("<Control>A")
edit_select_all.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_select_all.connect("activate", self.on_toolbutton_select_all_clicked)
edit_menu.append(edit_select_all)
edit_menu.append(edit_cut)
edit_menu.append(edit_copy)
edit_menu.append(edit_paste)
box_outer.pack_start(menuBar, False, False, 0)
entry = Gtk.Entry()
box_outer.pack_start(entry, False, False, 0)
editor = GtkSource.View.new()
editor.set_show_line_numbers(True)
editor.set_auto_indent(True)
box_outer.pack_start(editor, True, True, 0)
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
self.add(box_outer)
def quit(self,widget=None):
Gtk.main_quit()
def on_toolbutton_select_all_clicked(self, widget):
focusedWidget = self.get_focus()
if focusedWidget is not None:
if focusedWidget.has_focus():
if str(type(focusedWidget)) == "<class 'gi.repository.Gtk.Entry'>":
focusedWidget.select_region(0, -1)
elif str(type(focusedWidget)) == "<class 'gi.repository.GtkSource.View'>":
editor_buffer = focusedWidget.get_buffer()
editor_buffer.select_range(editor_buffer.get_start_iter(), editor_buffer.get_end_iter())
else:
pass
def on_toolbutton_cut_clicked(self, widget):
focusedWidget = self.get_focus()
if focusedWidget is not None:
if focusedWidget.has_focus():
if str(type(focusedWidget)) == "<class 'gi.repository.Gtk.Entry'>":
focusedWidget.cut_clipboard()
elif str(type(focusedWidget)) == "<class 'gi.repository.GtkSource.View'>":
editor_buffer = focusedWidget.get_buffer()
editor_buffer.cut_clipboard(self.clipboard, editor_buffer)
else:
pass
def on_toolbutton_copy_clicked(self, widget):
focusedWidget = self.get_focus()
if focusedWidget is not None:
if focusedWidget.has_focus():
if str(type(focusedWidget)) == "<class 'gi.repository.Gtk.Entry'>":
focusedWidget.copy_clipboard()
elif str(type(focusedWidget)) == "<class 'gi.repository.GtkSource.View'>":
editor_buffer = focusedWidget.get_buffer()
editor_buffer.copy_clipboard(self.clipboard)
else:
pass
def on_toolbutton_paste_clicked(self, widget):
focusedWidget = self.get_focus()
if focusedWidget is not None:
if focusedWidget.has_focus():
if str(type(focusedWidget)) == "<class 'gi.repository.Gtk.Entry'>":
focusedWidget.paste_clipboard()
elif str(type(focusedWidget)) == "<class 'gi.repository.GtkSource.View'>":
editor_buffer = focusedWidget.get_buffer()
editor_buffer.paste_clipboard(self.clipboard, None, editor_buffer)
else:
pass
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
默认情况下,"Ctrl+C" 和 "Ctrl+V" 快捷方式(以及 "right click menu")在任何 GTK 应用程序中都可用,例如只有一个 SourceView (见下文)。 但是如果我添加一个菜单项 "Edit->Copy" 并为其分配 "Ctrl+C" 加速器和相应的回调函数,那么它显然会停止工作,因为我正在用我自己的方法拦截信号。那么,如何在我的自定义方法中触发默认的 cut/copy/paste/select_all 功能?
注意:返回 False
适用于粘贴功能,但不适用于 Copy/Cut/Select 全部
简单示例 - 在这种情况下,所有功能(cut/copy/paste/select 全部)都可以正常工作。
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '3.0')
from gi.repository import Gtk, Gdk, Pango, GObject, GtkSource
class MyOwnApp(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.set_default_size(500, 500)
self.vbox = Gtk.VBox()
editor = GtkSource.View.new()
editor.set_show_line_numbers(True)
editor.set_auto_indent(True)
editor_buffer = editor.get_buffer()
self.vbox.pack_start(editor, False, False, 0)
self.add(self.vbox)
win = MyOwnApp()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
如果我添加带有回调的菜单项,它们将不再起作用。
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '3.0')
from gi.repository import Gtk, Gdk, Pango, GObject, GtkSource
class MyOwnApp(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.set_default_size(900, 900)
box_outer = Gtk.VBox()
# MENUBAR setup
menuBar = Gtk.MenuBar()
# Set accelerators
agr = Gtk.AccelGroup()
self.add_accel_group(agr)
# File menu
file_menu_dropdown = Gtk.MenuItem("File")
menuBar.append(file_menu_dropdown)
file_menu = Gtk.Menu()
file_menu_dropdown.set_submenu(file_menu)
# File menu Items
file_exit = Gtk.MenuItem("Exit")
key, mod = Gtk.accelerator_parse("<Control>Q")
file_exit.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
file_exit.connect("activate", self.quit)
file_menu.append(file_exit)
# Edit menu
edit_menu_dropdown = Gtk.MenuItem("Edit")
menuBar.append(edit_menu_dropdown)
edit_menu = Gtk.Menu()
edit_menu_dropdown.set_submenu(edit_menu)
# Edit menu Items
edit_cut = Gtk.MenuItem("Cut")
key, mod = Gtk.accelerator_parse("<Control>X")
edit_cut.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_cut.connect("activate", self.on_toolbutton_cut_clicked)
edit_copy = Gtk.MenuItem("Copy")
key, mod = Gtk.accelerator_parse("<Control>C")
edit_copy.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_copy.connect("activate", self.on_toolbutton_copy_clicked)
edit_paste = Gtk.MenuItem("Paste")
key, mod = Gtk.accelerator_parse("<Control>V")
edit_paste.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_paste.connect("activate", self.on_toolbutton_paste_clicked)
edit_select_all = Gtk.MenuItem("Select All")
key, mod = Gtk.accelerator_parse("<Control>A")
edit_select_all.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_select_all.connect("activate", self.on_toolbutton_select_all_clicked)
edit_menu.append(edit_select_all)
edit_menu.append(edit_cut)
edit_menu.append(edit_copy)
edit_menu.append(edit_paste)
box_outer.pack_start(menuBar, False, False, 0)
# SourceView
editor = GtkSource.View.new()
editor.set_show_line_numbers(True)
editor.set_auto_indent(True)
editor_buffer = editor.get_buffer()
box_outer.pack_start(editor, True, True, 0)
self.add(box_outer)
def quit(self,widget=None):
Gtk.main_quit()
def on_toolbutton_select_all_clicked(self, widget):
return False
def on_toolbutton_cut_clicked(self, widget):
return False
def on_toolbutton_copy_clicked(self, widget):
return False
def on_toolbutton_paste_clicked(self, widget):
return False
win = MyOwnApp()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
。在 editor_buffer(GtkSourceBuffer) 中调用特定于操作的函数,模拟默认处理 (cut/copy/paste/select all).
def on_toolbutton_select_all_clicked(self, widget):
print("Select all")
if self.editor.is_focus():
self.editor_buffer.select_range(self.editor_buffer.get_start_iter(), self.editor_buffer.get_end_iter())
else:
self.entry.select_region(0,-1)
return True
def on_toolbutton_cut_clicked(self, widget):
print("Cut")
if self.editor.is_focus():
self.editor_buffer.cut_clipboard(self.clipboard,self.editor_buffer)
else:
self.entry.emit("cut-clipboard")
return True
def on_toolbutton_copy_clicked(self, widget):
if self.editor.is_focus():
self.editor_buffer.copy_clipboard(self.clipboard)
else:
self.entry.emit("copy-clipboard")
return True
def on_toolbutton_paste_clicked(self, widget):
if self.editor.is_focus():
self.editor_buffer.paste_clipboard(self.clipboard, None, self.editor_buffer)
else:
self.entry.emit("paste-clipboard")
return True
有关详细信息,您可以查看此 (https://developer.gnome.org/pygtk/stable/class-gtktextbuffer.html)。对于其他发出信号的小部件,此实现也适用于 SourceView。
经过数小时的研究,我很高兴 post 为所有 GTK 爱好者提供此解决方案!
感谢@SivaGuru 的贡献!!
使用此解决方案,您可以在 window(Gtk.Entry
和 GtkSource.View
)中跨多个小部件使用 cut/copy/paste/selectAll 函数。
关键是这两个小部件对 cut/copy/paste/selectAll 功能使用不同的方法,但是 (正如预期的那样)它们都有默认方法来管理这些基本功能。无需重新发明轮子。
注意:Gtk.Entry
小部件继承自 Gtk.Editable
接口,它具有回退到 cut/copy/past/selectAll 默认处理的所有必要功能。
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '3.0')
from gi.repository import Gtk, Gdk, GtkSource
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.set_default_size(900, 900)
box_outer = Gtk.VBox()
# MENUBAR setup
menuBar = Gtk.MenuBar()
# Set accelerators
agr = Gtk.AccelGroup()
self.add_accel_group(agr)
# File menu
file_menu_dropdown = Gtk.MenuItem("File")
menuBar.append(file_menu_dropdown)
file_menu = Gtk.Menu()
file_menu_dropdown.set_submenu(file_menu)
#File menu Items
file_exit = Gtk.MenuItem("Exit")
key, mod = Gtk.accelerator_parse("<Control>Q")
file_exit.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
file_exit.connect("activate", self.quit)
file_menu.append(file_exit)
# Edit menu
edit_menu_dropdown = Gtk.MenuItem("Edit")
menuBar.append(edit_menu_dropdown)
edit_menu = Gtk.Menu()
edit_menu_dropdown.set_submenu(edit_menu)
# Edit menu Items
edit_cut = Gtk.MenuItem("Cut")
key, mod = Gtk.accelerator_parse("<Control>X")
edit_cut.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_cut.connect("activate", self.on_toolbutton_cut_clicked)
edit_copy = Gtk.MenuItem("Copy")
key, mod = Gtk.accelerator_parse("<Control>C")
edit_copy.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_copy.connect("activate", self.on_toolbutton_copy_clicked)
edit_paste = Gtk.MenuItem("Paste")
key, mod = Gtk.accelerator_parse("<Control>V")
edit_paste.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_paste.connect("activate", self.on_toolbutton_paste_clicked)
edit_select_all = Gtk.MenuItem("Select All")
key, mod = Gtk.accelerator_parse("<Control>A")
edit_select_all.add_accelerator("activate", agr, key, mod, Gtk.AccelFlags.VISIBLE)
edit_select_all.connect("activate", self.on_toolbutton_select_all_clicked)
edit_menu.append(edit_select_all)
edit_menu.append(edit_cut)
edit_menu.append(edit_copy)
edit_menu.append(edit_paste)
box_outer.pack_start(menuBar, False, False, 0)
entry = Gtk.Entry()
box_outer.pack_start(entry, False, False, 0)
editor = GtkSource.View.new()
editor.set_show_line_numbers(True)
editor.set_auto_indent(True)
box_outer.pack_start(editor, True, True, 0)
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
self.add(box_outer)
def quit(self,widget=None):
Gtk.main_quit()
def on_toolbutton_select_all_clicked(self, widget):
focusedWidget = self.get_focus()
if focusedWidget is not None:
if focusedWidget.has_focus():
if str(type(focusedWidget)) == "<class 'gi.repository.Gtk.Entry'>":
focusedWidget.select_region(0, -1)
elif str(type(focusedWidget)) == "<class 'gi.repository.GtkSource.View'>":
editor_buffer = focusedWidget.get_buffer()
editor_buffer.select_range(editor_buffer.get_start_iter(), editor_buffer.get_end_iter())
else:
pass
def on_toolbutton_cut_clicked(self, widget):
focusedWidget = self.get_focus()
if focusedWidget is not None:
if focusedWidget.has_focus():
if str(type(focusedWidget)) == "<class 'gi.repository.Gtk.Entry'>":
focusedWidget.cut_clipboard()
elif str(type(focusedWidget)) == "<class 'gi.repository.GtkSource.View'>":
editor_buffer = focusedWidget.get_buffer()
editor_buffer.cut_clipboard(self.clipboard, editor_buffer)
else:
pass
def on_toolbutton_copy_clicked(self, widget):
focusedWidget = self.get_focus()
if focusedWidget is not None:
if focusedWidget.has_focus():
if str(type(focusedWidget)) == "<class 'gi.repository.Gtk.Entry'>":
focusedWidget.copy_clipboard()
elif str(type(focusedWidget)) == "<class 'gi.repository.GtkSource.View'>":
editor_buffer = focusedWidget.get_buffer()
editor_buffer.copy_clipboard(self.clipboard)
else:
pass
def on_toolbutton_paste_clicked(self, widget):
focusedWidget = self.get_focus()
if focusedWidget is not None:
if focusedWidget.has_focus():
if str(type(focusedWidget)) == "<class 'gi.repository.Gtk.Entry'>":
focusedWidget.paste_clipboard()
elif str(type(focusedWidget)) == "<class 'gi.repository.GtkSource.View'>":
editor_buffer = focusedWidget.get_buffer()
editor_buffer.paste_clipboard(self.clipboard, None, editor_buffer)
else:
pass
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()