writing a QTableWidget to a .csv or .xls

Victoria Price picture Victoria Price · Sep 26, 2012 · Viewed 11.8k times · Source

Is it possible to write the contents of a QTableWidget to a csv? I found a question about writing to an .xls using xlwt, but can't seem to get it to work using my code.

def saveFile(self):
    filename = unicode(QtGui.QFileDialog.getSaveFileName(self, 'Save File', '', ".xls(*.xls)"))    
    wbk = xlwt.Workbook()
    self.sheet = wbk.add_sheet("sheet")
    self.write()
    wbk.save(filename)    


def write(self):
    for col in range (self.coordinates.columnCount()):
        for row in range(self.coordinates.rowCount()):
            text=str(self.coordinates.item(row,col).text())
            self.sheet.write(row,col,text)

I get the following error:

  File "C:\Users\Tory\Desktop\DIDSON.py", line 186, in saveFile
    self.write()
  File "C:\Users\Tory\Desktop\DIDSON.py", line 192, in write
    text=str(self.coordinates.item(row,col).text())
AttributeError: 'NoneType' object has no attribute 'text'

Why is this? self.coordinates is a QTableWidget. I was able to get the items themselves to save successfully to a worksheet, although I'd still like to save as a .csv...

Answer

ekhumoro picture ekhumoro · Sep 27, 2012

To answer the question about the AttributeError: it probably happens because there are some empty rows or columns in the table.

An empty cell has no QTableWidgetItem assigned to it, so table.item() will return None (which obviously has no 'text' attribute).

For saving the table as csv, try the example below (which can also open csv files, and hopefully deals with any potential unicode issues):

import sys, csv
from PyQt4 import QtGui, QtCore

class Window(QtGui.QWidget):
    def __init__(self, rows, columns):
        QtGui.QWidget.__init__(self)
        self.table = QtGui.QTableWidget(rows, columns, self)
        for column in range(columns - 1):
            for row in range(rows - 1):
                item = QtGui.QTableWidgetItem('Text%d' % row)
                self.table.setItem(row, column, item)
        self.buttonOpen = QtGui.QPushButton('Open', self)
        self.buttonSave = QtGui.QPushButton('Save', self)
        self.buttonOpen.clicked.connect(self.handleOpen)
        self.buttonSave.clicked.connect(self.handleSave)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.table)
        layout.addWidget(self.buttonOpen)
        layout.addWidget(self.buttonSave)

    def handleSave(self):
        path = QtGui.QFileDialog.getSaveFileName(
                self, 'Save File', '', 'CSV(*.csv)')
        if not path.isEmpty():
            with open(unicode(path), 'wb') as stream:
                writer = csv.writer(stream)
                for row in range(self.table.rowCount()):
                    rowdata = []
                    for column in range(self.table.columnCount()):
                        item = self.table.item(row, column)
                        if item is not None:
                            rowdata.append(
                                unicode(item.text()).encode('utf8'))
                        else:
                            rowdata.append('')
                    writer.writerow(rowdata)

    def handleOpen(self):
        path = QtGui.QFileDialog.getOpenFileName(
                self, 'Open File', '', 'CSV(*.csv)')
        if not path.isEmpty():
            with open(unicode(path), 'rb') as stream:
                self.table.setRowCount(0)
                self.table.setColumnCount(0)
                for rowdata in csv.reader(stream):
                    row = self.table.rowCount()
                    self.table.insertRow(row)
                    self.table.setColumnCount(len(rowdata))
                    for column, data in enumerate(rowdata):
                        item = QtGui.QTableWidgetItem(data.decode('utf8'))
                        self.table.setItem(row, column, item)

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = Window(10, 5)
    window.resize(640, 480)
    window.show()
    sys.exit(app.exec_())