I wanted to be able to paste data copied from Excel into a table component on an Ignition screen, and I saw that this thread
already existed, which gave me the basics of how to do it.
I took that code and modified it so that the data is pasted into the existing dataset instead of replacing the data. It handles cases where the pasted data has too many columns or too many rows like this:
Too many columns: pop up a warningBox to say that they need to paste data with less columns.
Too many rows, but same number of columns as original table dataset: paste all the data and extend the length of table.data to fit.
Too many rows and less columns than original table dataset: pop up a confirm dialog asking if they want to truncate the rows at the bottom, or don’t paste any of the data.
The clipboard data is pasted starting at the selectedRow and selectedColumn. I couldn’t figure out how to get the row and column of the right-click event, I only see x-y coordinates.
Here is the code, which I put on the mouseReleased event handler of my table, since we are in a Windows environment.
if event.popupTrigger:
def pasteData(event):
from java.awt import Toolkit
import system
from java.awt.datatransfer import DataFlavor
#Get data from the clipboard into a string
clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
clipboardString = clipboard.getContents(None).getTransferData(DataFlavor.stringFlavor)
# print clipboardString
#Get the current data's headers
tableData = event.source.data
tableHeaders = system.dataset.getColumnHeaders(tableData)
# print tableHeaders
#Get the selected cell coordinates
selectedRow = event.source.selectedRow
selectedColumn = event.source.selectedColumn
# print selectedRow, selectedColumn
#Turn the clipboard data into a dataset with correct column headers
newClipboardData=[]
rowlist = clipboardString.split("\n")
for clipboardRow in rowlist:
if len(clipboardRow):
cells = clipboardRow.split("\t")
# print cells
newClipboardData.append(cells)
# print newClipboardData
#Figure out which column headers are needed for the new data from clipboard
clipboardDataWidth = len(newClipboardData[0])
clipboardDataHeaders = []
for header in tableHeaders:
if (tableHeaders.index(header) >= selectedColumn) and (tableHeaders.index(header) < selectedColumn + clipboardDataWidth):
clipboardDataHeaders.append(header)
# print clipboardDataHeaders
try:
newClipboardDataSet = system.dataset.toDataSet(clipboardDataHeaders,newClipboardData)
generateNewData = 1
# print newClipboardDataSet
except IndexError:
generateNewData = 0
system.gui.warningBox("The data you pasted has too many columns to fit here. Please ensure the number of cells you copied will fit in this location and try again.")
if generateNewData:
#Create two lists containing the indexes of rows and columns affected by the clipboard data.
clipboardRowList = []
clipboardColumnList = []
for row in range(newClipboardDataSet.rowCount):
clipboardRowList.append(selectedRow + row)
for col in range(newClipboardDataSet.columnCount):
clipboardColumnList.append(selectedColumn + col)
# print clipboardRowList, clipboardColumnList
#Loop through the table dataset and if you get to the correct coordinates, substitute the data from the clipboard
newTableData = []
#If the pasted data includes extra rows with all columns full, append them. Else only paste up to the existing rowCount.
if len(tableHeaders) == len(clipboardDataHeaders):
totalRows = max(newClipboardDataSet.rowCount + selectedRow, tableData.rowCount)
appendAllData = 1
else:
totalRows = tableData.rowCount
appendAllData = 0
for row in range(totalRows):
oneRow = []
for col in range(tableData.columnCount):
# print row, col
if (row in clipboardRowList) and (col in clipboardColumnList):
clipboardValue = newClipboardDataSet.getValueAt(row - selectedRow, col - selectedColumn)
oneRow.append(clipboardValue)
else:
tableValue = tableData.getValueAt(row, col)
oneRow.append(tableValue)
newTableData.append(oneRow)
#Check to see if any rows were truncated and give user an option to paste anyway.
if (appendAllData == 0) and (newClipboardDataSet.rowCount + selectedRow > tableData.rowCount):
confirmed = system.gui.confirm("%d row(s) will be cut off at the bottom of the pasted data. Paste anyway?\n\n" % (newClipboardDataSet.rowCount + selectedRow - tableData.rowCount)+\
"(To prevent this, ensure pasted data has the same number of columns as the existing data.)")
else:
confirmed = 1
if confirmed:
#Put the new dataset on the table component.
event.source.data = system.dataset.toDataSet(tableHeaders, newTableData)
menu = system.gui.createPopupMenu({"Paste Data":pasteData})
menu.show(event)