pythontableviewpyqt4model-view

Pyqt4 Model View - Adding Slider , CheckBox Line Edit in Table model


I am working on a ui as shown in the image below.

In the First columns i have a Check Box, Second columns i have a Slider, Third just text

the slider value applied to a function. the result will be shown in the third column.

I am not not able to see the slider not the checkbox

Output is shown in the image

Code:

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


class PaletteTableModel(QtCore.QAbstractTableModel):
    def __init__(self, colors = [[]], parent = None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self.__colors = colors
    def rowCount(self, parent):
        return len(self.__colors)  
    def columnCount(self, parent):
        return len(self.__colors[0])
    def flags(self, index):
        if not index.isValid():
            return None
        if index.column() == 0:
            return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable
        else:
            return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

    def data(self, index, role):        
        row = index.row()
        col = index.column()
        if role == QtCore.Qt.DisplayRole:
            return '{0}'.format(self.__colors[row][col])
        elif role == Qt.CheckStateRole and col==0:
            return QPersistentModelIndex(index)
        else:
            return None
    def setData(self, index, value, role=Qt.EditRole):
        if not index.isValid():
            return False
        if role == Qt.CheckStateRole:
            if index.column() == 0:
                if self.__colors[index.row()][index.column()].isChecked():
                    return QtCore.Qt.Checked
                else:
                    return QtCore.Qt.Unchecked   

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    app.setStyle("plastique")

    tableView = QtGui.QTableView()
    tableView.show()

    row = 6
    col = 3
    table_data = []
    for row in range(row):
        data = [None,None,None]
        #Checkbox
        c1 = QCheckBox("c"+str(row))
        c1.setChecked(True)
        data[0] = c1

        #slider
        s1 = QSlider(Qt.Horizontal)
        s1.setMinimum(10)
        s1.setMaximum(30)
        s1.setValue(20)
        data[1] = s1   

        #text
        data[2] = 'TEST'
        table_data.append(data)


    model = PaletteTableModel(table_data)    
    tableView.setModel(model)

    sys.exit(app.exec_())

UI:

Sceen shot of ui


Solution

  • The models serve to keep information, do not keep the view. If you want to customize the view you should use delegates. By default if you save it in the CheckStateRole role, a checkbox will be created, if you save in the DisplayRole it will be displayed as text, so even if you save the widgets what is shown is the __str__ that shows the memory address.

    What you should do is just save the data, that is, the bool, the value and the text, and then create a delegate by creating an editor in the second column and make it persistent.

    import sys
    from PyQt4 import QtCore, QtGui
    
    
    class PaletteTableModel(QtCore.QAbstractTableModel):
        def __init__(self, cols=3,colors = [], parent = None):
            super(PaletteTableModel, self).__init__(parent)
            self.__colors = colors
            self.__cols = cols
    
        def rowCount(self, parent=QtCore.QModelIndex()):
            return len(self.__colors)  
    
        def columnCount(self, parent=QtCore.QModelIndex()):
            if parent.isValid():
                return 0
            return self.__cols
    
        def appendRow(self, data):
            self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
            self.__colors.append(data[:])
            self.endInsertRows()
    
        def flags(self, index):
            fl = QtCore.Qt.NoItemFlags
            if index.isValid():
                fl |= QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
                if index.column() == 0:
                    fl |= QtCore.Qt.ItemIsUserCheckable
            return fl
    
        def data(self, index, role=QtCore.Qt.DisplayRole):        
            if not index.isValid():
                return None
            row = index.row()
            col = index.column()
            if 0 <= row < self.rowCount() and 0<= col < self.columnCount():
                if role  == QtCore.Qt.DisplayRole and 0 < col < self.columnCount():
                    return self.__colors[row][col]
                elif role == QtCore.Qt.CheckStateRole and col == 0:
                    return QtCore.Qt.Checked if self.__colors[row][0] else QtCore.Qt.Unchecked
            return None
    
        def setData(self, index, value, role=QtCore.Qt.EditRole):
            if not index.isValid():
                return False
            row = index.row()
            col = index.column()
            if role == QtCore.Qt.CheckStateRole and col == 0:
                self.__colors[row][col] = value == QtCore.Qt.Checked
                return True
            elif role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
                if 0 < index.column() < self.columnCount():
                    self.__colors[row][col] = value
                    return True
            return False
    
    
    class PaletteDelegate(QtGui.QStyledItemDelegate):
        def paint(self, painter, option, index):
            if index.column() == 1:
                view = option.widget
                if isinstance(view, QtGui.QTableView):
                    if not view.openPersistentEditor(index):
                        view.openPersistentEditor(index)
            else:
                super(PaletteDelegate, self).paint(painter, option, index)
    
        def createEditor(self, parent, option, index):
            if index.column() == 1:
                editor = QtGui.QSlider(parent, minimum=10, maximum=30, orientation=QtCore.Qt.Horizontal)
                editor.valueChanged.connect(self.commitEditor)
                return editor
            return super(PaletteDelegate, self).createEditor(parent, option, index)
    
        def setEditorData(self, editor, index):
            if index.column() == 1:
                val = index.data()
                if isinstance(val, QtCore.QVariant):
                    _, val = val.toInt()
                editor.setValue(val)
            else:
                super(PaletteDelegate, self).setEditorData(editor, index)
    
        def setModelData(self, editor, model, index):
            if index.column() == 1:
                model.setData(index, editor.value())
            else:
                super(PaletteDelegate, self).setModelData(editor,model, index)
    
        def commitEditor(self):
            editor = self.sender()
            self.commitData.emit(editor)
    
    
    if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        app.setStyle("plastique")
    
        tableView = QtGui.QTableView()
        tableView.show()
    
        row, col = 6, 3
    
        model = PaletteTableModel(cols=col, parent=tableView)
        tableView.setModel(model)
        tableView.setItemDelegate(PaletteDelegate(tableView))
    
        for r in range(row):
            data = [True, 20, 'TEST']
            model.appendRow(data)
    
        sys.exit(app.exec_())
    

    enter image description here