Tôi đang làm việc trên một chương trình với một số bảng đầu vào mà tôi đang sử dụng wxPython wx.Grid (chủ yếu cho Windows). Tôi nhận thấy rằng ctrl-c và ctrl-v để sao chép và dán hé doe chỉ đơn giản là làm việc và tôi tìm kiếm các giải pháp để ngăn chặn phải gõ vào tất cả các số trong các bảng bằng tay. Tôi tìm thấy một bài đăng cũ của Ruben Charles ở đây: http://comments.gmane.org/gmane.comp.python.wxpython/26387Làm việc với ctrl-c và ctrl-v để sao chép và dán vào một wx.Grid trong wxPython
Điều đó dường như làm nhiều hơn hoặc ít hơn những gì tôi muốn, vì vậy tôi bắt đầu làm việc với điều đó và thực hiện một số điều mà tôi hy vọng là những cải tiến. (Tôi đã thêm chức năng 'hoàn tác' với ctrl-Z, để làm việc với các ô đơn lẻ và để dán nếu hàng hoặc cột cuối cùng nằm ngoài bảng lưới.)
Có cách nào tốt hơn để làm điều này, hoặc có thể bạn có lời khuyên để cải tiến? Đặc biệt: Làm thế nào để thực hiện công việc này với 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()
Hoàn hảo cho mục đích của tôi. Điều duy nhất tôi đã làm là sửa đổi câu lệnh multi-'if' trong 'OnKey' thành một từ điển gọi các hàm khác và tách phần dán và hoàn tác thành các trường hợp riêng biệt theo định nghĩa' paste' của tôi. – Kyrubas
Cảm ơn mẹo Kyrubas! Tôi chưa bao giờ nghĩ đến việc sử dụng từ điển theo cách đó. – ROB
Cảm ơn @ROB! Điều này rất hay và hữu ích. Cảm ơn đã giúp đỡ. – Deathkill14