在GTK中通过剪贴板处理电子表格数据

3 投票
1 回答
1441 浏览
提问于 2025-04-15 17:45

我在用一个叫做 GtkSheet 的小部件来做我应用程序的电子表格,这个小部件提供了一些接口,让我可以从单元格中提取和存入数据。(我也考虑过用 GtkTreeView,但觉得太麻烦了)

我不太明白的是,如何拦截粘贴请求(比如按 CTRL+V),这样我就可以处理这些数据,而不是直接让小部件去处理。目前,从电子表格粘贴的数据显示如下:

Source 变成 Destination

我应该拦截哪个信号呢?

我现在用的是 Ubuntu 9.10,Python 2.6。

1 个回答

7

要捕捉粘贴事件,首先需要创建一个自定义的输入类(这里叫做PastableEntry),它是从gtksheet.ItemEntry继承来的。在初始化的时候,我们要连接一个叫paste-clipboard的信号,这样就能捕捉到粘贴事件了:

class PastableEntry(gtksheet.ItemEntry):
    def __init__(self):
        gtksheet.ItemEntry.__init__(self)
        self.connect('paste-clipboard', self.__on_paste)

真正的工作在事件处理器里。首先,我们需要获取剪贴板的内容。在Unix系统中,剪贴板可以支持多种数据格式。根据你的截图,我猜你是想从Gnumeric中复制数据。Gnumeric支持的格式有application/x-gnumerictext/htmlUTF8_STRINGCOMPOUND_TEXTSTRING。在这个例子中,我们将使用UTF8_STRING格式,内容大概是这样的:

1,1 <tab> 1,2 <tab> 1,3 <newline>
2,1 <tab> 2,2 <tab> 2,3 <newline>
3,1 <tab> 3,2 <tab> 3,3

显然,如果任何单元格里有制表符或换行符,这样做会出问题,但为了简单起见,我们就用这个格式。在实际应用中,你可能需要解析application/x-gnumerictext/html格式的数据。

回到我们的PastableEntry类,现在我们定义粘贴事件的处理器:

    def __on_paste(self, entry):
        clip = gtk.Clipboard()
        data = clip.wait_for_contents('UTF8_STRING')
        text = data.get_text()
        sheet = self.parent
        o_row, o_col = sheet.get_active_cell()
        for i_row, row in enumerate(text.split('\n')):
            for i_col, cell in enumerate(row.split('\t')):
                sheet.set_cell_text(o_row + i_row, o_col + i_col, cell)
        self.stop_emission('paste-clipboard')

这个应该很容易理解。我们把剪贴板的数据按行(通过换行符)分开,然后再按单元格(通过制表符)分开,最后把这些值设置到表格的单元格里。

stop_emission的作用是阻止GTK+执行默认的粘贴操作处理。如果没有这一行,选中的单元格会被原始数据覆盖。

接着,我们要把这个类注册到GObject中:

gobject.type_register(PastableEntry)

最后,要真正使用我们自定义的输入类,只需把它传给gtksheet.Sheet的构造函数就可以了:

s = gtksheet.Sheet(20, 20, "Sheet 1", entry_type=PastableEntry)

撰写回答