我正在尝试编写一个dm脚本,其中包含一个后台线程,如下所示。在此代码中,我希望在关闭图像窗口时停止后台线程。我认为在这种情况下可能需要一些事件侦听器。您能告诉我如何通过关闭图像窗口的事件来控制(即停止)后台线程吗?如果您能建议修改我的代码或显示您的示例代码,我将非常感谢您的合作。
// $BACKGROUND$
//
Class CBackground : Thread
{
Number isRunning
Number imgID
Image tmpIMG
//
Void Init( Object self, Number iID ){
imgID = iID
tmpIMG := GetImageFromID( imgID )
}
//
Void StopRunning( Object self ){
isRunning = 0
}
//
Number GetIsRunning( Object self ){
return isRunning
}
//
Void RunThread( Object self ){
Result("Background thread is starting ......")
isRunning = 1
while (isRunning)
{
tmpIMG = random()
sleep(0.5)
}
Result(" finished !!" + "\n")
}
}
//
Void Main(){
Object cbkg = alloc(CBackground)
Image IMG := RealImage("test",4,64,64)
IMG = random()
IMG.ShowImage()
IMG.SetWindowSize(512,512)
cbkg.Init(IMG.GetImageID())
cbkg.StartThread()
}
//
Main()发布于 2018-06-24 08:14:34
下面是一个脚本的示例,它使用关闭窗口的侦听器来中止任务。
Class CBackgroundWithListeners
{
Number isRunning
Number imgID
Image tmpIMG
Number winListenID
// Constructor and Destructor method for debugging reason
// Always automatically called when object gets created or removed from memory
CBackgroundWithListeners(object self) {
Result( "\n Creating object " + self.ScriptObjectGetClassName() )
Result( " with ID: " + self.ScriptObjectGetID() )
}
~CBackgroundWithListeners(object self) {
Result( "\n Destroying object " + self.ScriptObjectGetClassName() )
Result( " with ID: " + self.ScriptObjectGetID() )
}
// Init Method
Void Init( Object self, Number iID ){
imgID = iID
tmpIMG := GetImageFromID( imgID )
If ( !tmpIMG.ImageIsValid() )
Throw( "Image of ID " + imgID + " not found." )
if ( 0 == tmpIMG.ImageCountImageDisplays() )
Throw( "Image of ID " + imgID + " has no display." )
DocumentWindow win = tmpIMG.ImageGetOrCreateImageDocument().ImageDocumentGetWindow()
if ( !win.WindowIsValid() )
Throw( "Image of ID " + imgID + " has no window." )
winListenID = win.WindowAddWindowListener( self, "window_closed:HandleClosedAction;" )
}
//
Void StopRunning( Object self ){
isRunning = 0
}
//
Number GetIsRunning( Object self ){
return isRunning
}
//
Void HandleClosedAction(object self, number e_fl, DocumentWindow Win)
{
self.StopRunning()
win.WindowRemoveWindowListener( winListenID )
}
//
Void RunThread( Object self ){
Result("Background thread is starting ......")
isRunning = 1
while (isRunning)
{
tmpIMG = random()
sleep(0.5)
}
Result(" finished !!" + "\n")
}
}
//
Void Main(){
Object cbkg = alloc(CBackgroundWithListeners)
Image IMG := RealImage("test",4,64,64)
IMG = random()
IMG.ShowImage()
IMG.SetWindowSize(512,512)
cbkg.Init(IMG.GetImageID())
cbkg.StartThread()
}
//
Main()发布于 2018-06-24 08:07:43
您不能从该线程外部停止后台线程,即不能中断线程。为了停止后台线程,相应的代码需要有一个停止条件并退出本身。
为了从另一个线程中引导这个停止条件,您需要在两个线程之间以某种方式“通信”。这可以通过许多不同的方式来完成。最简单的方法是使用一个简单的数字变量,这个变量由后台运行的代码检查,但是可以通过任何其他“外部”代码来设置。An example for this can be found in this answer here。
而不是简单的变量,人们也可以使用一些常见的地方,如f.e。全球标签。或者,为脚本语言定义一些更复杂的线程同步对象,如信号、互斥对象和semphores,并在这里的帮助文档中对其进行描述:

外部线程如何将“中断”插入后台运行线程也可以通过许多不同的方式完成。一个是--就像上面的例子一样--通过一些打开的对话框进行用户交互。另一个,正如作者所提到的,是有一些事件侦听器代码来触发这一点。下面的示例将一个键侦听器附加到图像中,这样用户就可以按ESC按钮来停止线程了。
我使用提供的脚本进行了最少的修改,以显示以下内容:
// $BACKGROUND$
//
Class CBackground : Thread
{
Number isRunning
Number imgID
Number keyListenID
Image tmpIMG
//
Void Init( Object self, Number iID ){
imgID = iID
tmpIMG := GetImageFromID( imgID )
ImageDisplay disp = tmpIMG.ImageGetImageDisplay(0)
keyListenID = disp.ImageDisplayAddKeyHandler( self, "KeyListenAction" )
}
//
Void StopRunning( Object self ){
isRunning = 0
}
//
Number GetIsRunning( Object self ){
return isRunning
}
/////////////////////////////////////////////////////////////////////////////
Number KeyListenAction(Object self, ImageDisplay disp, Object keydesc )
{
number b_keyhandled = 0
If ( keydesc.MatchesKeyDescriptor("esc") )
{
disp.ImageDisplayRemoveKeyHandler( keyListenID )
self.StopRunning()
Result( "\nSend stopping flag, unregister Key-Listeners" )
b_keyhandled = 1
}
return b_keyhandled;
}
//
Void RunThread( Object self ){
Result("Background thread is starting ......")
isRunning = 1
while (isRunning)
{
tmpIMG = random()
sleep(0.5)
}
Result(" finished !!" + "\n")
}
}
//
Void Main(){
Object cbkg = alloc(CBackground)
Image IMG := RealImage("test",4,64,64)
IMG = random()
IMG.ShowImage()
IMG.SetWindowSize(512,512)
cbkg.Init(IMG.GetImageID())
cbkg.StartThread()
}
//
Main()然而,有几件事我会采取不同的做法:
https://stackoverflow.com/questions/51006859
复制相似问题