如何在 dm-script 中创建包含两个以上按钮的阻塞对话框
How to create a blocking dialog with more than two buttons in dm-script
如何创建一个对话框,其中包含两个以上的自定义按钮而不是阻止脚本的“确定”和“取消”按钮?
可以使用 TwoButtonDialog()
在 dm-script 中创建一个带有两个自定义按钮的对话框。但请考虑以下询问是否覆盖文件的示例对话框。此对话框需要的不仅仅是“确定”和“取消”按钮。
可以使用 UIFrame
和对话框函数简单地创建此对话框。但是使用 UIFrame::display()
不会等待用户交互。对话框将显示,脚本继续。当使用 UIFrame::pose()
时,这会阻止当前脚本,但也会始终添加“确定”和“取消”按钮。所以在这里使用这些函数似乎不适合这种情况。
如何创建一个对话框来阻止脚本在没有额外的“确定”和“取消”按钮的情况下继续运行,以便我可以添加自己的按钮?或者,我如何使这个对话框成为模态?
我试过的
版本 1
我试图通过等待 Signal
来阻塞当前工作线程,如下面的示例代码所示。我正在创建对话框并使用不添加任何按钮的 UIFrame::display()
。然后我等待按钮点击回调中设置的信号。
number index = -1;
object wait_signal = NewSignal(0);
class ButtonDialog : UIFrame{
void button_pressed(object self, number i){
index = i;
wait_signal.SetSignal();
self.close();
}
object init(object self){
// creating dialog contents, for full example look at the bottom
return self;
}
}
// Version 1
alloc(ButtonDialog).init().display(title);
wait_signal.waitOnSignal(10, NULL);
result("The index is " + index + "\n");
底部的可执行版本,取消注释Version 1
块,注释所有其他版本
但这不起作用。出现的对话框还没有完成,看起来像下面这样:
我一更改 window,对话框就会显示文本和按钮,但仍然不可点击。再加上布局不完善
版本 2
所以我想把对话框完全移到一个单独的线程中。这样它就可以花费初始化所需的时间,并且肯定可以使用,因为新的单独线程永远不会被阻塞。
number index = -1;
object wait_signal = NewSignal(0);
class ButtonDialog : UIFrame{
void button_pressed(object self, number i){
index = i;
wait_signal.SetSignal();
self.close();
}
object init(object self){
// creating dialog contents, for full example look at the bottom
return self;
}
}
class ButtonDialogThread : Thread{
object init(object self){
return self;
}
void RunThread(object self){
alloc(ButtonDialog).init().display(title);
}
}
// Version 2
alloc(ButtonDialogThread).init().startThread();
wait_signal.waitOnSignal(10, NULL);
result("The index is " + index + "\n");
可执行版本在底部,取消注释Version 2
块,注释所有其他版本
但这会产生与上面提到和显示的对话框相同的输出。
版本 3
更基本的方法是使用 while
循环,中间有休眠。据我所知,Signal
s 的工作方式与此完全相同。但我还是试了一下。
number index = -1;
object wait_signal = NewSignal(0);
class ButtonDialog : UIFrame{
void button_pressed(object self, number i){
index = i;
wait_signal.SetSignal();
self.close();
}
object init(object self){
// creating dialog contents, for full example look at the bottom
return self;
}
}
// Version 3
alloc(ButtonDialog).init().display(title);
number security_counter = 0;
while(index == -1 && security_counter < 100){
sleep(0.1);
security_counter += 1;
}
result("The index is " + index + "\n");
可执行版本在底部,取消注释Version 3
块,注释所有其他版本
但同样,结果与 Version 1
相同。
我做错了什么?如何在显示的对话框进行一些用户交互之前阻塞主线程?
string text = "Several files already exist. Do you want to overwrite the file 'test_file.dm4' and 12 others?"
string button0 = "Yes";
string button1 = "Yes, all";
string button2 = "No";
string button3 = "No, all";
string button4 = "Cancel";
string title = "Overwrite?";
object wait_signal = NewSignal(0);
number index = -1;
class ButtonDialog : UIFrame{
void button_pressed(object self, number i){
index = i;
wait_signal.SetSignal();
self.close();
}
void button0_pressed(object self){self.button_pressed(0);}
void button1_pressed(object self){self.button_pressed(1);}
void button2_pressed(object self){self.button_pressed(2);}
void button3_pressed(object self){self.button_pressed(3);}
void button4_pressed(object self){self.button_pressed(4);}
object init(object self){
TagGroup dlg, dlg_items, wrapper, label, b;
index = -1;
dlg = DLGCreateDialog("Press a button", dlg_items);
dlg_items.DLGAddElement(DLGCreateLabel(text));
wrapper = DLGCreateGroup();
wrapper.DLGTableLayout(5, 1, 1);
dlg_items.DLGAddElement(wrapper);
b = DLGCreatePushButton(button0, "button0_pressed");
b.DLGWidth(80);
wrapper.DLGAddElement(b);
b = DLGCreatePushButton(button1, "button1_pressed");
b.DLGWidth(80);
wrapper.DLGAddElement(b);
b = DLGCreatePushButton(button2, "button2_pressed");
b.DLGWidth(80);
wrapper.DLGAddElement(b);
b = DLGCreatePushButton(button3, "button3_pressed");
b.DLGWidth(80);
wrapper.DLGAddElement(b);
b = DLGCreatePushButton(button4, "button4_pressed");
b.DLGWidth(80);
wrapper.DLGAddElement(b);
self.super.init(dlg);
return self;
}
}
class ButtonDialogThread : Thread{
object init(object self){
return self;
}
void RunThread(object self){
alloc(ButtonDialog).init().display(title);
}
}
// Version 1
// alloc(ButtonDialog).init().display(title);
// wait_signal.waitOnSignal(10, NULL);
// Version 2
alloc(ButtonDialogThread).init().startThread();
wait_signal.waitOnSignal(10, NULL);
// Version 3
// alloc(ButtonDialog).init().display(title);
// number security_counter = 0;
// while(index == -1 && security_counter < 100){
// sleep(0.1);
// security_counter += 1;
// }
result("The index is " + index + "\n");
实际上所有你的尝试都是好的,原则上是有效的。 (第一个是要搭配的那个。)但是,它们不起作用,因为您遗漏了一点:
All UI actions in DigitalMicrograph are run on the main thread of the application.
还有:
Any script is, by default, run on the main thread of the application.
因此,您的脚本是自阻塞的。该脚本在初始化对话框并发送消息以显示它之后,阻塞了主线程。因此无法执行正确绘制对话框的消息,并且无法正确显示对话框。
但是,当脚本等待来自对话框的消息时,您处于阻塞状态。
您不能将对话框放在单独的线程上 - 您只能将脚本放在单独的线程上启动对话框. UI 总是需要一些主线程周期才能实际工作。
因此,您真正需要做的是确保脚本不在主线程上。
最简单的方法是使用 old 方法,通过将脚本的第一行写成 exactly[= 将脚本执行放在单独的线程上34=]如下:
// $BACKGROUND$
(全部大写,//
后加白色 space)
如果将这一行添加到脚本中,一切正常。
在单独的线程上启动脚本的一种更优雅的方法是使用线程 class,就像您在 版本 2 中所做的那样。只需确保将脚本 waiting for the signal 放在后台线程,而不是对话框。
如何创建一个对话框,其中包含两个以上的自定义按钮而不是阻止脚本的“确定”和“取消”按钮?
可以使用 TwoButtonDialog()
在 dm-script 中创建一个带有两个自定义按钮的对话框。但请考虑以下询问是否覆盖文件的示例对话框。此对话框需要的不仅仅是“确定”和“取消”按钮。
可以使用 UIFrame
和对话框函数简单地创建此对话框。但是使用 UIFrame::display()
不会等待用户交互。对话框将显示,脚本继续。当使用 UIFrame::pose()
时,这会阻止当前脚本,但也会始终添加“确定”和“取消”按钮。所以在这里使用这些函数似乎不适合这种情况。
如何创建一个对话框来阻止脚本在没有额外的“确定”和“取消”按钮的情况下继续运行,以便我可以添加自己的按钮?或者,我如何使这个对话框成为模态?
我试过的
版本 1
我试图通过等待 Signal
来阻塞当前工作线程,如下面的示例代码所示。我正在创建对话框并使用不添加任何按钮的 UIFrame::display()
。然后我等待按钮点击回调中设置的信号。
number index = -1;
object wait_signal = NewSignal(0);
class ButtonDialog : UIFrame{
void button_pressed(object self, number i){
index = i;
wait_signal.SetSignal();
self.close();
}
object init(object self){
// creating dialog contents, for full example look at the bottom
return self;
}
}
// Version 1
alloc(ButtonDialog).init().display(title);
wait_signal.waitOnSignal(10, NULL);
result("The index is " + index + "\n");
底部的可执行版本,取消注释Version 1
块,注释所有其他版本
但这不起作用。出现的对话框还没有完成,看起来像下面这样:
我一更改 window,对话框就会显示文本和按钮,但仍然不可点击。再加上布局不完善
版本 2
所以我想把对话框完全移到一个单独的线程中。这样它就可以花费初始化所需的时间,并且肯定可以使用,因为新的单独线程永远不会被阻塞。
number index = -1;
object wait_signal = NewSignal(0);
class ButtonDialog : UIFrame{
void button_pressed(object self, number i){
index = i;
wait_signal.SetSignal();
self.close();
}
object init(object self){
// creating dialog contents, for full example look at the bottom
return self;
}
}
class ButtonDialogThread : Thread{
object init(object self){
return self;
}
void RunThread(object self){
alloc(ButtonDialog).init().display(title);
}
}
// Version 2
alloc(ButtonDialogThread).init().startThread();
wait_signal.waitOnSignal(10, NULL);
result("The index is " + index + "\n");
可执行版本在底部,取消注释Version 2
块,注释所有其他版本
但这会产生与上面提到和显示的对话框相同的输出。
版本 3
更基本的方法是使用 while
循环,中间有休眠。据我所知,Signal
s 的工作方式与此完全相同。但我还是试了一下。
number index = -1;
object wait_signal = NewSignal(0);
class ButtonDialog : UIFrame{
void button_pressed(object self, number i){
index = i;
wait_signal.SetSignal();
self.close();
}
object init(object self){
// creating dialog contents, for full example look at the bottom
return self;
}
}
// Version 3
alloc(ButtonDialog).init().display(title);
number security_counter = 0;
while(index == -1 && security_counter < 100){
sleep(0.1);
security_counter += 1;
}
result("The index is " + index + "\n");
可执行版本在底部,取消注释Version 3
块,注释所有其他版本
但同样,结果与 Version 1
相同。
我做错了什么?如何在显示的对话框进行一些用户交互之前阻塞主线程?
string text = "Several files already exist. Do you want to overwrite the file 'test_file.dm4' and 12 others?"
string button0 = "Yes";
string button1 = "Yes, all";
string button2 = "No";
string button3 = "No, all";
string button4 = "Cancel";
string title = "Overwrite?";
object wait_signal = NewSignal(0);
number index = -1;
class ButtonDialog : UIFrame{
void button_pressed(object self, number i){
index = i;
wait_signal.SetSignal();
self.close();
}
void button0_pressed(object self){self.button_pressed(0);}
void button1_pressed(object self){self.button_pressed(1);}
void button2_pressed(object self){self.button_pressed(2);}
void button3_pressed(object self){self.button_pressed(3);}
void button4_pressed(object self){self.button_pressed(4);}
object init(object self){
TagGroup dlg, dlg_items, wrapper, label, b;
index = -1;
dlg = DLGCreateDialog("Press a button", dlg_items);
dlg_items.DLGAddElement(DLGCreateLabel(text));
wrapper = DLGCreateGroup();
wrapper.DLGTableLayout(5, 1, 1);
dlg_items.DLGAddElement(wrapper);
b = DLGCreatePushButton(button0, "button0_pressed");
b.DLGWidth(80);
wrapper.DLGAddElement(b);
b = DLGCreatePushButton(button1, "button1_pressed");
b.DLGWidth(80);
wrapper.DLGAddElement(b);
b = DLGCreatePushButton(button2, "button2_pressed");
b.DLGWidth(80);
wrapper.DLGAddElement(b);
b = DLGCreatePushButton(button3, "button3_pressed");
b.DLGWidth(80);
wrapper.DLGAddElement(b);
b = DLGCreatePushButton(button4, "button4_pressed");
b.DLGWidth(80);
wrapper.DLGAddElement(b);
self.super.init(dlg);
return self;
}
}
class ButtonDialogThread : Thread{
object init(object self){
return self;
}
void RunThread(object self){
alloc(ButtonDialog).init().display(title);
}
}
// Version 1
// alloc(ButtonDialog).init().display(title);
// wait_signal.waitOnSignal(10, NULL);
// Version 2
alloc(ButtonDialogThread).init().startThread();
wait_signal.waitOnSignal(10, NULL);
// Version 3
// alloc(ButtonDialog).init().display(title);
// number security_counter = 0;
// while(index == -1 && security_counter < 100){
// sleep(0.1);
// security_counter += 1;
// }
result("The index is " + index + "\n");
实际上所有你的尝试都是好的,原则上是有效的。 (第一个是要搭配的那个。)但是,它们不起作用,因为您遗漏了一点:
All UI actions in DigitalMicrograph are run on the main thread of the application.
还有:
Any script is, by default, run on the main thread of the application.
因此,您的脚本是自阻塞的。该脚本在初始化对话框并发送消息以显示它之后,阻塞了主线程。因此无法执行正确绘制对话框的消息,并且无法正确显示对话框。 但是,当脚本等待来自对话框的消息时,您处于阻塞状态。
您不能将对话框放在单独的线程上 - 您只能将脚本放在单独的线程上启动对话框. UI 总是需要一些主线程周期才能实际工作。
因此,您真正需要做的是确保脚本不在主线程上。 最简单的方法是使用 old 方法,通过将脚本的第一行写成 exactly[= 将脚本执行放在单独的线程上34=]如下:
// $BACKGROUND$
(全部大写,//
后加白色 space)
如果将这一行添加到脚本中,一切正常。
在单独的线程上启动脚本的一种更优雅的方法是使用线程 class,就像您在 版本 2 中所做的那样。只需确保将脚本 waiting for the signal 放在后台线程,而不是对话框。