[PyQt] SystemLocaleShortDate omits the century on Linux

Maurizio Berti maurizio.berti at gmail.com
Sat Mar 14 15:42:26 GMT 2020


>
> > /However/, I was screamed at over at the Qt forum.  The experts told me
> > in no uncertain terms that this was /not/ the thing to do, to get a
> > string format for a type which you wanted.  They insisted I should be
> > doing it via QStyledItemDelegate, for whatever view I was in.  I should
> > not handle the data(Qt.DisplayRole) and return a string, I should leave
> > that (like Qt.EditRole) returning the underlying value type, not my
> > desired format.  Indeed, they basically said the only time I should
> > separate, say, DisplayRolefrom EditRole, is the kind of case quoted I
> > think in the docs, where you have a spreadsheet with formulae and the
> > thing you edit (the formula) is effectively quite a different data item
> > from the number you end up displaying when evaluated.
>

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).
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.
The code example in the official documentation shows this specific case
(ironically, I'd add): representing a date in a string format (
https://doc.qt.io/qt-5/qidentityproxymodel.html#details ). So I really
don't understand such an overzealous response from the Qt forums.


> I don't know what exactly the Qt experts had in mind, but for my
> application overriding data (or setData) in fact creates a problem:
>
> The data come from a PostgreSQL database and the date fields are
> converted to QDate on import into the model (a QStandardItemModel
> subclass). They are not edited in the table, but in a separate entry
> form which contains a QDateEdit for the date field. This is only
> sometimes changed, not in every edit of a record. After all the edits
> are done, the model data are exported, the dates converted to strings
> using the ISODate format, and then the database records are updated.
>
> This is why I don't want to keep the dates as strings in the model: the
> QDateEdit is quite comfortable to use, but it puts QDates into the model
> - if and only if the date has been changed, as far as I can see. So I
> get a mixture of strings and QDates in my exported list, which isn't
> helpful. While QDates in the model can be used through all the
> application, converted only at the start and at the end.
>
> So only one question remains: how best to subclass QStyledItemDelegate.
> Which method is the right one, where can I find an example which just
> changes the displayed string format?
>

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.
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).

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).

class Test(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        layout = QtWidgets.QVBoxLayout(self)

        formatEdit = QtWidgets.QLineEdit()
        layout.addWidget(formatEdit)

        table = QtWidgets.QTableView()
        layout.addWidget(table)
        table.setEditTriggers(table.NoEditTriggers)
        table.doubleClicked.connect(self.startEditDate)

        model = QtGui.QStandardItemModel()
        model.setHorizontalHeaderLabels(['Date', 'Something'])

        for row in range(10):
            dateItem = QtGui.QStandardItem()
            d = QtCore.QDate(randrange(2000, 2021), randrange(1, 13),
randrange(1, 29))
            dateItem.setData(d, QtCore.Qt.DisplayRole)
            model.appendRow([dateItem, QtGui.QStandardItem('something')])

        self.dateEdit = QtWidgets.QDateEdit()
        layout.addWidget(self.dateEdit)
        self.dateEdit.setEnabled(False)
        self.dateEdit.editingFinished.connect(self.submitDate)

        self.proxy = DateProxyModel()
        self.proxy.setSourceModel(model)
        table.setModel(self.proxy)

        formatEdit.setPlaceholderText(self.proxy.dateFormat())
        formatEdit.textChanged.connect(self.proxy.setDateFormat)

        self.currentIndex = None

    def startEditDate(self, tableIndex):
        sourceIndex = self.proxy.mapToSource(tableIndex)
        if isinstance(sourceIndex.data(), QtCore.QDate):
            self.dateEdit.setEnabled(True)
            self.dateEdit.setDate(sourceIndex.data())
            self.currentIndex = sourceIndex
            self.dateEdit.setFocus()
        else:
            self.dateEdit.setEnabled(False)
            self.currentIndex = None

    def submitDate(self):
        if self.currentIndex is not None:
            self.proxy.sourceModel().setData(self.currentIndex,
self.dateEdit.date())
        self.dateEdit.setEnabled(False)

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.

Maurizio
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20200314/469036bc/attachment.htm>


More information about the PyQt mailing list