Определить, почему диалоговое окно задач было закрыто в Delphi

Часть моего приложения Delphi обращается к информации из другой программы. Поскольку выполнение может занять некоторое время, а иногда другая программа может не отвечать, я запускаю эту часть своего кода в отдельном потоке.

Чтобы информировать пользователей о ходе выполнения фонового потока, я запускаю TaskDialog после запуска потока. Я передаю указатель на TaskDialog в свой поток, чтобы поток мог синхронизироваться с TaskDialog и обновлять его по мере выполнения потока. Когда поток завершается, я отправляю сообщение о закрытии в TaskDialog, используя PostMessage(CurrentTaskDialog.Handle, WM_CLOSE, 0, 0);

Пока все работает, но я хочу отменить процесс, если пользователь нажмет кнопку «Отмена» в TaskDialog (это единственная кнопка в TaskDialog). Я не могу понять, как это сделать. Независимо от того, нажимает ли пользователь кнопку или TaskDialog получает сообщение о закрытии, ModalResult всегда равно mrCancel. Я попытался назначить другой ModalResult в потоке, но он все еще оценивается как mrCancel.

Есть ли способ сделать это?


person Trey Thrasher    schedule 18.07.2020    source источник
comment
Добро пожаловать в stackoverflow.com. Если вы разместите пример кода, который позволит людям воспроизвести ошибку, вы можете получить ответ быстрее.   -  person DV82XL    schedule 18.07.2020


Ответы (1)


То, что вы описываете, является нормальным поведением, согласно TaskDialogIndirect() документация:

pnButton

Тип: int*

Адрес переменной, которая получает либо:

  • один из идентификаторов кнопок, указанных в члене pButtons параметра pTaskConfig

  • одно из следующих значений:

    • 0: Function call failed. Refer to return value for more information.
    • IDCANCEL: была выбрана кнопка "Отмена", были нажаты клавиши Alt-F4, был нажат Escape или пользователь нажал кнопку закрытия окна.
    • IDNO: кнопка не выбрана.
    • IDOK: была выбрана кнопка OK.
    • IDRETRY: была выбрана кнопка «Повторить попытку».
    • IDYES: была выбрана кнопка Да.

Поскольку у вас есть только кнопка «Отмена» и вы имитируете нажатие кнопки закрытия, тогда TaskDialogIndirect() всегда сообщает IDCANCEL, поэтому ModalResult всегда mrCancel. Невозможно определить фактическую причину (кроме подключения самого диалогового окна).

В любом случае вам вообще не нужно использовать ModalResult для выполнения того, что вы хотите.

Когда диалог закрывается по какой-либо причине, просто сигнализируйте завершение потока, а затем подождите, пока поток полностью завершится. Если поток уже завершился до закрытия диалога, сигнал будет проигнорирован, и ожидание будет выполнено немедленно.

Затем вы могли бы сделать еще один шаг вперед. Вместо использования tcbCancel в свойстве CommonButtons TaskDialog вы можете использовать пользовательскую кнопку в свойстве Buttons TaskDialog, а затем использовать событие OnButtonClicked TaskDialog, чтобы сигнализировать потоку о выходе. Заблокируйте автоматическое закрытие диалогового окна (установив CanClose=False в обработчике событий) и подождите, пока поток закроет диалоговое окно после завершения. Это позволит вам продолжать отображать обратную связь внутри TaskDialog, ожидая завершения потока, например отображая сообщение об ожидании. В то время как при другом подходе окно TaskDialog закрывается, когда пользователь нажимает стандартную кнопку «Отмена», поэтому вы больше не можете отображать обратную связь, даже если поток все еще работает.

person Remy Lebeau    schedule 18.07.2020
comment
Дополнительный вопрос. В какой-то момент в потоке невозможно отменить, поэтому я хотел бы удалить кнопку отмены в этот момент, чтобы пользователь не думал, что он может отменить. Я пробовал следующий код в потоке: tBackgroundIssueCheck.Synchronize(nil, начало процедуры StatusTaskDialog.CommonButtons := []; end); Но это не работает. Есть ли способ обновить кнопки в диалоге задач? - person Trey Thrasher; 24.07.2020
comment
Изменение CommonButtons после отображения диалогового окна не имеет никакого эффекта. Он используется только при инициализации диалога. Когда диалоговое окно станет видимым, отправьте его HWND сообщение TDM_ENABLE_BUTTON< /a> сообщение вместо этого. Вы также можете отправить TDM_SET_ELEMENT_TEXT или сообщение TDM_UPDATE_ELEMENT_TEXT с объяснением пользователю, почему кнопка отключена. - person Remy Lebeau; 24.07.2020