当然,这是一个相当晦涩的问题,但它确实影响了我在工作中的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();
基于LaunchExternalProcess()函数和外部程序的解决方案的建议提供了通往答案的路径。通过使用免费的、开源的Windows宏创建包AutoHotKey,我已经能够创建一个非常紧凑的可执行文件,名为restoremm .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:ProgramDataGatan,
// 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应用程序窗口在自定义对话框出现之前被恢复。