QTimeEdit opens with the selected section being hours
-
I have a table item editor delegate set to edit an exposure time field.
The QTimeEdit display format is set to "hh:mm:ss".The code to insert the model data reads:
int secs{ index.model()->data(index, Qt::EditRole).toInt() }; if (secs > 66399) secs = 86399; // 24 hours less 1 ms timeEdit = qobject_cast<QTimeEdit*>(editor); Q_ASSERT(timeEdit); QTime time{ QTime(0, 0) }; time = time.addSecs(secs); timeEdit->setTime(time); timeEdit->setCurrentSection(QDateTimeEdit::MinuteSection);
which I thought should select the minutes when the editor opened, but I see:
How to get it to select the minutes section?
Thanks
David -
This worked:
In ItemEditDelegate::createEditor():
{ QTimeEdit* editor = new QTimeEdit(parent); editor->setDisplayFormat("hh:mm:ss.zzz"); // // Commented out as parent class already sets an eventFilter up! // // editor->installEventFilter(const_cast<ItemEditDelegate*>(this)); return editor; }
and this is the event filter:
bool ItemEditDelegate::eventFilter(QObject* watched, QEvent* event) { if (QEvent::Show == event->type()) { QTimeEdit* timeEdit{ dynamic_cast<QTimeEdit*>(watched) }; QShowEvent* showEvent{ static_cast<QShowEvent*>(event) }; if (timeEdit) if (!showEvent->spontaneous()) { QTimer::singleShot(100, [timeEdit]() { timeEdit->setSelectedSection(QDateTimeEdit::MinuteSection); }); } } // // Always call the base class event filter (even though it currently // only handles stuff for TextEdit controls) // return Inherited::eventFilter(watched, event); }
-
@Perdrix said in QTimeEdit opens with the selected section being hours:
timeEdit->setCurrentSection(QDateTimeEdit::MinuteSection);
I think you need to do void QDateTimeEdit::setSelectedSection(QDateTimeEdit::Section section) for selection.
-
A good point (what's setCurrentSection actually do then?)...
I added setSelectedSection:
timeEdit->setTime(time); timeEdit->setCurrentSection(QDateTimeEdit::MinuteSection); timeEdit->setSelectedSection(QDateTimeEdit::MinuteSection);
but it made no difference :(
D.
-
@Perdrix said in QTimeEdit opens with the selected section being hours:
but it made no difference :(
Of course not: you used QDateTimeEdit::MinuteSection for both calls.
Use only setCurrentSection and then only setSelectedSection to see the difference. I think setCurrentSection will not select anything, only move the cursor to the section. setSelectedSection moves the cursor and selects the section (as described in the documentation). -
@jsulm said in QTimeEdit opens with the selected section being hours:
Of course not: you used QDateTimeEdit::MinuteSection for both calls.
Umm, but that is what the OP is asking to do! The screenshot shows the hours is selected, OP wants the munutes (middle section) to be selected, but claims
setCurrentSection(QDateTimeEdit::MinuteSection)
is not achieving that? -
@Perdrix
OK, here is the deal :) I agree your code does not work for me. It appears that when the time edit is shown something in Qt code initialises the selection to the first section unconditionally, hence thetimeEdit->setSelectedSection(QDateTimeEdit::MinuteSection)
does not take as you would expect.I discovered this by guessing and putting in a delayed timer to set the selection:
QTimer::singleShot(1000, [timeEdit]() { qDebug() << "Hello"; timeEdit->setSelectedSection(QDateTimeEdit::MinuteSection); });
I put this in after creating the
QTimeEdit
. It works, and you can see the selection move from the hours when it is initially shown to the minutes when the timer fires. Note that the time delay size seems to be critical here. I tried with0
and even with100
and it did not work. For me, I needed1000
(1 second) before it worked! You will need to play with that figure depending on your machine and where you call it/show the widget. Clearly something is going on in Qt after the widget is shown.If you want to get it "better" you probably want to subclass
QTimeEdit
so as to override theshowEvent()
, so that you are "closer" to the time it will be shown. Or, maybe you can do it in the show event of its parent widget or window or something. My 1 second was on a standalone program which had to start up and show its top-level widget containing theQTimeEdit
, you may find faster if your Qt program is already running.UPDATE
If you are prepared to subclass theQTimeEdit
so that you can overrideshowEvent
I got better "performance". Still needed to use a time delay, but getting that down to100
makes it so the user does not see the selection start at hours and then move:class MyTimeEdit : public QTimeEdit { public: explicit MyTimeEdit(QWidget *parent = nullptr) : QTimeEdit(parent) { } explicit MyTimeEdit(const QTime &time, QWidget *parent = nullptr) : QTimeEdit(time, parent) { } void showEvent(QShowEvent *event) override { QTimeEdit::showEvent(event); // next line commented out because still does not work // this->setSelectedSection(QDateTimeEdit::MinuteSection); // next line still requires `100` delay on my machine, but better than `1000` QTimer::singleShot(100, [this]() { qDebug() << "Hello"; this->setSelectedSection(QDateTimeEdit::MinuteSection); }); } };
I have written up my findings for posterity at https://stackoverflow.com/a/73879701/489865 :)
-
Well I tried this:
void ItemEditDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { QComboBox* combo{ nullptr }; QTimeEdit* timeEdit{ nullptr }; switch (static_cast<Column>(index.column())) { : STUFF DELETED case Column::Exposure: { double secs{ index.model()->data(index, Qt::EditRole).toDouble() }; if (secs > 66399.999) secs = 86399.999; // 24 hours less 1 ms double msecs = secs * 1000.0; timeEdit = qobject_cast<QTimeEdit*>(editor); Q_ASSERT(timeEdit); QTime time{ QTime(0, 0) }; time = time.addMSecs(msecs); timeEdit->setTime(time); // // timeEdit->setSelectedSection(QDateTimeEdit::MinuteSection); // didn't work, so set a singleshot timer to do it after 100 ms // QTimer::singleShot(100, [timeEdit]() { qDebug() << "Hello"; timeEdit->setSelectedSection(QDateTimeEdit::MinuteSection); }); } break; default: Inherited::setEditorData(editor, index); } }
which appeared to work except that when I closed the TimeEdit control by clicking outside it, I got:
:(
David
-
@Perdrix
Dunno, works in a standalone, something to do with your usage/context. My guess is that yourQTimeEdit
widget is the edit widget and that comes and goes and is not valid after thissetEditorData()
when the timer expires? In some shape or form. You could attach a slot toeditor->destroyed()
to debug when it gets destroyed?Other than that, start by removing the
timeEdit
argument to the lambda and verify theqDebug() << "Hello";
all works.which appeared to work except that when I closed the TimeEdit control by clicking outside it, I got:
Ah, so initially (if you don't click to destroy) it worked OK? Only later when closing you had a problem? The editor widget has been destroyed and then the single shot expires? (Like you click away within 100msecs?)
UPDATE
- Why do you not call the base implementation of
setEditorData()
in your exposure case? Does that make any difference? - I don't know, maybe the single shot would be better placed in
QStyledItemDelegate::createEditor()
? (Probably not, but looking for clues...)
Another thought: if it's an issue of the editor widget getting destroyed. instead of using the
static QTimer::singleShot()
create aQTimer
instance, set its parent to thetimeEdit
and set it as single shot. That way I'm hoping that it will automatically disconnect the slot accessing theQTimeEdit timeEdit
if it gets destroyed? - Why do you not call the base implementation of
-
This worked:
In ItemEditDelegate::createEditor():
{ QTimeEdit* editor = new QTimeEdit(parent); editor->setDisplayFormat("hh:mm:ss.zzz"); // // Commented out as parent class already sets an eventFilter up! // // editor->installEventFilter(const_cast<ItemEditDelegate*>(this)); return editor; }
and this is the event filter:
bool ItemEditDelegate::eventFilter(QObject* watched, QEvent* event) { if (QEvent::Show == event->type()) { QTimeEdit* timeEdit{ dynamic_cast<QTimeEdit*>(watched) }; QShowEvent* showEvent{ static_cast<QShowEvent*>(event) }; if (timeEdit) if (!showEvent->spontaneous()) { QTimer::singleShot(100, [timeEdit]() { timeEdit->setSelectedSection(QDateTimeEdit::MinuteSection); }); } } // // Always call the base class event filter (even though it currently // only handles stuff for TextEdit controls) // return Inherited::eventFilter(watched, event); }