Сортировка в pyqt tablewidget

Как я могу отсортировать столбец в pyqt по наибольшему числу? В настоящее время у меня есть setSortingEnabled(True), и это сортирует его только по наибольшему количеству чисел (например, 1,1,1,1,2,2,2,3,3), я хочу сделать это, например, по наибольшему числу (например, 58, 25,15,10). Спасибо!

Обновление данных:

def setmydata(self):
    for n, key in enumerate(self.data):
        for m, item in enumerate(self.data[key]):
            newitem = QtGui.QTableWidgetItem(item)
            self.setItem(m, n, newitem)

Весь код:

import sys
from PyQt4.QtGui import QTableWidget 
from PyQt4 import QtGui,QtCore,Qt
import MySQLdb as mdb
from functools import partial
import time
class Window(QtGui.QDialog):
    process_column_signal = QtCore.pyqtSignal()
    def __init__(self,parent=None):
        super(Window, self).__init__()
        self.layout = QtGui.QVBoxLayout(self)
        self.db = mdb.connect('serv','user','pass','db')
        self.model = self.db.cursor()
        self.initialData = self.get_data_status()
        self.table1 = MyTableStatus(self.initialData, 145, 4)
        callback = partial(self.process_column,self.table1)
        self.process_column_signal.connect(callback)        
        self.layout.addWidget(self.table1)  
        self.timer_status = QtCore.QTimer()
        self.timer_status.timeout.connect(self.updateAllViews)
        self.timer_status.timeout.connect(self.some_method)
        # check every half-second
        self.timer_status.start(1000*5)
    def some_method(self):
        self.process_column_signal.emit()

    def get_data_status(self):
        self.model.execute("""SELECT cpu_juliet,cpu,cpu_julietleft FROM status
                              WHERE date = (SELECT MAX(date) FROM status)""")        
        rows_status_cpu = self.model.fetchone()
        self.listb1 = ['%s' % rows_status_cpu[0],'%s' % rows_status_cpu[2],'%s' % rows_status_cpu[1],'%s' % rows_status_cpu[1]]#['%s %s' % self.rows_status]
        self.model.execute("""SELECT disk_queue_juliet FROM status
                              WHERE date = (SELECT MAX(date) FROM status)""")        
        rows_status_disk_queue = self.model.fetchone()        
        self.lista1 = 'Juliet','Julietleft','Pong','Hulk'
        self.listc1 = ['%s' % rows_status_disk_queue,'%s' % rows_status_disk_queue,'%s' % rows_status_disk_queue,'%s' % rows_status_disk_queue ]
        if self.listb1[0] >= '80' or self.listc1[0] >= '9':
            server_status_Juliet = 'WARNING'
        else:
            server_status_Juliet = 'Normal'
        if self.listb1[1] >= '80' or self.listc1[1] >= '9':
            server_status_Julietleft = 'WARNING'
        else:
            server_status_Julietleft = 'Normal'
        if self.listb1[2] >= '80' or self.listc1[2] >= '9':
            server_status_Pong = 'WARNING'
        else:
            server_status_Pong = 'Normal'
        if self.listb1[3] >= '80' or self.listc1[3] >= '9':
            server_status_Hulk = 'WARNING'
        else:
            server_status_Hulk = 'Normal'
        self.listd1 = ['%s' % server_status_Juliet,'%s' % server_status_Julietleft,'%s' % server_status_Pong,'%s' % server_status_Hulk]
#        if server_status_Hulk == "WARNING": #or server_status_Pong == "WARNING" or server_status_Julietleft == "WARNING" or server_status_Juliet == "WARNING":
#            self.serverstatus.setStyleSheet("QTabWidget {color: red}")
        #status label conditions
        self.mystruct1 = {'A':self.lista1, 'B':self.listb1, 'C':self.listc1, 'D':self.listd1} 
        return self.mystruct1

    def updateAllViews(self):
        _ = self.get_data_status()
        self.updateTable()

    def updateTable(self):
        self.table1.updateFromDict(self.mystruct1)
    def process_column(table1, processCol=1):
        colCount = table1.table1.rowCount()
        for row in xrange(table1.table1.rowCount()):
            for col in xrange(4):
                try:
                    item = table1.table1.item(row, 3)
                    text = item.text()
                    if (float(text) >= 20.0 ):
                        for col in xrange(colCount):
                            print row
                            item = table1.table1.item(row,col)
                            item.setBackground(QtGui.QBrush(QtCore.Qt.yellow))
                except:
                    pass


class MyTableStatus(QTableWidget):
    def __init__(self, thestruct, *args): 
        QTableWidget.__init__(self, *args)
        self.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Preferred)
        self.setHorizontalHeaderLabels(['Server', 'Avg. Disk Queue','CPU Load',"Status"])
        self.setSortingEnabled(False)


        self.data = {}
        self.setmydata()

    def updateFromDict(self, aDict):
        self.data.clear()
        self.data.update(aDict)

        self.setmydata()

    def setmydata(self):
        for n, key in enumerate(self.data):
            for m, item in enumerate(self.data[key]):
                newitem = QtGui.QTableWidgetItem(item)
                self.setItem(m, n, newitem)
def main():
   app = QtGui.QApplication(sys.argv)
   app.setStyle(QtGui.QStyleFactory.create("plastique"))
   main_window = Window()
   main_window.repaint()
   main_window.show() 
   sys.exit(app.exec_())

if __name__ == '__main__':
   main()

person Community    schedule 13.08.2012    source источник


Ответы (4)


Его сортировка буквенно-цифровая (то есть, с точки зрения строк, «1», «10», «11», «12», «2», «20», «21», «22», «3», « 4 'и т. д. - правильный порядок сортировки. Похоже, что для QTableWidgetItem, если вы используете метод setData(Qt.EditRole, value), порядок сортировки будет работать. В зависимости от вашей версии Qt (я предполагаю), у вас может быть чтобы перегрузить метод less than вашего элемента табличного виджета.

from PyQt4.QtCore import Qt, QVariant
from PyQt4.QtGui import QApplication, QTableWidget, QTableWidgetItem

class MyTableWidgetItem(QTableWidgetItem):
    def __lt__(self, other):
        if ( isinstance(other, QTableWidgetItem) ):
            my_value, my_ok = self.data(Qt.EditRole).toInt()
            other_value, other_ok = other.data(Qt.EditRole).toInt()

            if ( my_ok and other_ok ):
                return my_value < other_value

        return super(MyTableWidgetItem, self).__lt__(other)

if ( __name__ == '__main__' ):
    app = None
    if ( QApplication.instance() is None ):
        app = QApplication([])

    widget = QTableWidget()
    widget.setWindowFlags(Qt.Dialog)
    widget.setSortingEnabled(True)

    widget.setRowCount(50)
    widget.setColumnCount(3)
    for row in range(50):
       # create a normal QTableWidgetItem
       a = QTableWidgetItem()
       a.setText(str(row))
       widget.setItem(row, 0, a)

       # create a proper sorted item
       b = QTableWidgetItem()
       b.setData(Qt.EditRole, QVariant(row))
       widget.setItem(row, 1, b)

       # create a custom sorted item
       c = MyTableWidgetItem()
       c.setData(Qt.EditRole, QVariant(row))
       widget.setItem(row, 2, c)

    widget.show()
    if ( app ):
        app.exec_()
person Eric Hulser    schedule 13.08.2012
comment
На какой способ вы надеетесь? Что у вас есть на данный момент - как загружается? Единственное, что вам действительно нужно знать, это то, что вместо вызова: item.setText(str(text)), вы вызываете item.setData(Qt.EditRole, QVariant(data)) - person Eric Hulser; 14.08.2012
comment
Он все еще сортируется в алфавитно-цифровом порядке, когда я помещаю item, как показано в вопросе, в Qvariant. - person ; 14.08.2012
comment
Я отредактировал пример — честно говоря, я был удивлен, что он сработал в моем тестовом примере. Мне всегда приходилось перегружать метод меньше, чем раньше. Попробуйте это, используйте подкласс с пользовательским методом lt и посмотрите, работает ли это. - person Eric Hulser; 14.08.2012
comment
Как ни странно, это все еще не работает, если я вставляю элемент (или в вашем случае c), он остается прежним, однако, когда я вставляю m в qvariant в строке вашего случая, он просто идет 1-169 в каждом столбце (количество ряды израсходованы), есть идеи, почему? - person ; 16.08.2012
comment
Не могли бы вы опубликовать свой код? Я думаю, что зашел так далеко, как только мог, размышляя об этом абстрактно... спасибо! - person Eric Hulser; 17.08.2012
comment
Итак, важной частью моего примера является новый подкласс QTableWidgetItem, который реализует собственный метод less than. Вы все еще используете стандартный QTableWidgetItem в своем коде. Вам нужно использовать пользовательский класс. - person Eric Hulser; 17.08.2012
comment
Просто обратите внимание, хотя мы уже использовали setData, сам аргумент также должен быть в форме целого числа, а не строки. Итак, это не заставит сортировку работать : setData(Qt.DisplayRole, '10'), но это сработает : setData(Qt.DisplayRole, 10) - person swdev; 05.06.2014

Альтернативой использованию пользовательского Item является использование SortFilterProxy (что вам, вероятно, следует делать в любом случае). В этом случае вы можете определить метод lessThan, который будет использоваться для сортировки. Вот мой:

class SortFilterProxyModel(QSortFilterProxyModel):

    def lessThan(self, left_index, right_index):

        left_var = left_index.data(Qt.EditRole)
        right_var = right_index.data(Qt.EditRole)

        try:
            return float(left_var) < float(right_var)
        except (ValueError, TypeError):
            pass
        return left_var < right_var

Он использует EditRole для получения данных для сортировки, поэтому вы можете сделать любое сопоставление для удобства использования, которое вы хотите сделать в случаях DisplayRole. Он также просто пытается выполнить числовую сортировку значений, которые могут быть преобразованы в float, или собственную сортировку в противном случае. Не самый общий подход, но, кажется, хорошо работает для меня. YMMV.

person DirkR    schedule 07.04.2014
comment
Как мы используем это в QTableWidget? Любой пример? - person swdev; 05.06.2014
comment
Прокси простые, выше почти все. Создайте его экземпляр, используйте на нем setSourceModel(<original model>) и используйте его вместо исходной модели. Для редактирования вам также необходимо перенаправить вызовы startEditing() и stopEditing() на исходную модель. Кажется, это работает хорошо для меня до сих пор. - person DirkR; 18.06.2014

Другим возможным решением для числовой сортировки может быть добавление специального атрибута и сравнение его на основе этого значения. Mybe, это больше похоже на Java.

class MyTableWidgetItem(QTableWidgetItem):

def __init__(self, value):
    QTableWidgetItem.__init__(self)
    self.value = value

def __lt__(self, other):
    if isinstance(other, MyTableWidgetItem):
        return self.value < other.value

    return super(QTableWidgetItem, self).__lt__(other)
person S. Weber    schedule 08.03.2017

Более простой способ — добавить несколько пробелов к числовому тексту. Значение ascii ' ' меньше '0', поэтому оно будет работать так, как вы хотите. Вот что я делаю:

element = str(num)                # convert to str
padded = ('     '+element)[-5:]   # make all elements the same length
item.setText(padded)
person SoloPilot    schedule 30.03.2016
comment
zfill() заполняет '0's. Мы добавляем пустые символы, а не нули. - person SoloPilot; 04.03.2017