如何在 dm 脚本中关闭图像 window 时停止后台线程
How to stop a background thread when an image window is closed in dm-script
我正在尝试编写一个包含后台线程的 dm 脚本,如以下示例代码所示。在这段代码中,我想在图像 window 关闭时停止后台线程。我认为在这种情况下可能需要一些事件监听器。你能告诉我如何通过关闭图像 window 事件来控制(即停止)后台线程吗?如果您可以建议对我的代码进行一些修改或展示您的示例代码,我将不胜感激。
// $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()
您不能从该线程外部停止后台线程,即您不能中断一个线程。为了停止后台线程,相应的代码需要有一个停止条件并自行退出。
为了从另一个线程引导这个停止条件,您需要 "communicate" 以某种方式在两个线程之间。这可以通过许多不同的方式来完成。最简单的方法是使用一个简单的数字变量,该变量由后台 运行 代码检查,但可以通过任何其他 "outside" 代码设置。 .
除了简单的变量,还可以使用一些常用的地方,如 f.e。 全局标签。或者,为脚本语言定义了一些更复杂的线程同步对象,如 signals、mutexes 和 semphores并在此处的帮助文档中进行描述:
如何 外部线程将 'break' 插入后台 运行 线程也可以通过许多不同的方式完成。一种是——如上例所示——通过一些打开的对话框进行用户交互。另一个,正如作者所提到的,是有一些事件监听器代码来触发它。
下面的示例将一个键侦听器附加到图像,以便(将此图像放在最前面并选中)用户可以按 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()
但是,有几件事我会采取不同的做法:
- 使用正确的命令而不是旧的“$$BACKGROUND$$”方法启动后台线程。
- 尽可能封装成class
- 添加一些安全检查
- 同时添加一个windows关闭事件侦听器,这样关闭图像window也会停止线程
- 添加一些调试代码以显示对象何时创建以及何时从内存中删除
- 让 keylistener pause/unpause 动作。
这里是一个脚本示例,它使用 window-closed 侦听器来中止任务。
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()
我正在尝试编写一个包含后台线程的 dm 脚本,如以下示例代码所示。在这段代码中,我想在图像 window 关闭时停止后台线程。我认为在这种情况下可能需要一些事件监听器。你能告诉我如何通过关闭图像 window 事件来控制(即停止)后台线程吗?如果您可以建议对我的代码进行一些修改或展示您的示例代码,我将不胜感激。
// $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()
您不能从该线程外部停止后台线程,即您不能中断一个线程。为了停止后台线程,相应的代码需要有一个停止条件并自行退出。
为了从另一个线程引导这个停止条件,您需要 "communicate" 以某种方式在两个线程之间。这可以通过许多不同的方式来完成。最简单的方法是使用一个简单的数字变量,该变量由后台 运行 代码检查,但可以通过任何其他 "outside" 代码设置。
除了简单的变量,还可以使用一些常用的地方,如 f.e。 全局标签。或者,为脚本语言定义了一些更复杂的线程同步对象,如 signals、mutexes 和 semphores并在此处的帮助文档中进行描述:
如何 外部线程将 'break' 插入后台 运行 线程也可以通过许多不同的方式完成。一种是——如上例所示——通过一些打开的对话框进行用户交互。另一个,正如作者所提到的,是有一些事件监听器代码来触发它。 下面的示例将一个键侦听器附加到图像,以便(将此图像放在最前面并选中)用户可以按 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()
但是,有几件事我会采取不同的做法:
- 使用正确的命令而不是旧的“$$BACKGROUND$$”方法启动后台线程。
- 尽可能封装成class
- 添加一些安全检查
- 同时添加一个windows关闭事件侦听器,这样关闭图像window也会停止线程
- 添加一些调试代码以显示对象何时创建以及何时从内存中删除
- 让 keylistener pause/unpause 动作。
这里是一个脚本示例,它使用 window-closed 侦听器来中止任务。
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()