Python GTK3 TreeView实现行内容鼠标选择与复制功能
解决GTK TreeView行选择、右键复制及文本高亮自动复制问题
一、启用TreeView行选择
原代码未配置行选择模式,导致无法选中行。只需添加TreeSelection配置即可:
# 在创建treeview后添加 self.selection = self.treeview.get_selection() self.selection.set_mode(Gtk.SelectionMode.SINGLE) # 单选模式,可改为MULTIPLE支持多选
二、实现右键复制行内容功能
步骤1:创建右键菜单并绑定事件
在__init__方法中添加右键菜单及事件绑定:
# 创建右键菜单 self.popup_menu = Gtk.Menu() copy_item = Gtk.MenuItem(label="复制行内容") copy_item.connect("activate", self.on_copy_row) self.popup_menu.append(copy_item) self.popup_menu.show_all() # 绑定右键点击事件 self.treeview.connect("button-press-event", self.on_treeview_button_press)
步骤2:实现右键点击与复制逻辑
添加以下两个方法:
def on_treeview_button_press(self, widget, event): # 检测右键点击(GTK3中右键对应button=3) if event.button == 3: self.popup_menu.popup(None, None, None, None, event.button, event.time) return True return False def on_copy_row(self, widget): # 获取选中行数据 model, iter = self.selection.get_selected() if iter: # 拼接行内所有列数据(用制表符分隔) row_data = "\t".join([model[iter][0], model[iter][1], model[iter][2]]) # 复制到系统剪贴板 clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) clipboard.set_text(row_data, -1) # 显示复制提示 self.show_copy_tip("行内容已复制")
三、实现文本高亮自动复制及提示
步骤1:允许单元格文本选择
修改单元格渲染器配置,开启文本可选:
# 创建renderer时添加 renderer = Gtk.CellRendererText() renderer.set_property("selectable", True) # 允许文本选中
步骤2:监听鼠标释放事件,自动复制高亮文本
绑定button-release-event信号并实现复制逻辑:
# 在__init__中绑定信号 self.treeview.connect("button-release-event", self.on_treeview_button_release) # 添加复制方法 def on_treeview_button_release(self, widget, event): # 获取鼠标位置对应的单元格 x, y = int(event.x), int(event.y) path, column, cell_x, cell_y = self.treeview.get_path_at_pos(x, y) if path and column: # 获取单元格渲染器及选中文本范围 renderer = column.get_cells()[0] selection = renderer.get_selection() if selection: start, end = selection model = self.treeview.get_model() iter = model.get_iter(path) full_text = model[iter][column.get_sort_column_id()] selected_text = full_text[start:end] if selected_text: # 复制到剪贴板并提示 clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) clipboard.set_text(selected_text, -1) self.show_copy_tip("内容已复制")
四、实现复制提示功能
添加临时提示标签,显示3秒后自动隐藏:
# 在__init__中创建提示标签 self.copy_tip = Gtk.Label(label="") self.copy_tip.set_halign(Gtk.Align.CENTER) self.copy_tip.set_valign(Gtk.Align.TOP) self.copy_tip.set_margin_top(10) self.grid.attach(self.copy_tip, 0, 11, 5, 1) self.copy_tip.hide() # 添加提示显示与隐藏方法 def show_copy_tip(self, message): self.copy_tip.set_text(message) self.copy_tip.show() # 3秒后自动隐藏提示 Gtk.timeout_add(3000, self.hide_copy_tip) def hide_copy_tip(self): self.copy_tip.hide() return False
完整修改后的代码
import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk, Gdk # list of tuples for each variable, containing the environment variable name, its path, and the security category variable_list = [ ("$ENV1", "/usr/share/background/image.png", "Image"), ("$ENV2", "/home/user/script.py", "Program"), ("$ENV3", "/usr/share/icons/icon.png", "Image") ] class TreeViewFilterWindow(Gtk.Window): def __init__(self): super().__init__(title="Environment Variable View") self.set_border_width(10) # Setting up the self.grid in which the elements are to be positioned self.grid = Gtk.Grid() self.grid.set_column_homogeneous(True) self.grid.set_row_homogeneous(True) self.add(self.grid) # Creating the ListStore model self.variable_liststore = Gtk.ListStore(str, str, str) for variable_ref in variable_list: self.variable_liststore.append(list(variable_ref)) self.current_filter_category = None # Creating the filter, feeding it with the liststore model self.category_filter = self.variable_liststore.filter_new() # setting the filter function, note that we're not using the self.category_filter.set_visible_func(self.category_filter_func) # creating the treeview, making it use the filter as a model, and adding the columns self.treeview = Gtk.TreeView(model=self.category_filter) # 启用行选择,设置为单选模式 self.selection = self.treeview.get_selection() self.selection.set_mode(Gtk.SelectionMode.SINGLE) for i, column_title in enumerate( ["Variable", "Path", "Category"] ): renderer = Gtk.CellRendererText() # 设置单元格文本可选中 renderer.set_property("selectable", True) column = Gtk.TreeViewColumn(column_title, renderer, text=i) self.treeview.append_column(column) # 创建右键菜单 self.popup_menu = Gtk.Menu() copy_item = Gtk.MenuItem(label="复制行内容") copy_item.connect("activate", self.on_copy_row) self.popup_menu.append(copy_item) self.popup_menu.show_all() # 绑定右键点击事件 self.treeview.connect("button-press-event", self.on_treeview_button_press) # 绑定鼠标释放事件,检测文本高亮复制 self.treeview.connect("button-release-event", self.on_treeview_button_release) # 创建复制提示标签 self.copy_tip = Gtk.Label(label="") self.copy_tip.set_halign(Gtk.Align.CENTER) self.copy_tip.set_valign(Gtk.Align.TOP) self.copy_tip.set_margin_top(10) self.grid.attach(self.copy_tip, 0, 11, 5, 1) self.copy_tip.hide() # creating buttons to filter by Category, and setting up their events self.buttons = list() for var_category in ["Image", "Program"]: button = Gtk.Button(label=var_category) self.buttons.append(button) button.connect("clicked", self.on_selection_button_clicked) # setting up the layout, putting the treeview in a scrollwindow, and the buttons in a row self.scrollable_treelist = Gtk.ScrolledWindow() self.scrollable_treelist.set_vexpand(True) self.grid.attach(self.scrollable_treelist, 0, 0, 5, 10) self.grid.attach_next_to( self.buttons[0], self.scrollable_treelist, Gtk.PositionType.BOTTOM, 1, 1 ) for i, button in enumerate(self.buttons[1:]): self.grid.attach_next_to( button, self.buttons[i], Gtk.PositionType.RIGHT, 1, 1 ) self.scrollable_treelist.add(self.treeview) self.show_all() def category_filter_func(self, model, iter, data): """Tests if the Category in the row is the one in the filter""" if ( self.current_filter_category is None or self.current_filter_category == "None" ): return True else: return model[iter][2] == self.current_filter_category def on_selection_button_clicked(self, widget): """Called on any of the button clicks""" # we set the current category filter to the button's label self.current_filter_category = widget.get_label() print("%s category selected!" % self.current_filter_category) # we update the filter, which updates in turn the view self.category_filter.refilter() def on_treeview_button_press(self, widget, event): # 检测右键点击(GTK3中右键是button=3) if event.button == 3: self.popup_menu.popup(None, None, None, None, event.button, event.time) return True return False def on_copy_row(self, widget): # 获取选中行 model, iter = self.selection.get_selected() if iter: # 获取行内所有数据,用制表符分隔 row_data = "\t".join([model[iter][0], model[iter][1], model[iter][2]]) # 获取剪贴板 clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) clipboard.set_text(row_data, -1) # 显示复制提示 self.show_copy_tip("行内容已复制") def on_treeview_button_release(self, widget, event): # 获取当前鼠标位置对应的单元格 x, y = int(event.x), int(event.y) path, column, cell_x, cell_y = self.treeview.get_path_at_pos(x, y) if path and column: # 获取单元格的渲染器 renderer = column.get_cells()[0] # 获取选中的文本范围 selection = renderer.get_selection() if selection: start, end = selection model = self.treeview.get_model() iter = model.get_iter(path) full_text = model[iter][column.get_sort_column_id()] selected_text = full_text[start:end] if selected_text: clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) clipboard.set_text(selected_text, -1) self.show_copy_tip("内容已复制") def show_copy_tip(self, message): self.copy_tip.set_text(message) self.copy_tip.show() # 3秒后隐藏提示 Gtk.timeout_add(3000, self.hide_copy_tip) def hide_copy_tip(self): self.copy_tip.hide() return False win = TreeViewFilterWindow() win.connect("destroy", Gtk.main_quit) win.show_all() Gtk.main()
关键说明
- 行选择:通过
TreeSelection配置选择模式,支持单选/多选。 - 右键复制:监听右键点击事件弹出菜单,获取选中行数据后复制到剪贴板。
- 文本高亮复制:开启单元格文本可选,监听鼠标释放事件检测选中文本,自动复制并提示。
- 提示功能:用Label组件临时显示复制状态,3秒后自动隐藏,避免界面冗余。
内容的提问来源于stack exchange,提问作者Develobeer
相关产品推荐
相关产品推荐

