[Python] QtableView column sorting with floats formatted as strings

Discussão em 'Python' iniciado por Stack, Abril 22, 2025.

  1. Stack

    Stack Membro Participativo

    I need to use a custom QtableView in Python to display and format data.

    The example app below shows a table with the first column of floats formatted as strings to get the proper number of decimals, the second column of floats displayed without formatting, and the third column contains strings.

    When clicking on columns, I want to sort my data. This works fine for strings and floats (columns #2 and #3), but not for column #1 with formatted floats as strings where it's sorted alphabetically rather than numerically.

    I've been googling for a while without finding a way to have something working with QtableView.

    Any clue on how to get both floats sorting and decimal formatting?

    Thanks & cheers

    Stephane

    import sys
    from PyQt5 import QtCore, QtWidgets
    from PyQt5.QtCore import *

    # Table model
    class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
    super(TableModel, self).__init__()
    self._data = data
    # Set columns headers
    self.horizontalHeaders = [''] * 3
    self.setHeaderData(0, Qt.Horizontal, "Col #1\nfloats as string")
    self.setHeaderData(1, Qt.Horizontal, "Col #2\nfloats")
    self.setHeaderData(2, Qt.Horizontal, "Col #3\nstrings")

    def data(self, index, role):
    value = self._data[index.row()][index.column()]
    if role == Qt.DisplayRole:
    # convert col #1 from floats to string to get proper number of decimal formatting
    if index.column() == 0:
    return '%.4f' % value
    # otherwise display floats or strings for col #2 and #3
    else:
    return value

    # Align values right
    if role == Qt.TextAlignmentRole:
    return Qt.AlignVCenter + Qt.AlignRight

    def rowCount(self, index):
    # The length of the outer list.
    return len(self._data)

    def columnCount(self, index):
    # The following takes the first sub-list, and returns
    # the length (only works if all rows are an equal length)
    return len(self._data[0])

    def setHeaderData(self, section, orientation, data, role=Qt.EditRole):
    if orientation == Qt.Horizontal and role in (Qt.DisplayRole, Qt.EditRole):
    try:
    self.horizontalHeaders[section] = data
    return True
    except:
    return False
    return super().setHeaderData(section, orientation, data, role)

    def headerData(self, section, orientation, role=Qt.DisplayRole):
    if orientation == Qt.Horizontal and role == Qt.DisplayRole:
    try:
    return self.horizontalHeaders[section]
    except:
    pass
    return super().headerData(section, orientation, role)


    class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
    super().__init__()
    # Create a TableView (not a TableWidget !!!)
    self.table = QtWidgets.QTableView()

    # sample data
    data = [
    [4.2, 9.6, 1],
    [42.1, 0.0, 11],
    [3.1, 5.55, 2],
    [30.0, 3.55, 2222],
    [7.99, 8.99, 33],
    ]

    # Set table model
    self.model = TableModel(data)
    self.table.setModel(self.model)
    self.setCentralWidget(self.table)

    # Use proxy for column sorting
    proxyModel = QSortFilterProxyModel()
    proxyModel.setSourceModel(self.model)
    self.table.setModel(proxyModel)
    self.table.setSortingEnabled(True)

    # hide vertical headers
    self.table.verticalHeader().setVisible(False)

    # format horizontal headers
    stylesheet = "::section{Background-color:rgb(171,178,185);font-weight:bold}"
    self.table.setStyleSheet(stylesheet)
    self.table.setAlternatingRowColors(True)

    if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.setMinimumSize(350, 250)
    window.setWindowTitle('Sorting column example')
    window.show()
    app.exec_()

    Continue reading...

Compartilhe esta Página