Vala中向Gtk.Clipboard插入URI:粘贴重复调用get_func问题
解决Gtk.Clipboard粘贴时重复调用get_func覆盖数据的问题
你踩了Gtk.Clipboard.set_with_owner的一个常见坑——这个方法的get_func是按需提供数据的,而非一次性把数据写入剪贴板存储。也就是说,每次有程序请求剪贴板内容(比如按Ctrl+V),系统都会调用你的get_func来获取数据,而你原来的代码里每次都实时调用w.get_selected_file(),这就导致粘贴时拿到的是当前选中的文件,而非复制时选中的那个。
核心问题分析
你的get_func依赖的是窗口的实时选中状态,而不是复制时刻的状态。剪贴板本身不会保存你的数据,它只是在需要的时候向你索要,所以必须在复制操作发生时,把要复制的URI保存下来,后续get_func直接复用这个预存的数据即可。
修正后的实现步骤
- 先在你的Window类里添加一个成员变量,用来保存复制时刻的URI:
private string[]? copied_uris = null;
- 修改Ctrl+C的处理逻辑,复制时先保存当前选中的文件URI,再设置剪贴板:
// 处理Ctrl+C复制操作 copied_uris = { this.get_selected_file().get_uri() }; // 保存复制时刻的URI // 定义剪贴板目标 var clipboard_targets = [ new Gtk.TargetEntry("text/uri-list", 0, (int)ClipboardProtocol.TEXT_URI_LIST) ]; clipboard.set_with_owner( clipboard_targets, // get_func:当剪贴板需要数据时调用 (clipboard, selection_data, info, user_data_or_owner) => { print("clipboard get_func called\n"); if (copied_uris == null) return; switch (info) { case (int)ClipboardProtocol.TEXT_URI_LIST: print("Providing saved URIs: "); foreach (var uri in copied_uris) { print(uri + "\n"); } selection_data.set_uris(copied_uris); break; } }, // owner_destroy_func:当剪贴板失去所有权时调用(可选) (clipboard, user_data_or_owner) => { // 清空保存的URI,避免无效数据残留 copied_uris = null; }, this // 将当前Window作为owner传递 );
- 粘贴逻辑可以保持不变,加个空值判断会更健壮:
// 处理Ctrl+V粘贴操作 print("\nCTRL V pressed\n"); clipboard.request_uris((clipboard, uris) => { if (uris == null) { print("No URIs available in clipboard\n"); return; } foreach (string content in uris) { print("Try Pasting: "); print(content); print("\n"); } });
为什么这样能解决问题
现在get_func使用的是复制时刻保存的copied_uris,而非实时获取当前选中的文件。无论什么时候调用get_func(比如粘贴),都会返回你复制时的那个URI,不会被后续的选中状态改变覆盖。
另外,owner_destroy_func会在剪贴板失去所有权时(比如其他程序复制了内容)清空copied_uris,避免保存无效的旧数据。
内容的提问来源于stack exchange,提问作者Marcel
相关产品推荐
相关产品推荐

