title: With PySide2 and QTableView how do i get multiple delegates in table view using pandas model?
body: <p>hi i've tried all i can think of and had looked at hundreds of stack overflow questions about tables and delegate's, and scratched my head for hours looking at the documentation trying to understand the c++ language and i have not read anything clearly stating that there's limits to the of amount delegate's a table view can take and not take, now i hope i can say i've got a firm understanding of the basic's in  pyside2 and pyqt5 especially with tables and models but the delegates is a bit mind boggling, i've gotten this far based on people's questions mostly from stack overflow so this is my first attempt to ask any help..  </p>
  
  <pre><code>import pandas as pd
  from PySide2 import QtWidgets
  
  from PySide2.QtCore import (Qt, QAbstractTableModel, QModelIndex, QEvent, QPersistentModelIndex, 
                              QSortFilterProxyModel,
                              QTimer, Slot)
  from PySide2.QtWidgets import QTableView, QAbstractItemView, QComboBox, QItemDelegate
  
  
  class ScheduleModel(QAbstractTableModel):
  
      def __init__(self, schedules_list=None, parent=None):
          super(ScheduleModel, self).__init__(parent)
  
          if schedules_list is None:
              self.schedules_list = []
          else:
              self.schedules_list = schedules_list
  
      def rowCount(self, index=QModelIndex()):
          return self.schedules_list.shape[0]
  
      def columnCount(self, index=QModelIndex()):
          return self.schedules_list.shape[1]
  
      def data(self, index, role=Qt.DisplayRole):
          col = index.column()
          if index.isValid():
              if role == Qt.DisplayRole:
                  value = self.schedules_list.iloc[index.row(), index.column()]
                  return str(self.schedules_list.iloc[index.row(), index.column()])
          return None
  
      def headerData(self, section, orientation, role):
          # section is the index of the column/row.
          if orientation == Qt.Horizontal and role == Qt.DisplayRole:
              return self.schedules_list.columns[section]
  
          if orientation == Qt.Vertical:
              return str(self.schedules_list.index[section])
  
      def setData(self, index, value, role=Qt.EditRole):
          if role != Qt.EditRole:
              return False
  
          if index.isValid() and 0 &lt;= index.row() &lt; len(self.schedules_list):
              self.schedules_list.iloc[index.row(), index.column()] = value
              if self.data(index, Qt.DisplayRole) == value:
                  self.dataChanged.emit(index, index, (Qt.EditRole,))
                  return True
          return False
  
      def flags(self, index):
          if 1 &lt;= index.column() &lt;= 7:
              return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
          if index.column() == 5:
              return Qt.ItemIsEditable | Qt.ItemIsUserCheckable | Qt.ItemIsSelectable
          elif index.column() == 1 and index.column() == 7:
              return Qt.DecorationRole
          else:
              return Qt.ItemIsSelectable
  
  
  class ClickDelegate(QtWidgets.QStyledItemDelegate):
      blankText = '&lt;Click here to add path&gt;'
  
      def openFileDialog(self, lineEdit):
          if not self.blankText.startswith(lineEdit.text()):
              currentPath = lineEdit.text()
          else:
              currentPath = ''
          path, _ = QtWidgets.QFileDialog.getOpenFileName(lineEdit.window(),
                                                          'Select file', currentPath)
          if path:
              lineEdit.setText(path)
  
      def createEditor(self, parent, option, index):
          editor = QtWidgets.QWidget(parent)
  
          layout = QtWidgets.QHBoxLayout(editor)
          layout.setContentsMargins(0, 0, 0, 0)
          layout.setSpacing(0)
  
          editor.lineEdit = QtWidgets.QLineEdit(self.blankText)
          layout.addWidget(editor.lineEdit)
          editor.setFocusProxy(editor.lineEdit)
          editor.lineEdit.installEventFilter(self)
  
          button = QtWidgets.QToolButton(text='...')
          layout.addWidget(button)
          button.setFocusPolicy(Qt.NoFocus)
          button.clicked.connect(lambda: self.openFileDialog(editor.lineEdit))
          return editor
  
      def setEditorData(self, editor, index):
          if index.data():
              editor.lineEdit.setText(str(index.data()))
          editor.lineEdit.selectAll()
  
      def setModelData(self, editor, model, index):
          if not editor.lineEdit.text():
              model.setData(index, None)
          elif not self.blankText.startswith(editor.lineEdit.text()):
              model.setData(index, editor.lineEdit.text())
  
      def initStyleOption(self, option, index):
          super(ClickDelegate, self).initStyleOption(option, index)
  
          if not option.text:
              option.text = self.blankText
  
      def eventFilter(self, source, event):
          if isinstance(source, QtWidgets.QLineEdit):
              if (event.type() == QEvent.MouseButtonPress and
                      source.hasSelectedText() and
                      self.blankText.startswith(source.text())):
                  res = super(ClickDelegate, self).eventFilter(source, event)
                  source.clear()
                  return res
              elif event.type() == QEvent.KeyPress and event.key() in (
                      Qt.Key_Escape, Qt.Key_Tab, Qt.Key_Backtab):
                  return False
          return super(ClickDelegate, self).eventFilter(source, event)
  
      def checkIndex(self, table, index):
          if index in table.selectedIndexes() and index == table.currentIndex():
              table.edit(index)
  
      def editorEvent(self, event, model, option, index):
          if (event.type() == QEvent.MouseButtonPress and
                  event.button() == Qt.LeftButton and
                  index in option.widget.selectedIndexes()):
              table = option.widget
              QTimer.singleShot(0, lambda: self.checkIndex(table, index))
          return super(ClickDelegate, self).editorEvent(event, model, option, index)
  
  
  class CheckBoxDelegate(QtWidgets.QItemDelegate):
      """
      A delegate that places a fully functioning QCheckBox cell of the column to which it's applied.
      """
  
      def __init__(self, parent):
          QtWidgets.QItemDelegate.__init__(self, parent)
  
      def createEditor(self, parent, option, index):
          """
          Important, otherwise an editor is created if the user clicks in this cell.
          """
          return None
  
      def paint(self, painter, option, index):
          """
          Paint a checkbox without the label.
          """
          self.drawCheck(painter, option, option.rect,
                         Qt.Unchecked if int(index.data()) == 0 else Qt.Checked)
  
      def editorEvent(self, event, model, option, index):
          '''
          Change the data in the model and the state of the checkbox
          if the user presses the left mousebutton and this cell is editable. Otherwise do nothing.
          '''
          if not int(index.flags() and Qt.ItemIsEditable) &gt; 0:
              return False
  
          if event.type() == QEvent.MouseButtonRelease and event.button() == Qt.LeftButton:
              # Change the checkbox-state
              self.setModelData(None, model, index)
              return True
  
          return False
  
      def setModelData(self, editor, model, index):
          '''
          The user wanted to change the old state in the opposite.
          '''
          model.setData(index, 1 if int(index.data()) == 0 else 0, Qt.EditRole)
  
  
  class DoubleSpinBoxDelegate(QtWidgets.QStyledItemDelegate):
      """A delegate class displaying a double spin box."""
  
      def __init__(self, parent=None, minimum=0.0, maximum=100.0, step=0.01):
          QtWidgets.QStyledItemDelegate.__init__(self, parent)
          self._min = minimum
          self._max = maximum
          self._step = step
  
      def createEditor(self, parent, option, index):
          editor = QtWidgets.QDoubleSpinBox(parent)
          editor.setMinimum(self._min)
          editor.setMaximum(self._max)
          editor.setSingleStep(self._step)
          editor.setAccelerated(True)
          editor.installEventFilter(self)
          return editor
  
      def setEditorData(self, spinBox, index):
          value = float(index.model().data(index, Qt.DisplayRole))
          spinBox.setValue(value)
  
      def setModelData(self, spinBox, model, index):
          value = spinBox.value()
          model.setData(index, value)
  
      def updateEditorGeometry(self, editor, option, index):
          editor.setGeometry(option.rect)
  
  
  class ComboBoxDelegate(QItemDelegate):
      def __init__(self, parent=None):
          super(ComboBoxDelegate, self).__init__(parent)
          self.items = []
  
      def setItems(self, items):
          self.items = items
  
      def createEditor(self, parent, option, index):
          combo = QComboBox(parent)
          li = []
          for item in self.items:
              li.append(item)
          combo.addItems(li)
          combo.currentIndexChanged.connect(self.currentIndexChanged)
          return combo
  
      def setEditorData(self, editor, index):
          editor.blockSignals(True)
          text = index.model().data(index, Qt.DisplayRole)
          try:
              i = self.items.index(text)
          except ValueError:
              i = 0
          editor.setCurrentIndex(i)
  
      def setModelData(self, editor, model, index):
          # model.setData(index, editor.currentIndex(), Qt.EditRole)
          model.setData(index, editor.currentText())
  
      def updateEditorGeometry(self, editor, option, index):
          editor.setGeometry(option.rect)
  
      @Slot()
      def currentIndexChanged(self):
          self.commitData.emit(self.sender())
  
  
  class SchedulesViewer(QTableView):
      # selectionChanged = Signal(QItemSelection)
      # data_changed = Signal(QModelIndex, QModelIndex)
  
      def __init__(self, parent=None):
          QTableView.__init__(self, parent)
  
          # self.setContextMenuPolicy(Qt.CustomContextMenu)
          # self.customContextMenuRequested.connect(self.schedule_context_menu)
          address = {'idx': '1',
                     'presets': 'presets',
                     'selected_source': 'get_source',
                     'selected_destinations': 'selected_destinations',
                     'interval': '0400',
                     'active': '1',
                     'priority': 'high',
                     'categories': 'programming',
                     'last_total': '222',
                     }
  
          self.schedule_model = ScheduleModel(pd.DataFrame([address]))
  
          self.proxyModel = QSortFilterProxyModel(self)
          self.proxyModel.setSourceModel(self.schedule_model)
          self.proxyModel.setDynamicSortFilter(True)
  
          self.setModel(self.proxyModel)
  
          **"""
          HAVING LIMITS TO THE AMOUNT OF WIDGETS TABLE VIEW CAN HANDEL
          """
          dialog_delegate = ClickDelegate(self)
          self.setItemDelegateForColumn(2, dialog_delegate)
          self.setItemDelegateForColumn(3, dialog_delegate)
  
          # spin_delegate = DoubleSpinBoxDelegate()
          # self.setItemDelegateForColumn(4, spin_delegate)
  
          # CheckBox = CheckBoxDelegate(None)
          # self.setItemDelegateForColumn(5, CheckBox)
  
          data = ['programming', 'game_build', 'other']
          combo_delegate = ComboBoxDelegate()
          combo_delegate.setItems([str(row) for row in data])
          self.setItemDelegateForColumn(6, combo_delegate)**
  
          self.setSortingEnabled(True)
          self.setSelectionBehavior(QAbstractItemView.SelectRows)
          self.horizontalHeader().setStretchLastSection(True)
          self.verticalHeader().hide()
          self.setSelectionMode(QAbstractItemView.SingleSelection)
          self.proxyModel.sort(0, Qt.AscendingOrder)
          self.setSelectionBehavior(QAbstractItemView.SelectRows)
          self.setEditTriggers(QAbstractItemView.DoubleClicked)
  
          self.setSelectionMode(QAbstractItemView.SingleSelection)
  
          # self.selectionModel().selectionChanged.connect(self.selectionChanged)
  
          self.show()
  
  
  if __name__ == "__main__":
      import sys
      from PySide2.QtWidgets import QApplication
  
      app = QApplication(sys.argv)
      addressWidget = SchedulesViewer()
      addressWidget.show()
      sys.exit(app.exec_())
  </code></pre>
  
  <p>so please would someone help me understand what i'am i missing or not understanding, all that i want to achieve is to add the delegate's that have been hashed out and make it a editable table, but if i add either the spinbox or the checkbox delegate the app freezes and crashes so is there a limit as to how many delegate's the table view can handle or what i'am i doing wrong? Any help would be much appreciated please and thank you in advance.. </p>