985 Rate this article:
No rating

Managing a Graphical User Interface within an Object

Daryl Atencio

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.