[PyQt] QDateEdit, QStandardItemModel and empty date fields
J Barchan
jnbarchan at gmail.com
Tue Mar 5 08:43:49 GMT 2019
On Sun, 3 Mar 2019 at 15:57, Maurizio Berti <maurizio.berti at gmail.com>
wrote:
> Il giorno sab 2 mar 2019 alle ore 21:02 Sibylle Koczian <
> nulla.epistola at web.de> ha scritto:
>
>> How can I get a QDateEdit to show an empty date, or how can I clear the
>> date it shows?
>
> [...]
>
> Of course I can replace the QDateEdit with a QLineEdit and work with a
>> string representation of the date column throughout. Is that the only
>> solution?
>>
>
> QDateTimeEdit and its inherited QDateEdit/QTimeEdit all inherit from
> QAbstractSpinBox, which contains a "private" QLineEdit.
> While that is not publicly accessible, you can just use findChild() to get
> its reference.
> Here's a small example you can implement in a model view by using a
> delegate and checking for the data in the setEditorData() method:
>
> class ClearableDateEdit(QtWidgets.QDateEdit):
> def __init__(self, *args, **kwargs):
> QtWidgets.QDateEdit.__init__(self, *args, **kwargs)
> self.lineEdit = self.findChild(QtWidgets.QLineEdit)
> self.clear()
>
> def clear(self):
> self.lineEdit.setText('')
>
>
> class Widget(QtWidgets.QWidget):
> def __init__(self):
> QtWidgets.QWidget.__init__(self)
> layout = QtWidgets.QGridLayout()
> self.setLayout(layout)
> dateEdit = ClearableDateEdit()
> layout.addWidget(dateEdit)
> clearButton = QtWidgets.QPushButton('Clear date')
> layout.addWidget(clearButton)
> clearButton.clicked.connect(dateEdit.clear)
>
> There are some things you've to take into account, anyway, most
> importantly whenever the focus is get or lost or the cell is changed, which
> will require some control over the DateEdit widget *changed() signals and
> methods like dateTimeFromText(), and finally check everything before using
> setModelData.
>
> Maurizio
>
> --
> È difficile avere una convinzione precisa quando si parla delle ragioni
> del cuore. - "Sostiene Pereira", Antonio Tabucchi
> http://www.jidesk.net
> _______________________________________________
> PyQt mailing list PyQt at riverbankcomputing.com
> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>
You cannot have an empty QDateEdit, as per my topic long ago at
https://forum.qt.io/topic/86749/qdateedit-qabstractspinbox-blank-empty-value-problem
.
I had to deal with this. I did not take @Maurizio's approach. I do not
know what his solution does about QDateEdit.setData/data() for an empty
date, and other things. Until now I didn't know you could get at its
QLineEdit. For my part I chose to have a QLineEdit plus an associated ...
button to its right which leads to a modal dialog. I paste extracts below,
feel free to cannibalise it if you want my approach. If @Maurizio wishes
to criticize mine, that's fine, I will read and consider!
class JDateEdit(QWidget):
# Class to display an "editable date" widget
# It consists of a QLineEdit plus a "..." QPushButton
# which brings up a (modal) dialog to pick a date to copy into the line edit
# We have to use our own class and not the native Qt
"QDateEdit"+setCalendarPopup(True)
# because that does not allow a "blank/empty" date in any form,
# and we do need blank all over the place
# class variable for "editingFinished" signal
editingFinished = QtCore.pyqtSignal(name='editingFinished')
def __init__(self, parent=None):
super().__init__(parent)
self.minimumDate = None
self.maximumDate = None
# lineEdit holds the date
self.lineEdit = JLineEdit(self)
# "..." button, when clicked will bring up a dialog with a
QCalendarWidget
self.button = JDotDotDotButton(self)
# connect self.lineEdit.editingFinished signal to
self.editingFinished signal
self.lineEdit.editingFinished.connect(self.editingFinished)
layout = QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
layout.addWidget(self.lineEdit)
layout.addWidget(self.button)
layout.addStretch(1)
self.setLayout(layout)
self.button.clicked.connect(self.doDialog)
self.dialog = None
def doDialog(self):
self.dialog = JCalendarDialog(self.button)
if self.minimumDate:
self.dialog.calendar.setMinimumDate(self.minimumDate)
if self.maximumDate:
self.dialog.calendar.setMaximumDate(self.maximumDate)
date = self.date()
if date is not None:
self.dialog.setSelectedDate(pyDateToQDate(date))
pos = self.button.rect().topLeft()
pos = self.button.mapToGlobal(pos)
self.dialog.move(pos)
if self.dialog.exec():
date = qDateToPyDate(self.dialog.selectedDate())
# copy the selected date to the line edit
self.setDate(date)
# and emit the editingFinished signal
self.lineEdit.editingFinished.emit()
self.dialog = None
def setReadOnly(self, ro: bool):
self.lineEdit.setReadOnly(ro)
if ro:
self.button.hide()
else:
self.button.show()
def setDate(self, date: typing.Union[datetime.date, None]):
# Set the date
# Accepts None for the date, and sets it blank
if date is None:
self.lineEdit.setText("")
else:
self.lineEdit.setText(dateToStr(date))
def date(self) -> typing.Union[datetime.date, None]:
# Return the date
# If the date is blank, or if it fails to parse in
parseDateSoft(), return None
text = self.lineEdit.text()
if text == "":
return None
return parseDateSoft(text)
def dateOrWarn(self) -> typing.Union[datetime.date, None]:
# Return the date, which *should* be filled in
# If the date is blank, or if it fails to parse,
# put up an ErrorMsgBox() and then return None
text = self.lineEdit.text()
return parseDateHard(text, self.lineEdit)
def dateOrError(self) -> datetime.date:
# Return the date, which *must* be filled in
# If the date is blank, or if it fails to parse,
# put up an ErrorMsgBox() and then raise an exception
text = self.lineEdit.text()
date = parseDateHard(text, self.lineEdit)
if date is None:
raise ValueError("Valid date required")
return date
def clear(self):
self.lineEdit.clear()
def setText(self, a0: str):
self.lineEdit.setText(a0)
def text(self) -> str:
return self.lineEdit.text()
def setMinimumDate(self, date: typing.Union[datetime.date, None]):
self.minimumDate = date
def setMaximumDate(self, date: typing.Union[datetime.date, None]):
self.maximumDate = date
--
Kindest,
Jonathan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190305/3d63b148/attachment-0001.html>
More information about the PyQt
mailing list