Results 1 to 3 of 3

Thread: Delegate does not invoke setModelData() method

  1. #1
    Join Date
    Mar 2014
    Posts
    6
    Qt products
    Qt4
    Platforms
    Windows

    Default Delegate does not invoke setModelData() method

    I have an application in which I read and write to disk using data from a custom tree model. The model data is mapped to widgets on a standard form UI using QDataWidgetMapper. I noticed that the data reads in perfectly--except for QComboBox widgets. (The model holds the data just fine--it's the widget that doesn't properly display it.) After doing some searching, it seems that these require a custom delegate in order for the editor data to be correctly set from the model. I decided to test this out by developing a very simple form backed by a QAbstractTableModel. I have mostly followed this tutorial: http://doc.qt.digia.com/qq/qq21-datawidgetmapper.html ; my code (Python 2.7.3/PySide 1.2.1) is below:

    Qt Code:
    1. #!/usr/bin/python
    2. from PySide.QtCore import *
    3. from PySide.QtGui import *
    4. import sys
    5.  
    6. # Since the delegate only needs to communicate information between the model and the widget mapper,
    7. # we only need to provide implementations of the setEditorData() and setModelData() functions
    8. class CustomDelegate(QAbstractItemDelegate):
    9.  
    10. def __init__(self, parent=None):
    11. super(CustomDelegate, self).__init__(parent)
    12.  
    13. def setEditorData(self, editor, index):
    14. if editor.property("currentIndex") is not None:
    15. value = index.data(Qt.DisplayRole)
    16. editor.setProperty("currentIndex", index.data())
    17. return
    18. text = index.model().data(index, Qt.DisplayRole)
    19. editor.setText(text)
    20.  
    21. def setModelData(self, editor, model, index):
    22. print 'setting model data'
    23. if editor.property("currentIndex") is not None:
    24. return
    25. model.setData(index, editor.currentText(), Qt.EditRole)
    26.  
    27. class TableModel(QAbstractTableModel):
    28.  
    29. def __init__(self, data=None, parent=None):
    30. super(TableModel, self).__init__(parent)
    31. if data is not None:
    32. self.tbldata = data
    33. else:
    34. self.tbldata = [[]]
    35.  
    36. def rowCount(self, parent=QModelIndex()):
    37. return len(self.tbldata)
    38.  
    39. def columnCount(self, parent=QModelIndex()):
    40. return len(self.tbldata[0])
    41.  
    42. def data(self, index, role):
    43. if role == Qt.DisplayRole:
    44. return self.tbldata[index.row()][index.column()]
    45.  
    46. def flags(self, index):
    47. return Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsEnabled
    48.  
    49. def setData(self, index, value, role):
    50. if role == Qt.EditRole:
    51. self.tbldata[index.row()][index.column()] = value
    52. return True
    53. return False
    54.  
    55. class Form(QDialog):
    56.  
    57. def __init__(self, parent=None):
    58. super(Form, self).__init__(parent)
    59. self.setWindowTitle("Test mapping to QComboBox")
    60. tbldata = [
    61. ["Carol", "The Lighthouse", 1],
    62. ["Donald", "47338 Park Ave.", 2],
    63. ["Emma", "Research Station", 0]
    64. ]
    65. self.model = TableModel(tbldata)
    66. self.view = QTableView() # you have a view, but you won't add it as a widget to the layout
    67. self.view.setModel(self.model)
    68.  
    69. # create widgets
    70. name_label = QLabel("Name:")
    71. address_label = QLabel("Address:")
    72. type_label = QLabel("Type:")
    73. self.name_edit = QLineEdit()
    74. self.address_edit = QLineEdit()
    75. self.type_combo = QComboBox()
    76. self.type_combo.addItems(["0", "1", "2"])
    77. prev_button = QPushButton("Previous")
    78. next_button = QPushButton("Next")
    79. change_button = QPushButton("Change Data")
    80.  
    81. layout = QGridLayout()
    82. layout.addWidget(name_label, 0, 0)
    83. layout.addWidget(self.name_edit, 0, 1)
    84. layout.addWidget(prev_button, 0, 2)
    85. layout.addWidget(address_label, 1, 0)
    86. layout.addWidget(self.address_edit, 1, 1)
    87. layout.addWidget(next_button, 1, 2)
    88. layout.addWidget(type_label, 2, 0)
    89. layout.addWidget(self.type_combo, 2, 1)
    90. layout.addWidget(change_button, 2, 2)
    91. self.setLayout(layout)
    92.  
    93. # mapper
    94. self.mapper = QDataWidgetMapper()
    95. self.mapper.setModel(self.model)
    96. self.delegate = CustomDelegate()
    97. self.mapper.setItemDelegate(self.delegate)
    98. self.mapper.addMapping(self.name_edit, 0)
    99. self.mapper.addMapping(self.address_edit, 1)
    100. self.mapper.addMapping(self.type_combo, 2)
    101. self.mapper.setCurrentIndex(0)
    102.  
    103. # connections
    104. prev_button.clicked.connect(self.goPrevRecord)
    105. next_button.clicked.connect(self.goNextRecord)
    106. change_button.clicked.connect(self.changeData)
    107.  
    108. def goPrevRecord(self):
    109. self.mapper.toPrevious()
    110.  
    111. def goNextRecord(self):
    112. self.mapper.toNext()
    113.  
    114. def changeData(self):
    115. self.model.tbldata = [
    116. ["Paul", "72 Main St.", 2],
    117. ["John", "473 Wabash Ave.", 2],
    118. ["Jenny", "Outer Space", 0]
    119. ]
    120.  
    121. app = QApplication(sys.argv)
    122. form = Form()
    123. form.show()
    124. app.exec_()
    To copy to clipboard, switch view to plain text mode 

    Everything runs perfectly -- except that I'm unable to write data back to the model from the widgets! I put a print statement in the setModelData() method of the delegate to see whether the method is ever called, and it doesn't seem to be. And if it's not called, that would certainly explain why no edits go through to the model!

    The Trolltech tutorial I linked to makes it a point that all I should need to re-implement are the setEditorData() and setModelData() methods, but it seems as though I am missing something elementary, and a few hours of searching (and continued tinkering) has turned up nothing. If anyone can help point me in the right direction, I would deeply appreciate it!

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Delegate does not invoke setModelData() method

    I am not sure you need a delegate.

    You problem seems to be that your model has an integer in the column that you map into the combobox, but you haven't set the mapping to the "currentIndex" property:
    Qt Code:
    1. self.mapper.addMapping(self.type_combo, 2)
    To copy to clipboard, switch view to plain text mode 
    this creates a mapping between the type_combo widget and column 2 of the model, using the default property of the widget.
    In the case of QComboBox that is "currentText".

    What you could try instead of using a delegate is to map to the combobox "currentIndex" property:
    Qt Code:
    1. self.mapper.addMapping(self.type_combo, 2, "currentIndex")
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

  3. #3
    Join Date
    Mar 2014
    Posts
    6
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Delegate does not invoke setModelData() method

    Quote Originally Posted by anda_skoa View Post
    I am not sure you need a delegate.

    You problem seems to be that your model has an integer in the column that you map into the combobox, but you haven't set the mapping to the "currentIndex" property:
    Qt Code:
    1. self.mapper.addMapping(self.type_combo, 2)
    To copy to clipboard, switch view to plain text mode 
    this creates a mapping between the type_combo widget and column 2 of the model, using the default property of the widget.
    In the case of QComboBox that is "currentText".

    What you could try instead of using a delegate is to map to the combobox "currentIndex" property:
    Qt Code:
    1. self.mapper.addMapping(self.type_combo, 2, "currentIndex")
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _
    Thank you for the reply. I only had integers there because I had meant to implement something akin to the example in the Trolltech tutorial I linked to (where the QComboBox has its own QStringListModel, and the delegate maps indexes to actual text-based choices) but became stuck on the problem with setModelData. The same tutorial makes the following point:

    For widgets that only hold one piece of information, like QLineEdit and the others used in the previous example, using a widget mapper is straightforward. However, for widgets that present choices to the user, such as QComboBox, we need to think about how the list of choices is stored, and how the mapper will update the widget when a choice is made....To manage this relationship, we need to introduce another common model/view component: a delegate.
    Fortunately, the setEditorData function appears to work well: the correct integers are set in the comboboxes when I run the script, and the correct text is set in the line edit widgets. The problem remains in writing back to the model...I assumed that any time any widget data is changed that the delegate would automatically invoke the setModelData function, but it seems that that's not the case, unless I'm screwing up the re-implementation somehow.

    EDIT: On a whim I changed the parent class of my custom delegate to QItemDelegate rather than QAbstractItemDelegate (the former being a subclass of the latter), and now the setModelData() method works! Not sure why that is the case, but I'm happy to have this resolved!
    Last edited by tristam; 8th March 2014 at 19:43.

Similar Threads

  1. Model/View/Delegate How gets setEditorData / setModelData
    By moviemax in forum Qt Programming
    Replies: 0
    Last Post: 11th July 2011, 11:29
  2. Replies: 1
    Last Post: 28th October 2009, 18:42
  3. QTreeWidget Delegate setModelData limitations
    By kubas in forum Qt Programming
    Replies: 0
    Last Post: 8th September 2009, 08:40
  4. QThread::start() doesn't invoke run() method
    By seim in forum Qt Programming
    Replies: 2
    Last Post: 5th February 2009, 17:09
  5. setModelData for subclassed QItemDelegate
    By T4ng10r in forum Qt Programming
    Replies: 7
    Last Post: 27th May 2007, 12:09

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.