6

My question is about the way the QTableWidget displays the cell values.

I'd like for the cell to show only three decimals when it's not being edited and show the full value when you double click for editing.


I am doing calculations in background and then setting the cell value afterwards.

V_D = 3/0.7
self.TableWidget.setItem(0, 0, QTableWidgetItem(str(V_D)))

Similar to the way excel formats the cell to show certain number of digits.

Full Value:

enter image description here

Display Value:

enter image description here

How would I go about doing this?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
dre
  • 173
  • 3
  • 18

1 Answers1

10

The solution is to use a delegate and override the paint method that is responsible for showing what looks in normal state, I have built the following class based on the above.

class FloatDelegate(QItemDelegate):
    def __init__(self, decimals, parent=None):
        QItemDelegate.__init__(self, parent=parent)
        self.nDecimals = decimals

    def paint(self, painter, option, index):
        value = index.model().data(index, Qt.EditRole)
        try:
            number = float(value)
            painter.drawText(option.rect, Qt.AlignLeft, "{:.{}f}".format(number, self.nDecimals))
        except :
            QItemDelegate.paint(self, painter, option, index)

In your case you should use it as follows:

self.TableWidget.setItemDelegate(FloatDelegate(3))

Example:

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    w = QTableWidget()
    w.setColumnCount(8)
    w.setRowCount(8)
    for i in range(w.rowCount()):
        for j in range(w.columnCount()):
            number = (i+1)/(j+1)
            w.setItem(i, j, QTableWidgetItem(str(number)))
    w.setItemDelegate(FloatDelegate(3, w))
    w.show()
    sys.exit(app.exec_())

Screenshots:

enter image description here

enter image description here

Plus:

By Row o Column:

#only column 2
setItemDelegateForColumn(2, FloatDelegate(3))
#only row 2
setItemDelegateForRow(2, FloatDelegate(3))

If you want to apply only to cell 2,3

def paint(self, painter, option, index):
   if index.row() == 2 and index.column() == 3:
        value = index.model().data(index, Qt.EditRole)
        try:
            number = float(value)
            painter.drawText(option.rect, Qt.AlignLeft, "{:.{}f}".format(number, self.nDecimals))
        except :
            QItemDelegate.paint(self, painter, option, index)
    else:
        QItemDelegate.paint(self, painter, option, index)

Update:

  • QStyledItemDelegate:

    from math import log10
    
    class FloatDelegate(QStyledItemDelegate):
        def __init__(self, decimals, parent=None):
            super(FloatDelegate, self).__init__(parent=parent)
            self.nDecimals = decimals
    
        def displayText(self, value, locale):
            try:
                number = float(value)
            except ValueError:
                return super(FloatDelegate, self).displayText(value, locale)
            else:
                precision = log10(number) + 1 + self.nDecimals
                return locale.toString(number, f='f', prec=precision)
    
Jack Lilhammers
  • 1,207
  • 7
  • 19
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Cool makes sense. What if a cell is blank? It crashes the program. Also, can you .setItemDelegate on certain cells and not just the entire table? – dre Aug 09 '17 at 21:40
  • It still crashes, when I tested the code you gave, it's fine until I delete what is in the cell and then it crashes – dre Aug 09 '17 at 21:47
  • The new code you posted worked, not sure if you saw the part of my comment if you can .setItemDelegate certain cells – dre Aug 09 '17 at 21:58
  • Any cells, for example sake, lets say row 2 only – dre Aug 09 '17 at 22:02
  • Any idea why my .setTextAlignment on table cells work for some but not others? It started giving me an error after I updated the paint code, but when I deleted the code you provided, it still doesn't work for all cells. Have you had this problem? – dre Aug 10 '17 at 13:53
  • Share an mvce, and please run it and verify that functions before sharing it, it is tedious to have to correct import errors. – eyllanesc Aug 10 '17 at 13:56
  • I figured it out, I created a new QTableWidgetItem – dre Aug 10 '17 at 14:31
  • Thanks for the update eyllanesc, should there be return here just before ```super(FloatDelegate, self).displayText(value, locale)``` in the except ValueError: ? – Joseph May 01 '20 at 14:15