2022年IDL入门教程十二 .pdf
《2022年IDL入门教程十二 .pdf》由会员分享,可在线阅读,更多相关《2022年IDL入门教程十二 .pdf(12页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第十二章对话框程序本章概述本章主要讲解两种编写对话框程序的方法。对话框是用于接收用户信息,并把信息传递到另一个程序模块,或程序中。其中,将学到以下几个方面的内容:1.如何编写模式对话框;2.如何编写非模式对话框;3.如何在组件程序中用指针存储信息;4.如何在组件程序中使用伪消息;5.如何在独立的组件程序之间传递信息;创建模式对话框在上一章的XImageBar 程序中,已经调用过一个模式对话框程序,即GetImage,它允许用户选择并读入一个影像文件。在XImageBar 程序中,这个对话框被调用过两次。一次是在组件定义模块中,当一个影像数据未被传入到程序时;另一次则是在Open Image 按
2、钮被按下的时候。 (如果在上一章中没有编写XImageBar 程序,可以调用与本书配套使用的文档 XImageBar.9.pro 。 )在第一个程序实例中调用方式如下:image = GetImage (Cancel = canceled) 在第二个程序实例中调用如下:image = GetImage (Cancel = canceled, Parent = event. Top) 在这两次调用过程中有几个微小的区别,不过调用时读者可能没有注意到。如果想编写对话框程序,就必须了解这两次调用的差别以及它们是如何工作的。阻塞的组件程序在上述例子中,第一次调用GetImage 时, GetImage
3、 程序运行时就好比是阻塞的组件程序。要看它是如何工作的,在IDL 命令行中键入如下所示:IDL image = GetImage ( ) 注意到 IDL 命令行要么是消失了要么是变灰了。这时要在IDL 命令行上键入命令并执行它们是不可能的。我们就称IDL 命令行是阻塞了。 (当命令行正处于消失或变灰状态时,可以键入命令,但只有在命令行解除了阻塞后命令才可以执行。)一般而言,无论运行哪一种IDL 程序都会阻塞IDL 命令行。换言之,只有等到当前的命令执行完毕后才有可能键入并执行另一命令。IDL 5 以前的版本中,所有的组件程序也都是如此运行的。 一旦运行了一个组件程序,只有等到这个组件程序执行完
4、毕后才可进入IDL命令行。但在IDL5中,刚才的现象已经改变了。现在,可以运行一个组件程序并立即在IDL命令行上输入命令然后执行它。我们称这种组件程序为无阻塞组件程序。要创建一个无阻塞的组件程序,只需要程序中的XManager 命令使用关键字No_Block 即可。这正如先前编写名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 12 页 - - - - - - - - - 的程序 XimageBar 中所做的那样。然而,在程序GetImage 中的 XManager 命令是
5、没有关键字Bo_Block 的。因而,它是一种阻塞程序。在这里的“阻塞” ,是指在执行Xmanager 命令的同时,IDL 就停止执行GetImage 组件定义模块中的代码。 组件定义模块中任何在XManager 命令下面的代码 (其中也有一些可以,待会可以看到) 都不能被执行, 直到组件程序被销毁后才被执行,也就是说这是阻塞被解除了。这对像 GetImage 这样的程序是合适的,因为阻塞给用户提供了足够的时间来填写表格或对话框中的信息。当用户添完表格, 他们就会点击Cancel 或 Accept 按钮。无论哪种情况,IDL 都将销毁组件,并解除阻塞,程序也可以用所收集的信息继续工作。对于Ge
6、tImage 而言,收集的信息是指关于数据文件、打开文件读取数据,将结果返回给用户。所有收集,读取,返还这一系列的操作都是在组件定义模块中的XManager 命令执行完毕后才进行。优点就这些。 但是, 阻塞也有个细微方面容易被忽视。那就是,只有第一个调用XManager为阻塞的组件程序才可以成为阻塞。后来所有的组件程序都将越过阻塞好像他们是无阻塞的组件程序一样。这种行为对于像GetImage 这样的程序而言,完全是一个灾难,因为程序将在用户获得填写表格的机会之前就开始读取数据文件。从一个自己对它一无所知的文件中读取数据会带来一些小麻烦。模式组件程序如果想确保在任何条件下一个组件程序都会阻塞,而
7、不是仅仅在第一次侥幸地调用Manager 后才成为阻塞,那么就必须建立一个模式的组件程序。模式的组件程序总是在执行XManager 命令时处于阻塞状态,直到组件被销毁。在 IDL5 以前的版本中, 编写一个模式的组件程序相对简单些。只要简单地在XManager命令后设置关键字Modal 即可。但在IDL5 中, Xmanager 命令中的关键字Modal 已经被废弃了。取而代之的是,在创建顶级base时的 Widget_Base 函数中增加一个Modal 关键字。这里有一个很小却很重要的补充。如果为一个base组件设置Modal 关键字,同时也必须为那个base组建设置一个有效的Group L
8、eader(通过设置Group_Leader 关键字)。这对要编写一个既能在IDL 命令行中运行,又能在程序中运行的对话框程序的难度就更大了。等一会编写程序时或许就会明白这个意思了。编写模式对话框的定义模块程序 GetImage 是一个对话框程序的绝好例子,但也是相当复杂的。如果是从一个更简单的例子开始, 那么就能够更容易理解创建对话框的规则。由于在与本书配套使用的文档下的 Coyote 目录中,有许多类似2D 字节数组的数据文件,那我们就从编写一个简单对话框程序开始,用于打开和读入Coyote 目录下的文件。通过调用这个程序,就可以获得这个文件的名字以及在X 和 Y 方向上的大小,暂且称这个
9、程序为GetData 吧。Coyote 目录下的数据文件以及文件大小的详细信息请参阅313 页的“附录B:数据文件描述”。如果希望让用户将某些信息输入到表格中,一般来说, 这办法不是很好,如果我们对用户一点也不了解的话,或许他们就无法输入。如果可能的话, 让用户选择一个文件名或用鼠名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 12 页 - - - - - - - - - 标点击选择文件的大小将会是个更好的主意。假定确实要让用户输入,那么让用户输入的越少越好。解决上述问题
10、一种方法就是,在输入框内提供一些默认值,这些值可能是对的,因此用户也不需要输入。同样,也希望在程序调用时用户能够指定一个文件名或文件的大小。因此, 如下打开一个文本编辑窗口,将对话框的定义语句定义如下:Function GetData, filename, XSize = xsize, YSize = ysize, $ Cancel = cancel, Parent = parent 关键字Cancel 是一个输出型变量,它用来标示是对话框中的Cancel 按钮还是Accept按钮被按下了。关键字Parent 包含了模式组件程序的GroupLeader 的标示符。(喜欢关键字Group_Lea
11、der 的名字吧)记住在定义模式的base组件时必须有Group Leader。接下来,决定程序在出现错误时怎么处理(作者喜欢将程序控制返回给调用者),以及在没有提供关键字时设置关键字的默认值。增加如下所示:On_Error, 2; Return to caller. IF N_Elements (filename) EQ 0 THEN $ filename = Filepath (Root_Dir=Coyote(), ctscan.dat ) ELSE $filename = Filepath (Root_Dir=Coyote(), filename) IF N_Elements (xsiz
12、e) EQ 0 THEN xsize = 256 IF N_Elements (ysize) EQ 0 THEN ysize = 256 这里的 Coyote 命令是用于查找Coyote 目录的。如果这个目录存在,那么Coyote 目录将是默认的路径,否则将在当前的目录中查找文件。Filepath 命令将返回一个与设备无关的文件名称。默认的文件为ctscan.dat,一个有256X256 的字节数组。接着,定义对话框的偏移值,时的它定位于屏幕的中心,键入如下:Device, Get_Screen_size = screenSize XCenter = FIX (screenSize 0 / 2
13、 . 0) YCenter = FIX (screenSize 1 / 2 . 0) Xoff = xCenter - 150 Yoff = yCenter 150 定义一个顶级的模式base接下来的就是为这个模式对话框创建一个顶级的base。在定义一个定级的模式base 必须有一个有效的Group Leader,这在前面已经强调了多次。如果把一个Group Leader 通过关键字 Parent传递给程序,那将没什么问题。但事实并非总是如此。例如:如果用户想在IDL命令行中调用该程序,一般来讲,这是不不太可能获得一个有效的Group Leader 的。没有有效的 Group Leader,因
14、而就不得不依赖它是一个阻塞组件。再者, 如果在 IDL 命令行上第一次调用 Xmanager,这个程序将会阻塞,这时再调用程序也不成问题。当 Group Leader 没有定义或者程序GetData 的调用者是它自己本身时,程序就会出现麻烦了。 作者也不清楚该如何走出这进退两难的境地。更让我不喜欢的是,在另一个程序中如果要正确调用该程序,参数Group Leader 就是必不可少的。此外,当在IDL 命令行调用它时, Group Leader 参数就不应该是一个必须的参数。不管如何, 如果指定了Group Leader, 就可以创建顶级的模式base。 如果没有指定Group Leader,那
15、么只有指望在IDL 命令行上调用该程序了,如下所示:IF N_Elements (parent ) NE 0 THEN $ Tlb = Widget_Base(Column =1 , Xoffset = xoff, Yoffset = yoff, $ 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 12 页 - - - - - - - - - Title = Enter File Information , /Modal, $ Group_Leader=parent, /
16、Floating, /Base_Align_Center ) Else $ Tlb=Widget_Base(Column=1, Xoffset=xoff, Yoffset=yoff ,$ Title= Enter File Information , /Base_Align_Center) 注意,设置在顶级的模式base 上的关键字Floating。一个浮动组件总是浮现在Group Leader 程序之上。这可以防止程序隐藏在其他窗口之后。关键字Base_Align_Center 确保顶级 base的子组件在顶级base中以居中方式对齐。定义其他组件定义一个子base,来包含文件名域和文件大小
17、域。子base 并不是真的需要,但使用子base可以将在窗体周围设置一个框,并把它与窗体底部的按钮分隔开来。键入如下:Subbase = Widget_Base (tlb, Column = 1) Filesize = Strlen (filename) * 1.25 FileID = CW_Field (subbase, Title = Filename: ,$Value = filename, XSize = filesize) XsizeID =CW_ Field (subbase, Title = X Size: , $Value=xsize, / Integer) YsizeID =
18、 CW_Field (subbase, Title = Y Size: , $Value =ysize , / Integer) 注意在这里使用的是复合组件CW_Field 。 CW_Field 其实就是在一个可编辑文本框旁放置一个标签组件。而它的事件处理函数能够处理大量的细节。例如:设置CW_Field 的输入值为整数, 那么用户只能在输入域输入整数。另外,当使用这个文本框时,它的返回值就是一个整数,而不是字符数组。这样一来使用这些文本组件就便得更加容易了。接着,建立一个包含Cancel 按钮和 Accept 按钮的 base垒,键入:Butbase = Widget_Base(tlb, R
19、ow=1) Cancel = Widget_button (butbase, Value = Cancel )Accept = Widget_Button ( butbase, Value= Accept )现在已经建立了所有所需的组件,因此可以实现该程序:Widget_Control, tlb, / Realize 在模式对话框中保存信息对话框的作用就是从用户那儿收集信息,然后当用户按下Accept 按钮时将信息返回给用户。 (或根据这些信息做相应的操作)。但是,当用按下Accept 按钮时,对话框就被销毁,阻塞也被解除。 于是问题就出现了:程序所收集的信息应该保存在哪里,进而处理该信息或将
20、信息返回给用户呢?很显然,不要将信息保存在程序内部(比如说,保存在用户值中),因为当程序被销毁时信息也会被销毁。所以,信息必须保存在程序外部。公公块是一种方法,但作者喜欢将信息保存在指针内。在程序中创建一个指针,键入如下所示:ptr = ptr_New (Filename: , Cancel : 1, XSize :0, YSize: 0)这个指针指向一个匿名结构,里面包含了所有希望从窗体中收集的信息。注意有一个名为 Cancel 的字段, 是用来表明用户是按下了Cancel 按钮还是Accept 按钮。 这是信息非常重名师资料总结 - - -精品资料欢迎下载 - - - - - - - -
21、- - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 12 页 - - - - - - - - - 要,因为程序根据不同的值来采取不同的操作。创建 Info 结构与其他组件程序一样,本程序也要创建一个Info 结构来保存程序运行过程中所需的必要的信息。 从这一意义上来说,需要保存的信息有包含文件信息的组件标示符以及信息存储的位置。 info结构定义如下,并将它保存在顶级base 的用户值中。info = fileID: fileID, xsizeID: xsizeID,$ ysizeID:ysizeID,ptr:ptr Widget_Control,
22、 tlb, Set_UValue=info, /No_Copy 创建一个阻塞组件可以用 Xmanager 命令注册程序了。 注意,必须确保这各程序是一个不能使用No_Block关键字的阻塞程序。如果变此程序为无阻塞程序,那么可以在IDL 命令行上使用它而不必具有有效 Group Leader。键入如下所示:XManager, getdata , tlb, Event_Handler = Getdata_Events 从阻塞中返回在程序执行到上述代码时,IDL 已经停止执行组件定义模块中的代码了。程序的所有操作都发生在时间处理模块中。IDL 不会从阻塞中返回,进而执行组件定义模块的编码,直到用户
23、按下 Cancel 或 Accept 按钮后程序被销毁,阻塞被解除。当这发生后,对话框信息就会保存在指针内。在程序将信息返回给用户之前,要做的事情就是获取并处理信息。在本程序中, 要做的事情就是获取文件名、数据文件大小,然后读取文件并将影像数据返回给程序调用者。首先,获取指针内的信息。由于正在操作指针,所以可以删除它,如下:fileInfo = * ptr ptr_free, ptr 现在已经有了打开和读取数据文件所需的信息。当然, 还可以认为, 现在拥有了程序所需要的信息。事实上,程序可能只是获得了不正确的信息。用户可能忘记了键入文件名,或者在输入文件大小的文本框中多加了一位数字,或者他们根
24、本就不知道文件大小而只是猜测而已。 事实上, 当开始读取这个数据文件时,各种意想不到的事都可能发生,因此最好有个心理准备。建立一个 Catch 错误捕获语句来捕捉所有可能发生的意想不到的事,以及在读取数据文件时产生的错误。 (Catch 错误捕获语句的详细信息请参阅227 页的“ Catch 控制语句”。 )键入以下命令:Catch , error IF error NE 0 THEN BEGIN Catch, /Cancel Ok = Dialog_Message (!Err_String) Cancel = 1 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - -
25、- - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 12 页 - - - - - - - - - IF N_Elements (lun) NE 0THEN FREE_LUN, LUN Return, -1 ENDIF 这个错误处理语句将错误信息显示给用户,(以让他们知道出现了一些情况。)设置Cancel 标识(因而用户不必使用函数的返回值),如果文件已打开则关闭文件,并返回-1。接下来,检查一下用户按下了Cancel 按钮。如果是,设置Cancel 标识并返回 -1。键入如下语句:cancel=fileInfo.cancel IF cancel The
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 2022年IDL入门教程十二 2022 IDL 入门教程 十二
限制150内