在GTK中通过剪贴板处理电子表格数据
我在用一个叫做 GtkSheet
的小部件来做我应用程序的电子表格,这个小部件提供了一些接口,让我可以从单元格中提取和存入数据。(我也考虑过用 GtkTreeView,但觉得太麻烦了)
我不太明白的是,如何拦截粘贴请求(比如按 CTRL+V),这样我就可以处理这些数据,而不是直接让小部件去处理。目前,从电子表格粘贴的数据显示如下:
我应该拦截哪个信号呢?
我现在用的是 Ubuntu 9.10,Python 2.6。
1 个回答
要捕捉粘贴事件,首先需要创建一个自定义的输入类(这里叫做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-gnumeric
、text/html
、UTF8_STRING
、COMPOUND_TEXT
和STRING
。在这个例子中,我们将使用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-gnumeric
或text/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)