PyQt5:如何在单击QHeaderView的标题时对QTableView进行排序?

时间:2016-10-17 18:48:45

标签: python sorting pyqt5 qtableview qheaderview

我想在点击QHeaderView的标题时对QTableView进行排序。我在互联网上找到了几个代码示例,如下所示:Sort QTableView in pyqt5 但它对我不起作用。我也看看Summerfield的Rapid Gui编程书,但我也能找到一些有用的东西。

在这个快速示例中,我如何按名称或年龄对表进行排序?

这是我的代码:

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import pandas as pd
import operator

# This class was generated from the Qt Creator
class Ui_tableView_ex(object):
    def setupUi(self, tableView_ex):
        tableView_ex.setObjectName("tableView_ex")
        tableView_ex.resize(800, 600)
        self.centralwidget = QWidget(tableView_ex)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.myTable = QTableView(self.centralwidget)
        self.myTable.setObjectName("monTablo")
        self.gridLayout.addWidget(self.myTable, 0, 0, 1, 1)
        tableView_ex.setCentralWidget(self.centralwidget)

        self.retranslateUi(tableView_ex)
        QMetaObject.connectSlotsByName(tableView_ex)

    def retranslateUi(self, tableView_ex):
        _translate = QCoreApplication.translate
        tableView_ex.setWindowTitle(_translate("tableView_ex", "MainWindow"))


class TableTest(QMainWindow, Ui_tableView_ex):
    def __init__(self, parent=None):
        super(TableTest, self).__init__(parent)
        self.setupUi(self)

        self.model = TableModel()
        self.myTable.setModel(self.model)
        self.myTable.setShowGrid(False)

        self.hView = HeaderView(self.myTable)
        self.myTable.setHorizontalHeader(self.hView)
        self.myTable.verticalHeader().hide()

        # adding alternate colours
        self.myTable.setAlternatingRowColors(True)
        self.myTable.setStyleSheet("alternate-background-color: rgb(209, 209, 209)"
                                   "; background-color: rgb(244, 244, 244);")

        # self.myTable.setSortingEnabled(True)
        # self.myTable.sortByColumn(1, Qt.AscendingOrder)


class HeaderView(QHeaderView):
    def __init__(self, parent):
        QHeaderView.__init__(self, Qt.Horizontal, parent)
        self.model = TableModel()
        self.setModel(self.model)

        # Setting font for headers only
        self.font = QFont("Helvetica", 12)
        self.setFont(self.font)

        # Changing section backgroud color. font color and font weight
        self.setStyleSheet("::section{background-color: pink; color: green; font-weight: bold}")

        self.setSectionResizeMode(1)
        self.setSectionsClickable(True)


class TableModel(QAbstractTableModel):

    def __init__(self):
        QAbstractTableModel.__init__(self)
        super(TableModel, self).__init__()

        self.headers = ["Name", "Age", "Grades"]
        self.stocks = [["George", "26", "80%"],
                       ["Bob", "16", "95%"],
                       ["Martha", "22", "98%"]]
        self.data = pd.DataFrame(self.stocks, columns=self.headers)

    def update(self, in_data):
        self.data = in_data

    def rowCount(self, parent=None):
        return len(self.data.index)

    def columnCount(self, parent=None):
        return len(self.data.columns.values)

    def setData(self, index, value, role=None):
        if role == Qt.EditRole:
            row = index.row()
            col = index.column()
            column = self.data.columns.values[col]
            self.data.set_value(row, column, value)
            self.update(self.data)
            return True

    def data(self, index, role=None):
        if role == Qt.DisplayRole:
            row = index.row()
            col = index.column()
            value = self.data.iloc[row, col]
            return value

    def headerData(self, section, orientation, role=None):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return self.data.columns.values[section]

# -----------------NOT WORKING!!!---------------
# =================================================

    def sort(self, Ncol, order):
        """Sort table by given column number.
        """
        self.layoutAboutToBeChanged.emit()
        self.data = sorted(self.data, key=operator.itemgetter(Ncol))
        if order == Qt.DescendingOrder:
            self.data.reverse()
        self.layoutChanged.emit()
# =================================================


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    app.setStyle(QStyleFactory.create("Fusion"))
    main_window = TableTest()
    main_window.show()
    app.exec_()
    sys.exit()

我尝试修改了一些内容,但没有任何结果,当我取消注释setSortingEnabled(True)行时,窗口甚至都没有打开。因此,我无法知道我是否更接近解决方案!我还想根据等级更改文本颜色(红色低于50,绿色高于50)。为此,我没有那么多搜索,所以我会在问问题之前自己尝试一下,但如果你有任何提示,我将非常感激!

感谢您的帮助!

1 个答案:

答案 0 :(得分:3)

你的排序函数是问题,你没有使用pandas DataFrame排序函数,self.data变成python list,然后其他函数失败,程序崩溃。

要正确排序DataFrame,请使用sort_values函数,如下所示:

def sort(self, Ncol, order):
    """Sort table by given column number."""
    self.layoutAboutToBeChanged.emit()
    self.data = self.data.sort_values(self.headers[Ncol],
                                      ascending=order == Qt.AscendingOrder)
    self.layoutChanged.emit()