2

First off thanks for trying to help me. I found some code online that is super close to what I need it to do, but I have been unable to do the last bit. I want any number in the csv (tableView) that is negative to be displayed as red and be formatted as (x.xx) and positive numbers would be x.xx. I found some code online about changing the background of the cell, but I want to change the font and the example used abstract model, do I need to do all of this with abstract instead of standard? If I need to do it as abstract can you provide the example (I am pretty new to all of this).

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import csv
import locale

from PyQt5 import QtCore, QtGui, QtWidgets


class MyWindow(QtWidgets.QWidget):
    def __init__(self, fileName, parent=None):
        super(MyWindow, self).__init__(parent)

        locale.setlocale(locale.LC_ALL, '')

        self.fileName = fileName

        self.model = QtGui.QStandardItemModel(self)

        self.tableView = QtWidgets.QTableView(self)
        self.tableView.setModel(self.model)
        self.tableView.horizontalHeader().setStretchLastSection(True)

        self.pushButtonLoad = QtWidgets.QPushButton(self)
        self.pushButtonLoad.setText("Load Csv File!")
        self.pushButtonLoad.clicked.connect(self.on_pushButtonLoad_clicked)

        self.pushButtonWrite = QtWidgets.QPushButton(self)
        self.pushButtonWrite.setText("Write Csv File!")
        self.pushButtonWrite.clicked.connect(self.on_pushButtonWrite_clicked)

        self.layoutVertical = QtWidgets.QVBoxLayout(self)
        self.layoutVertical.addWidget(self.tableView)
        self.layoutVertical.addWidget(self.pushButtonLoad)
        self.layoutVertical.addWidget(self.pushButtonWrite)

    def loadCsv(self, fileName):
        with open(fileName, "r") as fileInput:
            # skip header
            next(fileInput)
            for row in csv.reader(fileInput):
                # convert to $x.xx and ($x.xx)
                row[-1] = float(row[-1])
                row[-1] = locale.currency(row[-1], grouping=True)

                items = [
                    QtGui.QStandardItem(field)
                    for field in row
                ]

                self.model.appendRow(items)

    def writeCsv(self, fileName):
        with open(fileName, "w", newline='') as fileOutput:
            writer = csv.writer(fileOutput)
            for rowNumber in range(self.model.rowCount()):
                fields = [
                    self.model.data(
                        self.model.index(rowNumber, columnNumber),
                        QtCore.Qt.DisplayRole
                    )
                    for columnNumber in range(self.model.columnCount())
                ]
                writer.writerow(fields)

    @QtCore.pyqtSlot()
    def on_pushButtonWrite_clicked(self):
        self.writeCsv(self.fileName)

    @QtCore.pyqtSlot()
    def on_pushButtonLoad_clicked(self):
        self.loadCsv(self.fileName)

if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    app.setApplicationName('MyWindow')

    main = MyWindow("data.csv")
    main.show()

    sys.exit(app.exec_())
Scott Ulmer
  • 139
  • 11
  • short answer: you have to subclass the data model `QStandardItemModel` and modify the `data` method to return an appropriate `qbrush` object. see: https://stackoverflow.com/a/10220126/3220135 – Aaron Oct 23 '19 at 14:53

1 Answers1

1

To change the format of how the information is displayed there are several options:

  • Override the data method of the model so that it returns the necessary value associated to the standard roles, for example in this case Qt::DisplayRole and Qt::ForegroundRole,

  • Use a proxy such as QIdentityProxyModel or alternatively a QSortFilterProxyModel by overwriting the data method as the previous method, or

  • Create a delegate to customize the painting.

In this case I will use the last method since it is more flexible since if you want to show the information of the model in several views to form differently and also that you can modify other properties not determined by the model but by other elements such as style.

Considering the above, the solution is:

class CustomDelegate(QtWidgets.QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super(CustomDelegate, self).initStyleOption(option, index)
        try:
            value = float(option.text)
        except ValueError:
            return
        option.text = "{0:.2f}".format(value)
        brush = (
            option.palette.brush(QtGui.QPalette.Text)
            if value >= 0
            else QtGui.QBrush(QtGui.QColor("red"))
        )
        option.palette.setBrush(QtGui.QPalette.Text, brush)
self.tableView = QtWidgets.QTableView(self)
# ...
delegate = CustomDelegate(self.tableView)
self.tableView.setItemDelegateForColumn(1, delegate)
eyllanesc
  • 235,170
  • 19
  • 170
  • 241