X

NV5 Geospatial Blog

Each month, NV5 Geospatial posts new blog content across a variety of categories. Browse our latest posts below to learn about important geospatial information or use the search bar to find a specific topic or author. Stay informed of the latest blog posts, events, and technologies by joining our email list!



Mapping Earthquake Deformation in Taiwan With ENVI

Mapping Earthquake Deformation in Taiwan With ENVI

12/15/2025

Unlocking Critical Insights With ENVI® Tools Taiwan sits at the junction of major tectonic plates and regularly experiences powerful earthquakes. Understanding how the ground moves during these events is essential for disaster preparedness, public safety, and building community resilience. But traditional approaches like field... Read More >

Comparing Amplitude and Coherence Time Series With ICEYE US GTR Data and ENVI SARscape

Comparing Amplitude and Coherence Time Series With ICEYE US GTR Data and ENVI SARscape

12/3/2025

Large commercial SAR satellite constellations have opened a new era for persistent Earth monitoring, giving analysts the ability to move beyond simple two-image comparisons into robust time series analysis. By acquiring SAR data with near-identical geometry every 24 hours, Ground Track Repeat (GTR) missions minimize geometric decorrelation,... Read More >

Empowering D&I Analysts to Maximize the Value of SAR

Empowering D&I Analysts to Maximize the Value of SAR

12/1/2025

Defense and intelligence (D&I) analysts rely on high-resolution imagery with frequent revisit times to effectively monitor operational areas. While optical imagery is valuable, it faces limitations from cloud cover, smoke, and in some cases, infrequent revisit times. These challenges can hinder timely and accurate data collection and... Read More >

Easily Share Workflows With the Analytics Repository

Easily Share Workflows With the Analytics Repository

10/27/2025

With the recent release of ENVI® 6.2 and the Analytics Repository, it’s now easier than ever to create and share image processing workflows across your organization. With that in mind, we wrote this blog to: Introduce the Analytics Repository Describe how you can use ENVI’s interactive workflows to... Read More >

Deploy, Share, Repeat: AI Meets the Analytics Repository

Deploy, Share, Repeat: AI Meets the Analytics Repository

10/13/2025

The upcoming release of ENVI® Deep Learning 4.0 makes it easier than ever to import, deploy, and share AI models, including industry-standard ONNX models, using the integrated Analytics Repository. Whether you're building deep learning models in PyTorch, TensorFlow, or using ENVI’s native model creation tools, ENVI... Read More >

1345678910Last
10291 Rate this article:
No rating

Managing a Graphical User Interface within an Object

Anonym

In many projects an object will include a Graphical User Interface (GUI) for displaying or manipulating data.  Here is an example – That can be used as a template – that demonstrates how this can be done.  See the method headers and comments in the code for more information.  To try it out:

Save the following code to a file named myobject__define.pro

Open an compile the file in the IDL Development Environment

Execute the following at the command prompt

a.       o = obj_new('myobject')

b.      o->ConstructGUI

;##############################################################################

; This example demonstrates managing a Graphical User Interface (GUI) from an

; object.

;##############################################################################

;------------------------------------------------------------------------------

;+

; The event handler called by XMANAGER.  This is defined by the EVENT_PRO

; keyword to WIDGET_BASE in MYOBJECT::CONSTRUCTGUI.

;

; :Params:

;   sEvent: in, required, type="structure"

;     An IDL widget event structure

;-

In many projects an object will include a Graphical User Interface (GUI) for displaying or manipulating data.  Here is an example – That can be used as a template – that demonstrates how this can be done.  See the method headers and comments in the code for more information.  To try it out:

Save the following code to a file named myobject__define.pro

Open an compile the file in the IDL Development Environment

Execute the following at the command prompt

a.      o = obj_new ('myobject')

b.     o-> ConstructGUI

;##############################################################################

; This example demonstrates managing a Graphical User Interface (GUI) from an

; object.

;##############################################################################

;------------------------------------------------------------------------------

;+

; The event handler called by XMANAGER.  This is defined by the EVENT_PRO

; keyword to WIDGET_BASE in MYOBJECT::CONSTRUCTGUI.

;

; :Params:

;   sEvent: in, required, type="structure"

;     An IDL widget event structure

;-

pro myobject_event , sEvent

compile_opt idl2, logical_predicate

; Get the instance of MYOBJECT stored in the UVALUE of the top level base

widget_control , sEvent.top, GET_UVALUE=oMyObject

; Send the event structure to the object's event handler

oMyObject-> Event , sEvent

end

 

;------------------------------------------------------------------------------

;+

; This routine will be called when the object's GUI is realized.  This is

; defined by the NOTIFY_REALIZE keyword to WIDGET_BASE in

; MYOBJECT::CONSTRUCTGUI.

;

; :Params:

;   tlb: in, required, type="long"

;     The widget ID of the GUIs top level base

;-

pro myobject_notifyrealize , tlb

compile_opt idl2, logical_predicate

; Get the instance of MYOBJECT stored in the UVALUE of the top level base

widget_control , tlb, GET_UVALUE=oMyObject

; Call the object's NOTIFYREALIZE method

oMyObject-> NotifyRealize

end

 

;------------------------------------------------------------------------------

;+

; Lifecycle method called when object is destroyed via OBJ_DESTROY.  It simply

; calls the destruct method which handles all of the cleanup.

;-

pro myobject :: Cleanup

compile_opt idl2, logical_predicate

self-> Destruct

end

 

;------------------------------------------------------------------------------

;+

; Closes (destroys) the object's GUI

;-

pro myobject ::CloseGUI

compile_opt idl2, logical_predicate

; If the object's top level base ID is not a valid widget ID then do nothing

if ~ widget_info (self.tlb, /VALID_ID) then return

self-> UpdateText ,'Closing the GUI...'

wait , 1.0

widget_control , self.tlb, /DESTROY

self.tlb= 0

end

 

;------------------------------------------------------------------------------

;+

; Constructs the Graphical User Interface

;-

pro myobject ::ConstructGUI

compile_opt idl2, logical_predicate

if widget_info (self. tlb , /VALID_ID) then begin

; The object's top level base ID is valid.  Do not construct another GUI.

return

endif

self.tlb= widget_base (/COLUMN, $

; This keyword defines the name of the event handler that XMANAGER will use

EVENT_PRO='myobject_event', $

; This keyword defines the name of the routine to be called when the GUI is

;  realized

NOTIFY_REALIZE='myobject_notifyrealize', $

TITLE="My Object's GUI", $

TLB_FRAME_ATTR= 1 , $; Do not allow the GUI to be resized

/TLB_KILL_REQUEST_EVENTS)

xSize = 300

wDraw = widget_draw (self.tlb, /BUTTON_EVENTS, /MOTION_EVENTS, $

XSIZE=xSize, YSIZE= 200 )

wText = widget_text (self.tlb, SCR_XSIZE=xSize, /SCROLL, UNAME= 'text', $

YSIZE= 10 )

wBase = widget_base (self.tlb, /ALIGN_RIGHT, /ROW)

wButton = widget_button (wBase, UNAME='ok', VALUE='OK')

wButton = widget_button (wBase, UNAME='close', VALUE='Close')

ss = get_screen_size ()

wGeom = widget_info (self.tlb, /GEOMETRY)

widget_control , self.tlb, XOFFSET=(ss[ 0 ]-wGeom.scr_xSize)/ 2 , $

YOFFSET=(ss[ 1 ]-wGeom.scr_ySize)/ 2

; Set the UVALUE of the top level base to the instance of the object.  This

; way, we can access the object in the event handler and send the event into

; an object method

widget_control , self.tlb, SET_UVALUE=self

widget_control , self.tlb, /REALIZE

end

 

;------------------------------------------------------------------------------

;+

; This method is for cleaning up when the object is destroyed (e.g. Clean up

; heap variables)

;-

pro myobject ::Destruct

compile_opt idl2, logical_predicate

self-> CloseGUI

end

 

;------------------------------------------------------------------------------

;+

; The main event handler method for the object.  This will be called in

; MYOBJECT_EVENT.

;

; :Params:

;   sEvent: in, required, type="structure"

;     An IDL widget event structure

;-

pro myobject ::Event, sEvent

compile_opt idl2, logical_predicate

; A method is defined for each type of widget event.  Send the event to the

; correct handler.

case tag_names (sEvent, /STRUCTURE_NAME) of

'WIDGET_BUTTON': self-> EventButton , sEvent

'WIDGET_DRAW': self-> EventDraw , sEvent

'WIDGET_KILL_REQUEST': begin

self-> UpdateText ,'[X] was pressed'

self-> CloseGUI

end

else : help , sEvent

endcase

end

 

;------------------------------------------------------------------------------

;+

; This method handles button widget events

;

; :Params:

;   sEvent: in, required, type="structure"

;     An IDL {WIDGET_BUTTON} structure

;-

pro myobject ::EventButton, sEvent

compile_opt idl2, logical_predicate

case widget_info (sEvent. id , /UNAME) of

'close': begin

self-> UpdateText ,'Close button pressed'

self-> CloseGUI

end

'ok': self-> UpdateText ,'OK button pressed'

else :

endcase

end

 

;------------------------------------------------------------------------------

;+

; This method handles draw widget events.

;

; :Params:

;   sEvent: in, required, type="structure"

;     An IDL {WIDGET_DRAW} structure

;-

pro myobject ::EventDraw, sEvent

compile_opt idl2, logical_predicate

case sEvent.type of

0 : begin

case sEvent.press of

1 : str ='Left mouse button pressed'

2 : str ='Middle mouse button pressed'

4 : str ='Right mouse button pressed'

else :

endcase

end

1 : begin

case sEvent.release of

1 : str ='Left mouse button released'

2 : str ='Middle mouse button released'

4 : str ='Right mouse button released'

else :

endcase

end

2 : str ='Mouse motion'

else :

endcase

if ( n_elements (str) EQ 0 ) then return

str+=' ['+ strtrim (sEvent.x, 2 )+','+ strtrim (sEvent.y, 2 )+']'

self-> UpdateText , str

end

 

;------------------------------------------------------------------------------

;+

; This method is for accessing widget IDs

;

; :Returns:

;   The widget ID if a valid NAME (uname) is input and 0 otherwisee

;

; :Params:

;   name: in, required, type="string"

;     The uName of the widget whose ID is to be returned

;

; :Keywords:

;   PARENT: in, optional, type="integer"

;     The widget ID of the parent widget whose children are to be searched.  If

;     not set the GUI's top level base will be used.

;-

function myobject ::GetWID, name, $

PARENT=wParent

compile_opt idl2, logical_predicate

if ( n_elements (wParent) EQ 0 ) then wParent = self.tlb

return , widget_info (wParent, FIND_BY_UNAME=name)

end

 

;------------------------------------------------------------------------------

;+

; Lifecycle method for initializing an instance of the object

;

; :Returns:

;   1 if the object initializes successfully and 0 otherwise.

;-

function myobject ::Init

compile_opt idl2, logical_predicate

; Initialize any member variables here

return , 1

end

 

;------------------------------------------------------------------------------

;+

; Called by MYOBJECT_NOTIFYREALIZE after the GUI has been realized.

;-

pro myobject ::NotifyRealize

compile_opt idl2, logical_predicate

; Start the event handler

xmanager ,'myobject', self.tlb

end

 

;------------------------------------------------------------------------------

;+

; The method adds a string or an array of strings to the text widget

;

; :Params:

;   strNew: in, required, type="string"

;     The string(s) to be added to the text widget

;-

pro myobject ::UpdateText, strNew

compile_opt idl2, logical_predicate

wText = self-> GetWID ('text')

ySize = ( widget_info (wText, /GEOMETRY)).ySize

widget_control , wText , /APPEND, SET_VALUE=strNew

widget_control , wText , GET_VALUE=str

widget_control , wText , SET_TEXT_TOP_LINE=( n_elements (str)-ySize+ 2 )> 0

end

;------------------------------------------------------------------------------

;+

; Class structure definition

;

; :Fields:

;   tlb: The widget ID of the GUI's top level base.  This can be used to access

;        all widgets in the GUI.

;-

pro myobject__define

compile_opt idl2, logical_predicate

void = {myobject$

,tlb: 0L $

}

end

pro myobject_event , sEvent

compile_opt idl2, logical_predicate

; Get the instance of MYOBJECT stored in the UVALUE of the top level base

widget_control , sEvent.top, GET_UVALUE=oMyObject

; Send the event structure to the object's event handler

oMyObject-> Event , sEvent

end

 

;------------------------------------------------------------------------------

;+

; This routine will be called when the object's GUI is realized.  This is

; defined by the NOTIFY_REALIZE keyword to WIDGET_BASE in

; MYOBJECT::CONSTRUCTGUI.

;

; :Params:

;   tlb: in, required, type="long"

;     The widget ID of the GUIs top level base

;-

pro myobject_notifyrealize , tlb

compile_opt idl2, logical_predicate

; Get the instance of MYOBJECT stored in the UVALUE of the top level base

widget_control , tlb, GET_UVALUE=oMyObject

; Call the object's NOTIFYREALIZE method

oMyObject-> NotifyRealize

end

 

;------------------------------------------------------------------------------

;+

; Lifecycle method called when object is destroyed via OBJ_DESTROY.  It simply

; calls the destruct method which handles all of the cleanup.

;-

pro myobject :: Cleanup

compile_opt idl2, logical_predicate

self-> Destruct

end

 

;------------------------------------------------------------------------------

;+

; Closes (destroys) the object's GUI

;-

pro myobject ::CloseGUI

compile_opt idl2, logical_predicate

; If the object's top level base ID is not a valid widget ID then do nothing

if ~ widget_info (self.tlb, /VALID_ID) then return

self-> UpdateText ,'Closing the GUI...'

wait , 1.0

widget_control , self.tlb, /DESTROY

self.tlb= 0

end

 

;------------------------------------------------------------------------------

;+

; Constructs the Graphical User Interface

;-

pro myobject ::ConstructGUI

compile_opt idl2, logical_predicate

if widget_info (self. tlb , /VALID_ID) then begin

; The object's top level base ID is valid.  Do not construct another GUI.

return

endif

self.tlb= widget_base (/COLUMN, $

; This keyword defines the name of the event handler that XMANAGER will use

EVENT_PRO='myobject_event', $

; This keyword defines the name of the routine to be called when the GUI is

;  realized

NOTIFY_REALIZE='myobject_notifyrealize', $

TITLE="My Object's GUI", $

TLB_FRAME_ATTR= 1 , $; Do not allow the GUI to be resized

/TLB_KILL_REQUEST_EVENTS)

xSize = 300

wDraw = widget_draw (self.tlb, /BUTTON_EVENTS, /MOTION_EVENTS, $

XSIZE=xSize, YSIZE= 200 )

wText = widget_text (self.tlb, SCR_XSIZE=xSize, /SCROLL, UNAME= 'text', $

YSIZE= 10 )

wBase = widget_base (self.tlb, /ALIGN_RIGHT, /ROW)

wButton = widget_button (wBase, UNAME='ok', VALUE='OK')

wButton = widget_button (wBase, UNAME='close', VALUE='Close')

ss = get_screen_size ()

wGeom = widget_info (self.tlb, /GEOMETRY)

widget_control , self.tlb, XOFFSET=(ss[ 0 ]-wGeom.scr_xSize)/ 2 , $

YOFFSET=(ss[ 1 ]-wGeom.scr_ySize)/ 2

; Set the UVALUE of the top level base to the instance of the object.  This

; way, we can access the object in the event handler and send the event into

; an object method

widget_control , self.tlb, SET_UVALUE=self

widget_control , self.tlb, /REALIZE

end

 

;------------------------------------------------------------------------------

;+

; This method is for cleaning up when the object is destroyed (e.g. Clean up

; heap variables)

;-

pro myobject ::Destruct

compile_opt idl2, logical_predicate

self-> CloseGUI

end

 

;------------------------------------------------------------------------------

;+

; The main event handler method for the object.  This will be called in

; MYOBJECT_EVENT.

;

; :Params:

;   sEvent: in, required, type="structure"

;     An IDL widget event structure

;-

pro myobject ::Event, sEvent

compile_opt idl2, logical_predicate

; A method is defined for each type of widget event.  Send the event to the

; correct handler.

case tag_names (sEvent, /STRUCTURE_NAME) of

'WIDGET_BUTTON': self-> EventButton , sEvent

'WIDGET_DRAW': self-> EventDraw , sEvent

'WIDGET_KILL_REQUEST': begin

self-> UpdateText ,'[X] was pressed'

self-> CloseGUI

end

else : help , sEvent

endcase

end

 

;------------------------------------------------------------------------------

;+

; This method handles button widget events

;

; :Params:

;   sEvent: in, required, type="structure"

;     An IDL {WIDGET_BUTTON} structure

;-

pro myobject ::EventButton, sEvent

compile_opt idl2, logical_predicate

case widget_info (sEvent. id , /UNAME) of

'close': begin

self-> UpdateText ,'Close button pressed'

self-> CloseGUI

end

'ok': self-> UpdateText ,'OK button pressed'

else :

endcase

end

 

;------------------------------------------------------------------------------

;+

; This method handles draw widget events.

;

; :Params:

;   sEvent: in, required, type="structure"

;     An IDL {WIDGET_DRAW} structure

;-

pro myobject ::EventDraw, sEvent

compile_opt idl2, logical_predicate

case sEvent.type of

0 : begin

case sEvent.press of

1 : str ='Left mouse button pressed'

2 : str ='Middle mouse button pressed'

4 : str ='Right mouse button pressed'

else :

endcase

end

1 : begin

case sEvent.release of

1 : str ='Left mouse button released'

2 : str ='Middle mouse button released'

4 : str ='Right mouse button released'

else :

endcase

end

2 : str ='Mouse motion'

else :

endcase

if ( n_elements (str) EQ 0 ) then return

str+=' ['+ strtrim (sEvent.x, 2 )+','+ strtrim (sEvent.y, 2 )+']'

self-> UpdateText , str

end

 

;------------------------------------------------------------------------------

;+

; This method is for accessing widget IDs

;

; :Returns:

;   The widget ID if a valid NAME (uname) is input and 0 otherwisee

;

; :Params:

;   name: in, required, type="string"

;     The uName of the widget whose ID is to be returned

;

; :Keywords:

;   PARENT: in, optional, type="integer"

;     The widget ID of the parent widget whose children are to be searched.  If

;     not set the GUI's top level base will be used.

;-

function myobject ::GetWID, name, $

PARENT=wParent

compile_opt idl2, logical_predicate

if ( n_elements (wParent) EQ 0 ) then wParent = self.tlb

return , widget_info (wParent, FIND_BY_UNAME=name)

end

 

;------------------------------------------------------------------------------

;+

; Lifecycle method for initializing an instance of the object

;

; :Returns:

;   1 if the object initializes successfully and 0 otherwise.

;-

function myobject ::Init

compile_opt idl2, logical_predicate

; Initialize any member variables here

return , 1

end

 

;------------------------------------------------------------------------------

;+

; Called by MYOBJECT_NOTIFYREALIZE after the GUI has been realized.

;-

pro myobject ::NotifyRealize

compile_opt idl2, logical_predicate

; Start the event handler

xmanager ,'myobject', self.tlb

end

 

;------------------------------------------------------------------------------

;+

; The method adds a string or an array of strings to the text widget

;

; :Params:

;   strNew: in, required, type="string"

;     The string(s) to be added to the text widget

;-

pro myobject ::UpdateText, strNew

compile_opt idl2, logical_predicate

wText = self-> GetWID ('text')

ySize = ( widget_info (wText, /GEOMETRY)).ySize

widget_control , wText , /APPEND, SET_VALUE=strNew

widget_control , wText , GET_VALUE=str

widget_control , wText , SET_TEXT_TOP_LINE=( n_elements (str)-ySize+ 2 )> 0

end

;------------------------------------------------------------------------------

;+

; Class structure definition

;

; :Fields:

;   tlb: The widget ID of the GUI's top level base.  This can be used to access

;        all widgets in the GUI.

;-

pro myobject__define

compile_opt idl2, logical_predicate

void = {myobject$

,tlb: 0L $

}

end



Please login or register to post comments.