Как обрабатывать модальный диалог, опубликованный отложенной задачей, когда окно приложения DM свернуто?

Конечно, это довольно загадочный вопрос, но он действительно влияет на модуль сценария DM, над которым я работаю. Я пытаюсь использовать настраиваемый модальный диалог, чтобы предупредить пользователей об ошибке, обнаруженной отложенной задачей основного потока. В большинстве случаев это работает просто отлично, но если окно приложения DM оказывается свернутым при публикации сообщения об ошибке, то DM оказывается в странном состоянии, когда восстанавливается в качестве приложения переднего плана. Модальное диалоговое окно невидимо, но, тем не менее, оно блокирует действия пользователя в DM до тех пор, пока не будет закрыто нажатием клавиши «enter» или «esc».

Пример кода ниже демонстрирует проблему и упоминает решение, которое работало в GMS 1.

Есть ли аналогичный или лучший обходной путь, который будет работать в GMS 2 и более поздних версиях?

class DeferredAlertTask
{
    Number deferredTaskID;

    DeferredAlertTask(Object self)
    {
        Number taskDelay_sec = 5;
        String message = "Click OK and then minimize the DM app window.\n";
        message += "After 5 seconds, select DM on the task bar to restore it.\n";
        message += "Dialog will be invisible, must hit 'enter' or 'esc' to go on.";
        OKDialog(message);

        deferredTaskID = AddMainThreadSingleTask(self, "Task", taskDelay_sec);
    }

    void Task(Object self)
    {
        String banner = "Error dialog";
        String message = "Error message details.";

        // Create the dialog box descriptor TagGroup
        TagGroup dialogItemsSpec;
        TagGroup dialogSpec = DLGCreateDialog(banner, dialogItemsSpec);

        // Create and add the content box and text field to the layout
        TagGroup contentBoxItemsSpec;
        TagGroup contentBoxSpec = DLGCreateBox(contentBoxItemsSpec);
        TagGroup contentLabelSpec = DLGCreateLabel(message);
        contentBoxItemsSpec.DLGAddElement(contentLabelSpec);
        dialogItemsSpec.DLGAddElement(contentBoxSpec);

        // If the DM app window has been minimized, 
        // this modal dialog will be invisible,
        // but it will still inhibit further user action
        // within DM as it awaits 'esc' or 'enter'.

        // The following is a remedy that works in GMS1, but not in GMS2
        // GetApplicationWindow().WindowSelect();

        Object dialog = Alloc(UIFrame).Init(dialogSpec);
        String result = (dialog.Pose()) ? "OK" : "Cancel";
        OKDialog(result);
    }
}

void main()
{
    Alloc(DeferredAlertTask);
}

main();

person Mike Kundmann    schedule 09.10.2016    source источник
comment
Действительно интересно. Боюсь, я не знаю решения для этого - похоже, это часть управления окнами MS, и сценарии могут ничего не сделать. Однако я только что подтвердил, что у вас нет этой проблемы в GMS 3.   -  person BmyGuest    schedule 10.10.2016
comment
Очень близкая идея: знаете ли вы способ восстановить/развернуть свернутое окно приложения с помощью командной строки (или другого исполняемого файла)? Я не нашел такого с помощью быстрого поиска в Интернете, но если вы это сделаете, может быть решение с помощью команды LaunchExternalProcess(). По сути, кажется, что если вы вызываете () диалоговое окно в GMS 2, когда окно приложения свернуто, этому окну не назначается родительское окно. Поэтому вам нужно убедиться, что окно приложения отображается во время позирования....   -  person BmyGuest    schedule 10.10.2016
comment
@BmyGuest - Большое спасибо за ваши комментарии и идеи. Приятно слышать, что эта проблема не возникает в GMS 3. Эта новость побудила меня обновиться до последней версии, которая решает другие проблемы, которые у меня возникали с пользовательскими модальными диалогами. В частности, спасибо за подсказку о LaunchExternalProcess(). Я нашел решение, используя вашу идею за углом, и опубликую ее как ответ на мой собственный вопрос.   -  person Mike Kundmann    schedule 11.10.2016


Ответы (1)


Предложение основывать решение на функции LaunchExternalProcess() и внешней программе предоставило путь к ответу. Используя бесплатный пакет для создания макросов Windows с открытым исходным кодом под названием AutoHotKey, я смог создать очень компактный исполняемый файл с именем RestoreDM. .исполняемый файл. Поместив этот исполняемый файл в папку, легко доступную из сценария DM, его можно запустить с помощью LaunchExternalProcessAsync(), чтобы убедиться, что окно приложения DM восстановлено перед публикацией пользовательского диалога. Ниже представлена ​​модифицированная версия исходного тестового сценария, иллюстрирующая это решение и предоставляющая подробную информацию о сценарии AutoHotKey:

class DeferredAlertTask
{
    Number deferredTaskID;

    DeferredAlertTask(Object self)
    {
        Number taskDelay_sec = 5;
        String message = "Click OK and then minimize the DM app window.\n";
        message += "After 5 seconds, select DM on the task bar to restore it.\n";
        message += "Dialog will be invisible, must hit 'enter' or 'esc' to go on.";
        OKDialog(message);

        deferredTaskID = AddMainThreadSingleTask(self, "Task", taskDelay_sec);
    }

    void Task(Object self)
    {
        String banner = "Error dialog";
        String message = "Error message details.";

        // Create the dialog box descriptor TagGroup
        TagGroup dialogItemsSpec;
        TagGroup dialogSpec = DLGCreateDialog(banner, dialogItemsSpec);

        // Create and add the content box and text field to the layout
        TagGroup contentBoxItemsSpec;
        TagGroup contentBoxSpec = DLGCreateBox(contentBoxItemsSpec);
        TagGroup contentLabelSpec = DLGCreateLabel(message);
        contentBoxItemsSpec.DLGAddElement(contentLabelSpec);
        dialogItemsSpec.DLGAddElement(contentBoxSpec);

        // If the DM app window has been minimized, 
        // this modal dialog will be invisible,
        // but it will still inhibit further user action
        // within DM as it awaits 'esc' or 'enter'.

        // The following is a remedy that works in GMS1, but not in GMS2
        // GetApplicationWindow().WindowSelect();

        // For GMS2, we can use an executable that restores the DM app window.
        // The lines below launch RestoreDM.exe, placed in C:\ProgramData\Gatan,
        // where RestoreDM is an executable of the following AutoHotKey script:
        // IfWinNotActive, Digital Micrograph
        //      WinRestore, Digital Micrograph
        String commandDir = GetApplicationDirectory(3, 0);
        String restoreCommand = commandDir.PathConcatenate("RestoreDM");
        LaunchExternalProcessAsync(restoreCommand);
        Sleep(0.1);

        Object dialog = Alloc(UIFrame).Init(dialogSpec);
        String result = (dialog.Pose()) ? "OK" : "Cancel";
        OKDialog(result);
    }
}

void main()
{
    Alloc(DeferredAlertTask);
}

main();

Необходимо использовать асинхронный вариант LaunchExternalProcessAsync(), потому что задача отложенного оповещения вызывается в основном потоке и, таким образом, блокирует восстановление окна DM по запросу программы RestoreDM (что приводит к зависанию DM). Также обратите внимание, что после вызова внешней программы требуется короткий сон, чтобы убедиться, что окно приложения DM восстановлено до того, как будет создано пользовательское диалоговое окно.

person Mike Kundmann    schedule 10.10.2016
comment
Примерно то решение, которое я имел в виду. (Я надеялся, что будет один без дополнительного исполняемого файла, например, через cmd.exe, но я не смог найти его самостоятельно.) просто для информации: в GMS3 есть команда для сворачивания/восстановления окна приложения DM. Я бы предположил именно по тем причинам, которые вы указали... - person BmyGuest; 11.10.2016