Quantcast
Channel: Undocumented Matlab » UIInspect
Viewing all articles
Browse latest Browse all 12

Uicontrol callbacks

$
0
0

In my previous post I showed how we can extensively customize a Matlab uicontrol’s appearance and behavior by accessing its undocumented underlying Java object. In this post I will show how to further customize the control’s behavior using the callbacks exposed by its underlying object.

Matlab’s uicontrol handles normally expose only a few event callbacks. These are ‘CreateFcn’, ‘DeleteFcn’, ‘ButtonDownFcn’, ‘KeyPressFcn’ and the control-specific ‘Callback’. In contrast, the underlying Java control exposes many more callbacks: 26 standard callbacks, plus a few control-specific callbacks, as follows:

  • AncestorMovedCallback – fired when one of the component’s container ancestors has changed its position relative to its container.
  • AncestorAddedCallback – fired when one of the component’s container ancestors has been added to another container
  • AncestorRemovedCallback – fired when one of the component’s container ancestors has been removed from the component’s hierarchy
  • AncestorResizedCallback – fired when one of the component’s container ancestor has been resized
  • ComponentAddedCallback – fired when a sub-component is added as a direct child to this component. Compare: ComponentRemovedCallback
  • ComponentHiddenCallback – fired when the component is hidden (setVisible(false)). Compare: ComponentShownCallback
  • ComponentMovedCallback – fired when the component is moved within its container. Since Java components are enclosed in a tight-fitting HG container, this callback will never fire for them: it does not fire when the container moves or resizes, only when the component’s starting position is moved within it.
  • ComponentRemovedCallback – fired when a sub-component is added as a direct child to this component. Compare: ComponentAddedCallback
  • ComponentResizedCallback – fired when the component is resized, either directly or because its container was resized.
  • ComponentShownCallback – fired when the component is displayed (setVisible(true)). Compare: ComponentHiddenCallback
  • FocusGainedCallback – fired when the component gains GUI focus, by mouse click, Tab click, or calling the component’s requestFocus() method.
  • FocusLostCallback – fired when the component loses focus to another component or window. Compare: FocusGainedCallback
  • HierarchyChangedCallback – fired when the component changes its ancestors (for example, moved from one panel to another).
  • KeyPressedCallback – fired continuously when any keyboard button (including Shift, Ctrl etc.) was pressed while the component had focus. The meta-data contains details about the specific key and modifiers (Alt, Shift, Ctrl, …) that were pressed. Compare: KeyReleasedCallback, KeyTypedCallback
  • KeyReleasedCallback – fired when a keyboard button was released while the component had focus. The meta-data contains details about the specific key and modifiers (Alt, Shift, Ctrl, …) that were pressed. Compare: KeyPressedCallback
  • KeyTypedCallback – similar to KeyPressedCallback, but only fired (continuously) when an actual printable character is clicked. Therefore, for Shift-A, KeyPressedCallback will fire twice (Shift, ‘A’) but KeyTypedCallback will only fire once. Compare: KeyPressedCallback, KeyReleasedCallback
  • MouseClickedCallback – fired when a mouse button is pressed and then released (=clicked) within the component’s bounds. If either the press or the release occurs outside the component’s bounds, the event will not fire. The figure’s ‘SelectionType’ property will be ‘normal’, ‘extend’ or ‘alt’ depending on which button was pressed. Compare: MousePressedCallback, MouseReleasedCallback.
  • MouseDraggedCallback – fired continuously when the mouse is clicked within the component’s bounds and then moved while the button is still depressed (i.e., dragged), even beyond the component’s bounds. The callback event’s meta-data will contain the delta-x and delta-y of the movement (positive for x-right/y-down; negative for x-left/y-up). Compare: MouseMovedCallback
  • MouseEnteredCallback – fired when the mouse is moved (depressed or not) into the component’s bounds. Compare: MouseExitedCallback
  • MouseExitedCallback – fired when the mouse is moved (depressed or not) out of the component’s bounds. Compare: MouseEnteredCallback
  • MouseMovedCallback – fired continuously when the mouse is moved undepressed within the component’s bounds. The callback event’s meta-data will contain the delta-x and delta-y of the movement (positive for x-right/y-down; negative for x-left/y-up). Compare: MouseDraggedCallback
  • MousePressedCallback – fired immediately when the mouse button is depressed (even before it was released) within the component’s bounds. The callback event’s meta-data will contain the click location within the component’s bounds. Compare: MouseClickedCallback, MouseReleasedCallback
  • MouseReleasedCallback – fired immediately when the mouse button is released within the component’s bounds. The callback event’s meta-data will contain the click location within the component’s bounds. Compare: MousePressedCallback
  • MouseWheelMovedCallback – fired immediately when the mouse wheel is turned (even before it was released) within the component’s bounds.
  • PropertyChangeCallback – fired when one of the component’s properties has changed. For example, after setting the component’s text, tooltip or border. Does not fire when modifying the component’s callback properties.
  • VetoableChangeCallback – fired upon a constrained property value change, allowing the callback to intercept and prevent the property change by raising an exception. Of all the Swing components, only JInternalFrame actually declares vetoable properties which can be intercepted.

It should be noted that these callbacks are standard in all Swing GUI controls. Thus, they can be used not just for Matlab uicontrols’ underlying Java objects, but also for any Swing component that you display using Matlab’s built-in javacomponent function.

The specific list of callbacks supported by each component depends on component type. As noted above, some components have additional specific callbacks. For example, ActionPerformedCallback is fired when a user has performed the main action associated with the control (selecting/clicking etc.). This is one of the most commonly used callbacks, one of the few exposed by Matlab HG handles (as the general-purpose ‘Callback’). This callback is implemented by JButton and JCheckBox (for instance), but not by JList or JMenu. CaretUpdateCallback and CaretPositionChangedCallback are only supported by text-entry controls like JTextField or JEditorPane, but not by JSlider or JTabbedPane. Other components have other such specific callbacks.

To see the full list of supported callbacks for a particular object, use the UIINSPECT utility from the File Exchange or use the following code snippet:

>> props = sort(fieldnames(get(javax.swing.JButton)));
>> callbackNames = props(~cellfun(@isempty,regexp(props,'Callback$')));
callbackNames =
    'ActionPerformedCallback'
    'AncestorAddedCallback'
    'AncestorMovedCallback'
    ...

A nice example of using Java callbacks to automatically select (highlight) the content text in a text-box when focus is gained was one of the first online posts in CSSM to use Matlab 7′s new javacomponent Swing integration.

Another typical usage is to set a continuously-firing callback whenever a slider uicontrol is dragged – the Matlab HG callback only fires once after the drag has completed, whereas we often wish to update some value or graphics during the drag events. This can easily be done using JSlider’s underlying object (a Swing JScrollBar) callbacks.


In order to prevent memory leaks in heavily-laden GUIs, it is advisable to get and set callback properties using the handle object, instead of directly on the “naked” Java reference. For this reason, using set/get is discouraged by MathWorks and may even be disabled in some future Matlab release:

jb = javax.swing.JButton;
jbh = handle(jb,'CallbackProperties');
% or for an existing uicontrol: jbh = findjobj(hButton);
set(jbh, 'ActionPerformedCallback',@myCallbackFcn)  % ok!
set(jb,  'ActionPerformedCallback',@myCallbackFcn)  % bad! memory leak

In some future post I plan to present more details about handle() and its intricacies. But in a nutshell, this code snippet is all you need to start working.

Callbacks can be set in the normal Matlab fashion, using one of three methods:

set(jbh, 'ActionPerformedCallback',@myCallbackFcn);
set(jbh, 'ActionPerformedCallback',{@myCallbackFcn,param1,param2});
set(jbh, 'ActionPerformedCallback','disp(123);');

I would be happy to hear how you use these newly-exposed callbacks in your application. Please leave your welcome comments below.

 
Related posts:
  1. Additional uicontrol tooltip hacks Matlab's uicontrol tooltips have several limitations that can be overcome using the control's underlying Java object....
  2. Setting line position in an edit-box uicontrol Matlab uicontrols have many useful features that are only available via Java. Here's how to access them....
  3. uisplittool & uitogglesplittool callbacks Matlab's undocumented uisplittool and uitogglesplittool are powerful toolbar controls - this article explains how to customize their behavior...
  4. Matlab callbacks for Java events in R2014a R2014a changed the way in which Java objects expose events as Matlab callbacks. ...
 

Viewing all articles
Browse latest Browse all 12

Trending Articles