3

I am trying to sort a column which has progressbar in it. I want column to be sorted by progressbar value. Any help will be much appreciated enter image description here

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys


class Example(QMainWindow):

    def __init__(self):
        super(Example, self).__init__()

        self.initUI()

    def initUI(self):

        self.tablew = Table(self)
        self.setCentralWidget(self.tablew)

        self.setGeometry(300, 300, 300, 200)
        self.show()


class ProgressBar(QProgressBar):

    def __init__(self, value, parent=None):
        QProgressBar.__init__(self)
        self.setMinimum(1)
        self.setMaximum(5.0)
        self.setValue(value)
        self.setFormat('{0:.5f}'.format(value))
        style = ''' QProgressBar{max-height: 15px;text-align: center;}'''
        self.setStyleSheet(style)


class Table(QTableWidget):

    def __init__(self,   parent=None):
        QTableWidget.__init__(self)
        self.setColumnCount(2)
        self.setHorizontalHeaderLabels(['id', 'status'])
        header = self.horizontalHeader()
        header.setResizeMode(QHeaderView.Stretch)
        self.setSortingEnabled(True)
        self.loadData()
        #

    def loadData(self):
        #
        tableData = [[89, 4.8], [99, 3.9], [101, 2.6], [105, 4]]
        #
        self.setRowCount(len(tableData))
        #
        for index, value in enumerate(tableData):
            # column1
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, value[0])
            self.setItem(index, 0, item)
            # column2
            self.setCellWidget(index, 1, ProgressBar(value[1]))
        #


def main():

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

UPDATE: Based on answer from @ekhumoro Below is the complete code but somehow it doest sort correctly. Screenshot attached after sorting column manually probelm in sorting

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys


class Example(QMainWindow):

    def __init__(self):
        super(Example, self).__init__()

        self.initUI()

    def initUI(self):

        self.tablew = Table(self)
        self.setCentralWidget(self.tablew)

        self.setGeometry(300, 300, 300, 200)
        self.show()


class ProgressBar(QProgressBar):

    def __init__(self, value, parent=None):
        QProgressBar.__init__(self)
        self.setMinimum(1)
        self.setMaximum(5.0)
        self.setValue(value)
        self.setFormat('{0:.5f}'.format(value))
        style = ''' QProgressBar{max-height: 15px;text-align: center;}'''
        self.setStyleSheet(style)


class Table(QTableWidget):

    def __init__(self,   parent=None):
        QTableWidget.__init__(self)
        self.setColumnCount(2)
        self.setHorizontalHeaderLabels(['id', 'status'])
        header = self.horizontalHeader()
        header.setResizeMode(QHeaderView.Stretch)
        self.setSortingEnabled(True)
        self.loadData()
        #

    def loadData(self):
        #
        tableData = [[89, 4.8], [99, 3.9], [101, 2.6], [105, 4]]
        #
        self.setRowCount(len(tableData))
        #
        for index, value in enumerate(tableData):
            # column1
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, value[0])
            self.setItem(index, 0, item)
            # column2
            item = ProgressWidgetItem()
            self.setItem(index, 1, item)
            item.updateValue(value[1])
            progress = ProgressBar(value[1])
            self.setCellWidget(index, 1, progress)
            progress.valueChanged.connect(item.updateValue)
        self.sortItems(1, Qt.DescendingOrder)


class ProgressWidgetItem(QTableWidgetItem):

    def __lt__(self, other):
        return self.data(Qt.UserRole) < other.data(Qt.UserRole)

    def updateValue(self, value):
        self.setData(Qt.UserRole, value)


def main():

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
django
  • 2,809
  • 5
  • 47
  • 80

1 Answers1

5

You can subclass QTableWidgetItem and reimplement __lt__, and then add blank items to the progress bar column:

            # column2
            item = ProgressWidgetItem()
            self.setItem(index, 1, item)
            item.updateValue(value[1])
            progress = ProgressBar(value[1])
            self.setCellWidget(index, 1, progress)
            progress.valueChanged.connect(item.updateValue)
        self.sortItems(1, Qt.DescendingOrder)


class ProgressWidgetItem(QTableWidgetItem):
    def __lt__(self, other):
        # python 3
        # return self.data(Qt.UserRole) < other.data(Qt.UserRole)
        # python 2
        return (self.data(Qt.UserRole).toPyObject() <
                other.data(Qt.UserRole).toPyObject())

    def updateValue(self, value):
        self.setData(Qt.UserRole, value)

PS:

The implementation of __lt__ is different for Python 2 vs Python 3, because, by default, the latter will return normal Python types rather than QVariant and QString. It is possible to directly test whether two QVariant objects are equal, but not whether one is less than the other (even if they contain values of the same type).

In Python 2, you can eliminate QVariant and QString by putting the following code before the first PyQt imports in your application:

import sip
sip.setapi('QString', 2)
sip.setapi('QVariant', 2)

This will make the behaviour the same as Python 3, and means you never have to use ugly code like variant.toPyObject() or str(qtstring).

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • I used your suggestion but when i apply sorting order i get is 2.6,3.9,4.8,4.0 4.0 is stuck at bottom afetr that no matter how many times I sort table.. any Ideas ? – django Oct 29 '15 at 08:22
  • @django. I checked it again and it works perfectly fine for me. Are you sure you made the right changes? Copy my code and replace the last three lines of `loadData`. – ekhumoro Oct 29 '15 at 15:24
  • please check above. I have updated my post with new code and screenshit of problem as well – django Oct 30 '15 at 08:21
  • @django. Please read my previous comment more carefully: copy my code and **replace** the **last three lines** of `loadData`. – ekhumoro Oct 30 '15 at 16:33
  • I did replaced loadData last three lines with your code but It is not working for me. I have Updated my post with complete code as you suggested and attached screenshot of the problem at the end too. Could it be python version problem ? I am using Python 2.7.6.1 and QT 4.8.5 – django Nov 02 '15 at 04:09
  • @django. For some reason, I was certain you were using python3. Anyway, see my updated code and explanation for some solutions. – ekhumoro Nov 02 '15 at 16:00