[转帖][数据结构]IDl中全局变量存储和设计分析_play in the free wo...

来源:百度文库 编辑:神马文学网 时间:2024/04/28 12:52:34
[转帖][数据结构]IDl中全局变量存储和设计分析2007-08-31 13:25

原文引自qqz的博客,此人系星图一技术狂人博客中不少文章值得好好读读,点击此处查看原文

对全局变量的处理是IDL语言的特色之一!
在IDL语言中没有全局变量的概念,所有的变量都是局部变量,只在当前的程序中有效。但是在实际的编程中,大部分情况下全局的变量又是必须的,那如何处理
IDl中的所需的全局变量呢?本文探讨IDL使用中常用处理方法。

1 common----定义公共区
在程序中用common命令定义一个公共区,在公共区中保存程序中所需的公共变量。具体形式如下:
COMMON Block_Name, Variable1, Variable2, ..., Variablen
其原理是,在内存中定义一个公共区来存储变量,需要这些变量的程序,只要引用这个公共区的名称(Block_Name)就可,公共区中可以存放多个变量,支持
IDl中所以的变量类型。
例子:
RO    vartest
common vart , a,b,c    ;定义所需的公共区
a=2&b=3&c=4
print,(a*b*c)
vartest2            
End
Pro vartest2
common vart            ;引用公共区
print,(a+b)
End


注意:

common的方式来定义全局变量,是早期IDl程序使用方法,

用这种方法来处理全局变量,变量管理很混乱而且程序维护性差。

现在程序已经不使用这种方法,不推荐使用。

--------------------------------------------------------------------------------------------------------------

2 DEFSYSV ---定义系统变量
在程序中用defsysv来定义用户自己的系统变量。具体形式如下:
DEFSYSV, Name, Value
IDL的的系统都以!开头,IDl有很多已定义好现成的系统变量(详细细节请看帮助System Variables ),如:!DPI ,!MAP,!PI ,!CPU 。。。
它们都可以直接使用,如!DPI表示双精度圆周率的值。
用户自定义系统变量后,就可以直接使用,支持所有的变量类型

例子 :
Pro vartest2
c=!sysvar_a+!sysvar_b
print,c
End

PRO    vartest
a=2
b=3
defsysv,'!sysvar_a',a
defsysv,'!sysvar_b',b
c =!sysvar_a * !sysvar_b
print,c
vartest2
End

注意:
1)DEFSYSV 程序一次只能定义一个系统变量;
2)所有的系统变量名称只能以!开头;
3)用DEFSYSV 的系统变量 的存在周期和编译器一样,除非关闭编译器或reset才能使系统变量无效;
4)一般在系统变量中保存一些使用频率很高的差数,如:程序系统路径,draw大小。
5)不存储数据量很大的数组,无法销毁,生命太长;
6)一般只在程序开始时定义,随意使用会使程序很混乱,很难维护;

-----------------------------------------------------------------------------------------------------------------------

3 用uvalue 来储存变量
uvalue是个好东西,里面可以存放各种数据类型,在IDL中有两个地方有uvalue,一个是所有界面组件中,有uvalue关键字可以存放变量,二是在所有图型类(IDlgr开头的类)中
uvalue属性,可以存储变量,具体形式如下:
组件:
定义:
可以在初始化中定义    wtlb=widget_base(uvalue = var)
用widget_control对已有的组件进行设置    widget_control,wtlb,set_uvalue=var
引用:
    widget_control,wtlb,get_uvalue=var
类:
定义:
初始化中定义    omodel = obj_new('IDLgrmodel',uvalue=var)
已有类进行定义     omodel->setproperty,uvalue=var
引用:
omodel -> getproperty,uvalue=var
一般类中只存储与它功能相关的数据或差数。程序中所需的全局变量一般存储在tlb(顶级base)的uvalue中。因为tlb的值就是事件结构体中的event.top,可以直接获得。
根据tlb的值,用widget_control,wtlb,get_uvalue=var,就可以直接获得存储的全局变量var
例子:

pro testbar_cleanup,base
;清空内存
widget_control,base,get_uvalue=pstate ; 获取全局变量
for i=0,n_tags(*pstate)-1 do begin
   case size((*pstate).(i), /tname) of
    'POINTER':$
     ptr_free, (*pstate).(i)
    'OBJREF':$
     obj_destroy, (*pstate).(i)
    else:
endcase
end
ptr_free,pstate
end


pro testbar_event, event
print,event
help,event
widget_control, event.top, get_uvalue=pstate   ; 获取全局变量
uname =widget_info(event.id,/uname)
case uname of
   'quit':begin
    widget_control, event.top,/destroy
    end
   'open':begin
    print, 'widget user uname = ' + uname
    print, 'open'
    file = dialog_pickfile(/read, filter = '*.jpg',title='读取数据')
    if file eq '' then return
    print, file
    read_jpeg, file, image, /true
    image = congrid(image,3,600,450)
    (*pstate).oimage = obj_new('idlgrimage',image)
    (*pstate).omodel->add, (*pstate).oimage
    (*pstate).owin->draw, (*pstate).oview
   end
   else:
endcase
end
;-----------------------------------------------------------------------
pro testbar
;组件系统
base = widget_base(title = 'qqz_练习',$
       mbar=bar_base,$
       xsize=600,$
       ysize=450,$
       /kill_notify)
   file_menu = widget_button(bar_base, value='file', /menu)
    file_bttn1 = widget_button(file_menu, value='open', uname='open')
    file_bttn2 = widget_button(file_menu, value='file item 2', uname='file 2')
    file_bttn3 = widget_button(file_menu, value='file item 3', uname='file 3')
    file_bttn4 = widget_button(file_menu, value='quit', uname='quit')

   opt_menu = widget_button(bar_base, value='options', /menu)
    opt_bttn1 = widget_button(opt_menu,value='options item 1', uname='file1')
    opt_bttn2 = widget_button(opt_menu,value='options item 2', uname='file2')
    opt_bttn3 = widget_button(opt_menu,value='options item 3', uname='file3')
    opt_pr = widget_button(opt_menu,value='options pull-right', /menu)
     pr_bttn1 = widget_button(opt_pr, value='options pull   item1', uname='pr 1')
     pr_bttn2 = widget_button(opt_pr, value='options pull   item2', uname='pr 2')
    opt_bttn5 = widget_button(opt_menu,value='options item 5', uname='file5')
   help_menu = widget_button(bar_base,value='help', /menu)
    help_buttn1 = widget_button(help_menu,value='help item 1', uname= 'help 1')
    help_buttn2 = widget_button(help_menu,value='help item 2', uname= 'help 2')
   wdraw = widget_draw(base,graphics_level=2,$
         retain=2,$
         xsize=600,$
         ysize=450)
widget_control, base, /realize
;
widget_control, wdraw, get_value=owin
;对象系统
oview = obj_new('IDlgrview', viewplane_rect=[0,0,600,450],dimension=[600,450])

omodel = obj_new('IDlgrmodel', name='topmodel')

oview->add, omodel
;全局变量
state = {owin:owin    ,$
     oview:oview   ,$
     omodel:omodel   ,$
     oimage:obj_new() ,$
     wdraw:wdraw    $
     }
;把全局变量结构体的指针付给顶base
widget_control, base,set_uvalue=ptr_new(state, /no_copy)
xmanager, 'testbar', base,cleanup='testbar_cleanup',   /no_block
end

注意:
1)用tlb的uvalue来存储全局变量,是IDL全局变量处理最主要的手段。
2)uvalue中也只能存放一个变量,存放多个全局变量,一般采用在uvalue中存放一个结构体的指针。
例如:
state ={a:a,b:b,c:c,d:d }
widget_control,wtlb,set_uvalue=ptr_new(state,/no_copy)
3)面向对象的程序设计,大部分的变量都可以存在各功能类或子base的uvalue里,真正需要存在tlb的全局变量不多。

---------------------------------------------------------------------------------------------------------------------------
4 用sav来存储系统参数
一个完善的软件,涉及到的系统各种差数很多,参数模块也很多,留给用户交换配置的参数也很多,就像IDL编译器分file-prefercences。
原理是:对于与主模块非常独立的模块之间参数传递,定义一个结构体,存储需要传递的参数。然后在把结构体以sav文件的形式存在指定的路径下。
需要这些参数是把这个sav文件,restore了就可以了。著名的IDL开源软件dave就采用的这种手段
例子:

Pro vartest2
;从指定目录还原sav文件
restore,!sysfile
(*sys).a=3
(*sys).b=3
(*sys).c=obj_new('IDlgrmodel')
;改变后数据在存储
save,filename=!sysfile,sys
print,'*sys'
help,*sys,/str
obj_destroy,(*sys).c
ptr_free,sys
End
PRO   vartest
;定义系统结构体
     sys_define={         $
     a:1    ,$  
     b:2    ,$
     c:obj_new()   $   
         }
;
print,'sys_define'        
help,sys_define,/str
;
defaults_file = 'C:\.defs.sav'
;自定义系统参数,保存路径名
defsysv, '!sysfile', defaults_file
sys=ptr_new(sys_define)
;把参数保存在自定目录下
save,filename=!sysfile,sys

ptr_free,sys
vartest2
End

注意:适用多模块,大型系统,一般程序不推荐使用。

---------------------------------------------------------------------------------------------------------------------------
5 完全面向文件变量存储
这种方法比较落后,不推荐使用,仅让大家有所了解。一些古老或对IDL不太了解的研究者,会用到这种方法
这种方法没有所谓的全局变量,所有生成的变量或数据,都把它们写成txt文件文件或dat的数据。别的程序需要调用的时候,在读这些txt或dat。这种程序
bug率非常高。程序很难控制。

后记:
一般程序设计会使用一种或几种相结合。常用的方法用defsysv和uvalue。

大型软件会用到sav。

全局变量中是在内存中常驻的,所以尽量减少变量冗余,和
大型数组。