1

当然,这是一个相当神秘的问题,但它确实会影响我正在开发的 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();
4

1 回答 1

1

基于 LaunchExternalProcess() 函数和外部程序的解决方案的建议提供了一个答案路径。通过使用名为AutoHotKey的免费开源 Windows 宏创建包,我已经能够创建一个名为 RestoreDM.exe 的非常紧凑的可执行文件。通过将此可执行文件放置在可从 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(),因为延迟警报任务在主线程上调用,因此在 RestoreDM 程序提示时阻止 DM 恢复其窗口(导致 DM 挂起)。另请注意,调用外部程序后需要短暂睡眠,以确保在自定义对话框出现之前恢复 DM 应用程序窗口。

于 2016-10-10T22:55:07.577 回答