我正在开发一个包含多个输入表格的程序,主要在Windows平台上使用wxPython wx.Grid。我注意到使用ctrl-c和ctrl-v复制和粘贴并不起作用,并且寻找解决方案以防止手动输入所有数字。我在这里找到了Ruben Charles的一篇旧帖子: http://comments.gmane.org/gmane.comp.python.wxpython/26387
那似乎基本达到了我想要的效果,所以我开始使用它并做了一些改进(我添加了"撤销"功能,以便处理单个单元格以及在网格表格以外粘贴时,如果最后一行或列超出范围)。
还有更好的方法吗?或者您可能有改进建议吗? 特别是:如何使其与Python 3.5兼容?
import wx
import wx.grid
class MyFrame(wx.Frame):
def __init__(self, parent, ID, title, pos=wx.DefaultPosition, size=wx.Size(800, 400), style=wx.DEFAULT_FRAME_STYLE):
wx.Frame.__init__(self, parent, ID, title, pos, size, style)
agrid = MyGrid(self, -1, wx.WANTS_CHARS)
agrid.CreateGrid(7, 7)
for count in range(3):
for count2 in range(3):
agrid.SetCellValue(count, count2, str(count + count2))
class MyGrid(wx.grid.Grid):
""" A Copy&Paste enabled grid class"""
def __init__(self, parent, id, style):
wx.grid.Grid.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, style)
wx.EVT_KEY_DOWN(self, self.OnKey)
self.data4undo = [0, 0, '']
def OnKey(self, event):
# If Ctrl+C is pressed...
if event.ControlDown() and event.GetKeyCode() == 67:
self.copy()
# If Ctrl+V is pressed...
if event.ControlDown() and event.GetKeyCode() == 86:
self.paste('clip')
# If Ctrl+Z is pressed...
if event.ControlDown() and event.GetKeyCode() == 90:
if self.data4undo[2] != '':
self.paste('undo')
# If del is pressed...
if event.GetKeyCode() == 127:
# Call delete method
self.delete()
# Skip other Key events
if event.GetKeyCode():
event.Skip()
return
def copy(self):
# Number of rows and cols
print self.GetSelectionBlockBottomRight()
print self.GetGridCursorRow()
print self.GetGridCursorCol()
if self.GetSelectionBlockTopLeft() == []:
rows = 1
cols = 1
iscell = True
else:
rows = self.GetSelectionBlockBottomRight()[0][0] - self.GetSelectionBlockTopLeft()[0][0] + 1
cols = self.GetSelectionBlockBottomRight()[0][1] - self.GetSelectionBlockTopLeft()[0][1] + 1
iscell = False
# data variable contain text that must be set in the clipboard
data = ''
# For each cell in selected range append the cell value in the data variable
# Tabs '\t' for cols and '\r' for rows
for r in range(rows):
for c in range(cols):
if iscell:
data += str(self.GetCellValue(self.GetGridCursorRow() + r, self.GetGridCursorCol() + c))
else:
data += str(self.GetCellValue(self.GetSelectionBlockTopLeft()[0][0] + r, self.GetSelectionBlockTopLeft()[0][1] + c))
if c < cols - 1:
data += '\t'
data += '\n'
# Create text data object
clipboard = wx.TextDataObject()
# Set data object value
clipboard.SetText(data)
# Put the data in the clipboard
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(clipboard)
wx.TheClipboard.Close()
else:
wx.MessageBox("Can't open the clipboard", "Error")
def paste(self, stage):
if stage == 'clip':
clipboard = wx.TextDataObject()
if wx.TheClipboard.Open():
wx.TheClipboard.GetData(clipboard)
wx.TheClipboard.Close()
else:
wx.MessageBox("Can't open the clipboard", "Error")
data = clipboard.GetText()
if self.GetSelectionBlockTopLeft() == []:
rowstart = self.GetGridCursorRow()
colstart = self.GetGridCursorCol()
else:
rowstart = self.GetSelectionBlockTopLeft()[0][0]
colstart = self.GetSelectionBlockTopLeft()[0][1]
elif stage == 'undo':
data = self.data4undo[2]
rowstart = self.data4undo[0]
colstart = self.data4undo[1]
else:
wx.MessageBox("Paste method "+stage+" does not exist", "Error")
text4undo = ''
# Convert text in a array of lines
for y, r in enumerate(data.splitlines()):
# Convert c in a array of text separated by tab
for x, c in enumerate(r.split('\t')):
if y + rowstart < self.NumberRows and x + colstart < self.NumberCols :
text4undo += str(self.GetCellValue(rowstart + y, colstart + x)) + '\t'
self.SetCellValue(rowstart + y, colstart + x, c)
text4undo = text4undo[:-1] + '\n'
if stage == 'clip':
self.data4undo = [rowstart, colstart, text4undo]
else:
self.data4undo = [0, 0, '']
def delete(self):
# print "Delete method"
# Number of rows and cols
if self.GetSelectionBlockTopLeft() == []:
rows = 1
cols = 1
else:
rows = self.GetSelectionBlockBottomRight()[0][0] - self.GetSelectionBlockTopLeft()[0][0] + 1
cols = self.GetSelectionBlockBottomRight()[0][1] - self.GetSelectionBlockTopLeft()[0][1] + 1
# Clear cells contents
for r in range(rows):
for c in range(cols):
if self.GetSelectionBlockTopLeft() == []:
self.SetCellValue(self.GetGridCursorRow() + r, self.GetGridCursorCol() + c, '')
else:
self.SetCellValue(self.GetSelectionBlockTopLeft()[0][0] + r, self.GetSelectionBlockTopLeft()[0][1] + c, '')
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, "Copy and paste enabled only for a single range")
frame.Show(True)
self.SetTopWindow(frame)
return True
def main():
app = MyApp()
app.MainLoop()
if __name__ == '__main__':
main()
OnKey
中的多个if
语句修改为调用其他函数的字典,并在我的paste
定义下将粘贴和撤销分别拆分为不同的情况。 - Kyrubas