<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">> /However/, I was screamed at over at the Qt forum. The experts told me<br>
> in no uncertain terms that this was /not/ the thing to do, to get a<br>
> string format for a type which you wanted. They insisted I should be<br>
> doing it via QStyledItemDelegate, for whatever view I was in. I should<br>
> not handle the data(Qt.DisplayRole) and return a string, I should leave<br>
> that (like Qt.EditRole) returning the underlying value type, not my<br>
> desired format. Indeed, they basically said the only time I should<br>
> separate, say, DisplayRolefrom EditRole, is the kind of case quoted I<br>
> think in the docs, where you have a spreadsheet with formulae and the<br>
> thing you edit (the formula) is effectively quite a different data item<br>
> from the number you end up displaying when evaluated.<br></blockquote><div><br></div><div>I could partially agree, but there's always some "level" of tolerance to those paradigms depending on the situation. If you have complete control over the way the model is accessed in read/write, I strongly believe that overriding the paint method is simply an overshoot (especially for very big tables with *a lot* of visible cells).</div><div>While it is true that the conversion only happens for painting and geometry reasons in basic classes of item views, the documentation clearly says that DisplayRole is the "key data to be rendered in form of text", and that's exactly what QIdentityProxyModel is intended for.</div><div>The code example in the official documentation shows this specific case (ironically, I'd add): representing a date in a string format ( <a href="https://doc.qt.io/qt-5/qidentityproxymodel.html#details">https://doc.qt.io/qt-5/qidentityproxymodel.html#details</a> ). So I really don't understand such an overzealous response from the Qt forums.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I don't know what exactly the Qt experts had in mind, but for my<br>
application overriding data (or setData) in fact creates a problem:<br>
<br>
The data come from a PostgreSQL database and the date fields are<br>
converted to QDate on import into the model (a QStandardItemModel<br>
subclass). They are not edited in the table, but in a separate entry<br>
form which contains a QDateEdit for the date field. This is only<br>
sometimes changed, not in every edit of a record. After all the edits<br>
are done, the model data are exported, the dates converted to strings<br>
using the ISODate format, and then the database records are updated.<br>
<br>
This is why I don't want to keep the dates as strings in the model: the<br>
QDateEdit is quite comfortable to use, but it puts QDates into the model<br>
- if and only if the date has been changed, as far as I can see. So I<br>
get a mixture of strings and QDates in my exported list, which isn't<br>
helpful. While QDates in the model can be used through all the<br>
application, converted only at the start and at the end.<br>
<br>
So only one question remains: how best to subclass QStyledItemDelegate.<br>
Which method is the right one, where can I find an example which just<br>
changes the displayed string format?<br></blockquote><div><br></div><div>Sorry, I'm not sure I've understood; if the dates from the database are converted to QDate and then stored as strings when converted back, there shouldn't be any problem using a QIdentityProxyModel: the source data is never changed, only how it's displayed on the table.</div><div>Then, if you want to edit a date in a separate form using the index provided by the table (for example by double clicking on a cell/row), you can access the actual QDate by using sourceIndex = proxyModel.mapToSource(tableIndex).</div><div></div><div><br></div><div>The following example is based on the previous one (without the delegate, since you said that you don't want to edit the date in the table): when an item is double clicked it maps the index to the source model, and if the display role returns a QDate it enables the QDateEdit; then it stores the data in the *source* model as a QDate when the date editing finishes (note that editingFinished is called for both enter/return key press and loss of focus, but this is just an example).<br></div><div><br></div><font face="monospace">class Test(QtWidgets.QWidget):<br> def __init__(self):<br> super().__init__()<br> layout = QtWidgets.QVBoxLayout(self)<br><br> formatEdit = QtWidgets.QLineEdit()<br> layout.addWidget(formatEdit)<br><br> table = QtWidgets.QTableView()<br> layout.addWidget(table)<br> table.setEditTriggers(table.NoEditTriggers)<br> table.doubleClicked.connect(self.startEditDate)<br><br> model = QtGui.QStandardItemModel()<br> model.setHorizontalHeaderLabels(['Date', 'Something'])<br><br> for row in range(10):<br> dateItem = QtGui.QStandardItem()<br> d = QtCore.QDate(randrange(2000, 2021), randrange(1, 13), randrange(1, 29))<br> dateItem.setData(d, QtCore.Qt.DisplayRole)<br> model.appendRow([dateItem, QtGui.QStandardItem('something')])<br><br> self.dateEdit = QtWidgets.QDateEdit()<br> layout.addWidget(self.dateEdit)<br> self.dateEdit.setEnabled(False)<br> self.dateEdit.editingFinished.connect(self.submitDate)<br><br> self.proxy = DateProxyModel()<br> self.proxy.setSourceModel(model)<br> table.setModel(self.proxy)<br><br> formatEdit.setPlaceholderText(self.proxy.dateFormat())<br> formatEdit.textChanged.connect(self.proxy.setDateFormat)<br><br> self.currentIndex = None<br><br> def startEditDate(self, tableIndex):<br> sourceIndex = self.proxy.mapToSource(tableIndex)<br> if isinstance(sourceIndex.data(), QtCore.QDate):<br> self.dateEdit.setEnabled(True)<br> self.dateEdit.setDate(sourceIndex.data())<br> self.currentIndex = sourceIndex<br> self.dateEdit.setFocus()<br> else:<br> self.dateEdit.setEnabled(False)<br> self.currentIndex = None<br><br> def submitDate(self):<br> if self.currentIndex is not None:<br> self.proxy.sourceModel().setData(self.currentIndex, self.dateEdit.date())<br> self.dateEdit.setEnabled(False)</font></div><div class="gmail_quote"><font face="monospace"><br></font></div><div class="gmail_quote">In this way, the dates on the source model will always be QDate objects for both reading and writing, and you can choose the way the dates are *displayed* without affecting the actual data for the model and the exported data.<font face="monospace"><br></font></div><div class="gmail_quote"><br></div><div class="gmail_quote">Maurizio</div></div></div></div></div></div></div></div>