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!



Not All Supernovae Are Created Equal: Rethinking the Universe’s Measuring Tools

Not All Supernovae Are Created Equal: Rethinking the Universe’s Measuring Tools

6/3/2025

Rethinking the Reliability of Type 1a Supernovae   How do astronomers measure the universe? It all starts with distance. From gauging the size of a galaxy to calculating how fast the universe is expanding, measuring cosmic distances is essential to understanding everything in the sky. For nearby stars, astronomers use... Read More >

Using LLMs To Research Remote Sensing Software: Helpful, but Incomplete

Using LLMs To Research Remote Sensing Software: Helpful, but Incomplete

5/26/2025

Whether you’re new to remote sensing or a seasoned expert, there is no doubt that large language models (LLMs) like OpenAI’s ChatGPT or Google’s Gemini can be incredibly useful in many aspects of research. From exploring the electromagnetic spectrum to creating object detection models using the latest deep learning... Read More >

From Image to Insight: How GEOINT Automation Is Changing the Speed of Decision-Making

From Image to Insight: How GEOINT Automation Is Changing the Speed of Decision-Making

4/28/2025

When every second counts, the ability to process geospatial data rapidly and accurately isn’t just helpful, it’s critical. Geospatial Intelligence (GEOINT) has always played a pivotal role in defense, security, and disaster response. But in high-tempo operations, traditional workflows are no longer fast enough. Analysts are... Read More >

Thermal Infrared Echoes: Illuminating the Last Gasp of a Dying Star

Thermal Infrared Echoes: Illuminating the Last Gasp of a Dying Star

4/24/2025

This blog was written by Eli Dwek, Emeritus, NASA Goddard Space Flight Center, Greenbelt, MD and Research Fellow, Center for Astrophysics, Harvard & Smithsonian, Cambridge, MA. It is the fifth blog in a series showcasing our IDL® Fellows program which supports passionate retired IDL users who may need support to continue their work... Read More >

A New Era of Hyperspectral Imaging with ENVI® and Wyvern’s Open Data Program

A New Era of Hyperspectral Imaging with ENVI® and Wyvern’s Open Data Program

2/25/2025

This blog was written in collaboration with Adam O’Connor from Wyvern.   As hyperspectral imaging (HSI) continues to grow in importance, access to high-quality satellite data is key to unlocking new insights in environmental monitoring, agriculture, forestry, mining, security, energy infrastructure management, and more.... Read More >

1345678910Last
9136 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.