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:
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