<div dir="ltr"><div dir="ltr"><div style="font-family:tahoma,sans-serif" class="gmail_default"></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, 3 Mar 2019 at 15:57, Maurizio Berti <<a href="mailto:maurizio.berti@gmail.com">maurizio.berti@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">Il giorno sab 2 mar 2019 alle ore 21:02 Sibylle Koczian <<a href="mailto:nulla.epistola@web.de" target="_blank">nulla.epistola@web.de</a>> ha scritto:<br></div><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">How can I get a QDateEdit to show an empty date, or how can I clear the<br>
date it shows? </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">[...]</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Of course I can replace the QDateEdit with a QLineEdit and work with a<br>
string representation of the date column throughout. Is that the only<br>
solution?<br></blockquote><div><br></div><div>QDateTimeEdit and its inherited QDateEdit/QTimeEdit all inherit from QAbstractSpinBox, which contains a "private" QLineEdit.<br></div><div>While that is not publicly accessible, you can just use findChild() to get its reference.</div><div>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:</div><div><br></div><div><div><font face="monospace, monospace">class ClearableDateEdit(QtWidgets.QDateEdit):</font></div><div><font face="monospace, monospace">    def __init__(self, *args, **kwargs):</font></div><div><font face="monospace, monospace">        QtWidgets.QDateEdit.__init__(self, *args, **kwargs)</font></div><div><font face="monospace, monospace">        self.lineEdit = self.findChild(QtWidgets.QLineEdit)</font></div><div><font face="monospace, monospace">        self.clear()</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">    def clear(self):</font></div><div><font face="monospace, monospace">        self.lineEdit.setText('')</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">class Widget(QtWidgets.QWidget):</font></div><div><font face="monospace, monospace">    def __init__(self):</font></div><div><font face="monospace, monospace">        QtWidgets.QWidget.__init__(self)</font></div><div><font face="monospace, monospace">        layout = QtWidgets.QGridLayout()</font></div><div><font face="monospace, monospace">        self.setLayout(layout)</font></div><div><font face="monospace, monospace">        dateEdit = ClearableDateEdit()</font></div><div><font face="monospace, monospace">        layout.addWidget(dateEdit)</font></div><div><font face="monospace, monospace">        clearButton = QtWidgets.QPushButton('Clear date')</font></div><div><font face="monospace, monospace">        layout.addWidget(clearButton)</font></div><div><font face="monospace, monospace">        clearButton.clicked.connect(dateEdit.clear)</font></div></div><div><br></div><div>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.</div><div><br></div><div>Maurizio</div><div><br></div><div>-- <br></div></div><div dir="ltr" class="gmail-m_430176785845214760gmail_signature">È difficile avere una convinzione precisa quando si parla delle ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi<br><a href="http://www.jidesk.net" target="_blank">http://www.jidesk.net</a></div></div></div></div>
_______________________________________________<br>
PyQt mailing list    <a href="mailto:PyQt@riverbankcomputing.com" target="_blank">PyQt@riverbankcomputing.com</a><br>
<a href="https://www.riverbankcomputing.com/mailman/listinfo/pyqt" rel="noreferrer" target="_blank">https://www.riverbankcomputing.com/mailman/listinfo/pyqt</a><br>
</blockquote></div><div><br></div><div><div style="font-family:tahoma,sans-serif" class="gmail_default"><div style="font-family:tahoma,sans-serif" class="gmail_default"></div><div dir="ltr"><div class="gmail_default" style="font-family:tahoma,sans-serif">You cannot have an empty <span style="font-family:monospace,monospace">QDateEdit</span>, as per my topic long ago at <a href="https://forum.qt.io/topic/86749/qdateedit-qabstractspinbox-blank-empty-value-problem">https://forum.qt.io/topic/86749/qdateedit-qabstractspinbox-blank-empty-value-problem</a>.<br></div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">I had to deal with this.  I did not take @Maurizio's approach.  I do not know what his solution does about <span style="font-family:monospace,monospace">QDateEdit.setData/data()</span> for an empty date, and other things.  Until now I didn't know you could get at its <span style="font-family:monospace,monospace">QLineEdit</span>.  For my part I chose to have a <span style="font-family:monospace,monospace">QLineEdit</span> plus an associated <span style="font-family:monospace,monospace">...</span>
 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!</div></div></div></div><div><br></div><div><div style="font-family:tahoma,sans-serif" class="gmail_default"><pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:"DejaVu Sans Mono";font-size:9pt"><span style="color:rgb(0,0,128);font-weight:bold">class </span>JDateEdit(QWidget):<br>    <span style="color:rgb(128,128,128);font-style:italic"># Class to display an "editable date" widget<br></span><span style="color:rgb(128,128,128);font-style:italic">    # It consists of a QLineEdit plus a "..." QPushButton<br></span><span style="color:rgb(128,128,128);font-style:italic">    # which brings up a (modal) dialog to pick a date to copy into the line edit<br></span><span style="color:rgb(128,128,128);font-style:italic">    # We have to use our own class and not the native Qt "QDateEdit"+setCalendarPopup(True)<br></span><span style="color:rgb(128,128,128);font-style:italic">    # because that does not allow a "blank/empty" date in any form,<br></span><span style="color:rgb(128,128,128);font-style:italic">    # and we do need blank all over the place<br></span><span style="color:rgb(128,128,128);font-style:italic"><br></span><span style="color:rgb(128,128,128);font-style:italic">    # class variable for "editingFinished" signal<br></span><span style="color:rgb(128,128,128);font-style:italic">    </span>editingFinished = QtCore.pyqtSignal(<span style="color:rgb(102,0,153)">name</span>=<span style="color:rgb(0,128,128);font-weight:bold">'editingFinished'</span>)<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">def </span><span style="color:rgb(178,0,178)">__init__</span>(<span style="color:rgb(148,85,141)">self</span>, parent=<span style="color:rgb(0,0,128);font-weight:bold">None</span>):<br>        <span style="color:rgb(0,0,128)">super</span>().<span style="color:rgb(178,0,178)">__init__</span>(parent)<br><br>        <span style="color:rgb(148,85,141)">self</span>.minimumDate = <span style="color:rgb(0,0,128);font-weight:bold">None<br></span><span style="color:rgb(0,0,128);font-weight:bold">        </span><span style="color:rgb(148,85,141)">self</span>.maximumDate = <span style="color:rgb(0,0,128);font-weight:bold">None<br></span><span style="color:rgb(0,0,128);font-weight:bold"><br></span><span style="color:rgb(0,0,128);font-weight:bold">        </span><span style="color:rgb(128,128,128);font-style:italic"># lineEdit holds the date<br></span><span style="color:rgb(128,128,128);font-style:italic">        </span><span style="color:rgb(148,85,141)">self</span>.lineEdit = JLineEdit(<span style="color:rgb(148,85,141)">self</span>)<br>        <span style="color:rgb(128,128,128);font-style:italic"># "..." button, when clicked will bring up a dialog with a QCalendarWidget<br></span><span style="color:rgb(128,128,128);font-style:italic">        </span><span style="color:rgb(148,85,141)">self</span>.button = JDotDotDotButton(<span style="color:rgb(148,85,141)">self</span>)<br><br>        <span style="color:rgb(128,128,128);font-style:italic"># connect self.lineEdit.editingFinished signal to self.editingFinished signal<br></span><span style="color:rgb(128,128,128);font-style:italic">        </span><span style="color:rgb(148,85,141)">self</span>.lineEdit.editingFinished.connect(<span style="color:rgb(148,85,141)">self</span>.editingFinished)<br><br>        layout = QHBoxLayout(<span style="color:rgb(148,85,141)">self</span>)<br>        layout.setContentsMargins(<span style="color:rgb(0,0,255)">0</span>, <span style="color:rgb(0,0,255)">0</span>, <span style="color:rgb(0,0,255)">0</span>, <span style="color:rgb(0,0,255)">0</span>)<br>        layout.setSpacing(<span style="color:rgb(0,0,255)">0</span>)<br>        layout.addWidget(<span style="color:rgb(148,85,141)">self</span>.lineEdit)<br>        layout.addWidget(<span style="color:rgb(148,85,141)">self</span>.button)<br>        layout.addStretch(<span style="color:rgb(0,0,255)">1</span>)<br>        <span style="color:rgb(148,85,141)">self</span>.setLayout(layout)<br><br>        <span style="color:rgb(148,85,141)">self</span>.button.clicked.connect(<span style="color:rgb(148,85,141)">self</span>.doDialog)<br>        <span style="color:rgb(148,85,141)">self</span>.dialog = <span style="color:rgb(0,0,128);font-weight:bold">None<br></span><span style="color:rgb(0,0,128);font-weight:bold"><br></span><span style="color:rgb(0,0,128);font-weight:bold">    def </span>doDialog(<span style="color:rgb(148,85,141)">self</span>):<br>        <span style="color:rgb(148,85,141)">self</span>.dialog = JCalendarDialog(<span style="color:rgb(148,85,141)">self</span>.button)<br>        <span style="color:rgb(0,0,128);font-weight:bold">if </span><span style="color:rgb(148,85,141)">self</span>.minimumDate:<br>            <span style="color:rgb(148,85,141)">self</span>.dialog.calendar.setMinimumDate(<span style="color:rgb(148,85,141)">self</span>.minimumDate)<br>        <span style="color:rgb(0,0,128);font-weight:bold">if </span><span style="color:rgb(148,85,141)">self</span>.maximumDate:<br>            <span style="color:rgb(148,85,141)">self</span>.dialog.calendar.setMaximumDate(<span style="color:rgb(148,85,141)">self</span>.maximumDate)<br>        date = <span style="color:rgb(148,85,141)">self</span>.date()<br>        <span style="color:rgb(0,0,128);font-weight:bold">if </span>date <span style="color:rgb(0,0,128);font-weight:bold">is not None</span>:<br>            <span style="color:rgb(148,85,141)">self</span>.dialog.setSelectedDate(pyDateToQDate(date))<br>        pos = <span style="color:rgb(148,85,141)">self</span>.button.rect().topLeft()<br>        pos = <span style="color:rgb(148,85,141)">self</span>.button.mapToGlobal(pos)<br>        <span style="color:rgb(148,85,141)">self</span>.dialog.move(pos)<br>        <span style="color:rgb(0,0,128);font-weight:bold">if </span><span style="color:rgb(148,85,141)">self</span>.dialog.exec():<br>            date = qDateToPyDate(<span style="color:rgb(148,85,141)">self</span>.dialog.selectedDate())<br>            <span style="color:rgb(128,128,128);font-style:italic"># copy the selected date to the line edit<br></span><span style="color:rgb(128,128,128);font-style:italic">            </span><span style="color:rgb(148,85,141)">self</span>.setDate(date)<br>            <span style="color:rgb(128,128,128);font-style:italic"># and emit the editingFinished signal<br></span><span style="color:rgb(128,128,128);font-style:italic">            </span><span style="color:rgb(148,85,141)">self</span>.lineEdit.editingFinished.emit()<br>        <span style="color:rgb(148,85,141)">self</span>.dialog = <span style="color:rgb(0,0,128);font-weight:bold">None<br></span><span style="color:rgb(0,0,128);font-weight:bold"><br></span><span style="color:rgb(0,0,128);font-weight:bold">    def </span>setReadOnly(<span style="color:rgb(148,85,141)">self</span>, ro: <span style="color:rgb(0,0,128)">bool</span>):<br>        <span style="color:rgb(148,85,141)">self</span>.lineEdit.setReadOnly(ro)<br>        <span style="color:rgb(0,0,128);font-weight:bold">if </span>ro:<br>            <span style="color:rgb(148,85,141)">self</span>.button.hide()<br>        <span style="color:rgb(0,0,128);font-weight:bold">else</span>:<br>            <span style="color:rgb(148,85,141)">self</span>.button.show()<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">def </span>setDate(<span style="color:rgb(148,85,141)">self</span>, date: typing.Union[datetime.date, <span style="color:rgb(0,0,128);font-weight:bold">None</span>]):<br>        <span style="color:rgb(128,128,128);font-style:italic"># Set the date<br></span><span style="color:rgb(128,128,128);font-style:italic">        # Accepts None for the date, and sets it blank<br></span><span style="color:rgb(128,128,128);font-style:italic">        </span><span style="color:rgb(0,0,128);font-weight:bold">if </span>date <span style="color:rgb(0,0,128);font-weight:bold">is None</span>:<br>            <span style="color:rgb(148,85,141)">self</span>.lineEdit.setText(<span style="color:rgb(0,128,128);font-weight:bold">""</span>)<br>        <span style="color:rgb(0,0,128);font-weight:bold">else</span>:<br>            <span style="color:rgb(148,85,141)">self</span>.lineEdit.setText(dateToStr(date))<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">def </span>date(<span style="color:rgb(148,85,141)">self</span>) -> typing.Union[datetime.date, <span style="color:rgb(0,0,128);font-weight:bold">None</span>]:<br>        <span style="color:rgb(128,128,128);font-style:italic"># Return the date<br></span><span style="color:rgb(128,128,128);font-style:italic">        # If the date is blank, or if it fails to parse in parseDateSoft(), return None<br></span><span style="color:rgb(128,128,128);font-style:italic">        </span>text = <span style="color:rgb(148,85,141)">self</span>.lineEdit.text()<br>        <span style="color:rgb(0,0,128);font-weight:bold">if </span>text == <span style="color:rgb(0,128,128);font-weight:bold">""</span>:<br>            <span style="color:rgb(0,0,128);font-weight:bold">return None<br></span><span style="color:rgb(0,0,128);font-weight:bold">        return </span>parseDateSoft(text)<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">def </span>dateOrWarn(<span style="color:rgb(148,85,141)">self</span>) -> typing.Union[datetime.date, <span style="color:rgb(0,0,128);font-weight:bold">None</span>]:<br>        <span style="color:rgb(128,128,128);font-style:italic"># Return the date, which *should* be filled in<br></span><span style="color:rgb(128,128,128);font-style:italic">        # If the date is blank, or if it fails to parse,<br></span><span style="color:rgb(128,128,128);font-style:italic">        # put up an ErrorMsgBox() and then return None<br></span><span style="color:rgb(128,128,128);font-style:italic">        </span>text = <span style="color:rgb(148,85,141)">self</span>.lineEdit.text()<br>        <span style="color:rgb(0,0,128);font-weight:bold">return </span>parseDateHard(text, <span style="color:rgb(148,85,141)">self</span>.lineEdit)<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">def </span>dateOrError(<span style="color:rgb(148,85,141)">self</span>) -> datetime.date:<br>        <span style="color:rgb(128,128,128);font-style:italic"># Return the date, which *must* be filled in<br></span><span style="color:rgb(128,128,128);font-style:italic">        # If the date is blank, or if it fails to parse,<br></span><span style="color:rgb(128,128,128);font-style:italic">        # put up an ErrorMsgBox() and then raise an exception<br></span><span style="color:rgb(128,128,128);font-style:italic">        </span>text = <span style="color:rgb(148,85,141)">self</span>.lineEdit.text()<br>        date = parseDateHard(text, <span style="color:rgb(148,85,141)">self</span>.lineEdit)<br>        <span style="color:rgb(0,0,128);font-weight:bold">if </span>date <span style="color:rgb(0,0,128);font-weight:bold">is None</span>:<br>            <span style="color:rgb(0,0,128);font-weight:bold">raise </span><span style="color:rgb(0,0,128)">ValueError</span>(<span style="color:rgb(0,128,128);font-weight:bold">"Valid date required"</span>)<br>        <span style="color:rgb(0,0,128);font-weight:bold">return </span>date<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">def </span>clear(<span style="color:rgb(148,85,141)">self</span>):<br>        <span style="color:rgb(148,85,141)">self</span>.lineEdit.clear()<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">def </span>setText(<span style="color:rgb(148,85,141)">self</span>, a0: <span style="color:rgb(0,0,128)">str</span>):<br>        <span style="color:rgb(148,85,141)">self</span>.lineEdit.setText(a0)<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">def </span>text(<span style="color:rgb(148,85,141)">self</span>) -> <span style="color:rgb(0,0,128)">str</span>:<br>        <span style="color:rgb(0,0,128);font-weight:bold">return </span><span style="color:rgb(148,85,141)">self</span>.lineEdit.text()<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">def </span>setMinimumDate(<span style="color:rgb(148,85,141)">self</span>, date: typing.Union[datetime.date, <span style="color:rgb(0,0,128);font-weight:bold">None</span>]):<br>        <span style="color:rgb(148,85,141)">self</span>.minimumDate = date<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">def </span>setMaximumDate(<span style="color:rgb(148,85,141)">self</span>, date: typing.Union[datetime.date, <span style="color:rgb(0,0,128);font-weight:bold">None</span>]):<br>        <span style="color:rgb(148,85,141)">self</span>.maximumDate = date<br><br></pre></div><br></div><br>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><span style="font-family:tahoma,sans-serif">Kindest,</span></div><div><span style="font-family:tahoma,sans-serif">Jonathan</span></div></div></div></div></div></div>