-1

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

Pramit Sawant
  • 682
  • 1
  • 9
  • 17

1 Answers1

1

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

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks, How to get the slider values in data() and setData() functions?? – Pramit Sawant Oct 09 '18 at 04:29
  • 1
    @PramitSawant data() is used to obtain model information, and setData() to update the model, is a getter and a setter. If you want to obtain what is shown in the first slider we must use the data method, but this requires a QModelIndex, for this we use: `print(model.data(model.index(0, 1)))` or `print(model.index(0, 1).data())` – eyllanesc Oct 09 '18 at 04:33
  • if i link sliders and checkbox to database. and want to update as per chech box and slider values, should i put the update statements in setData() or create a new method to do this.. what will be the best approach? – Pramit Sawant Oct 09 '18 at 04:40
  • @PramitSawant Do you want the database to be updated through the view? This is why you do not use QSqlQueryModel or QSqlTableModel, it is easier, as you realize the view is independent of the model, in my solution I fix your model that has errors very serious, and added the delegate to generate the view. – eyllanesc Oct 09 '18 at 04:43
  • yes... I will load check box and slider values from the database. One slider value changed may reflects all other sliders and check boxes. so the view needs to be update on any slider change. I can keep a button to update the values from view in the database. Do you have any links or documentation reference to get more information about delegates ? – Pramit Sawant Oct 09 '18 at 04:55