首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在dm-script中关闭图像窗口时停止后台线程

如何在dm-script中关闭图像窗口时停止后台线程
EN

Stack Overflow用户
提问于 2018-06-24 04:01:48
回答 2查看 124关注 0票数 1

我正在尝试编写一个dm脚本,其中包含一个后台线程,如下所示。在此代码中,我希望在关闭图像窗口时停止后台线程。我认为在这种情况下可能需要一些事件侦听器。您能告诉我如何通过关闭图像窗口的事件来控制(即停止)后台线程吗?如果您能建议修改我的代码或显示您的示例代码,我将非常感谢您的合作。

代码语言:javascript
复制
// $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()
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-24 08:14:34

下面是一个脚本的示例,它使用关闭窗口的侦听器来中止任务。

代码语言:javascript
复制
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()
票数 1
EN

Stack Overflow用户

发布于 2018-06-24 08:07:43

您不能从该线程外部停止后台线程,即不能中断线程。为了停止后台线程,相应的代码需要有一个停止条件并退出本身。

为了从另一个线程中引导这个停止条件,您需要在两个线程之间以某种方式“通信”。这可以通过许多不同的方式来完成。最简单的方法是使用一个简单的数字变量,这个变量由后台运行的代码检查,但是可以通过任何其他“外部”代码来设置。An example for this can be found in this answer here

而不是简单的变量,人们也可以使用一些常见的地方,如f.e。全球标签。或者,为脚本语言定义一些更复杂的线程同步对象,如信号、互斥对象和semphores,并在这里的帮助文档中对其进行描述:

外部线程如何将“中断”插入后台运行线程也可以通过许多不同的方式完成。一个是--就像上面的例子一样--通过一些打开的对话框进行用户交互。另一个,正如作者所提到的,是有一些事件侦听器代码来触发这一点。下面的示例将一个键侦听器附加到图像中,这样用户就可以按ESC按钮来停止线程了。

我使用提供的脚本进行了最少的修改,以显示以下内容:

代码语言:javascript
复制
// $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()

然而,有几件事我会采取不同的做法:

  • 用正确的命令启动后台线程,而不是使用旧的'$$BACKGROUND$$‘方法。
  • 尽可能多地封装到类中。
  • 添加一些安全检查
  • 还添加一个窗口关闭事件侦听器,这样关闭图像窗口也会停止线程。
  • 添加一些调试代码,以显示何时创建对象以及何时从内存中删除对象。
  • 让键侦听器暂停/取消暂停操作。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51006859

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档