The javacomponent function

In this blog I have often showed how using Java components can significantly improve Matlab GUI. Here is a simple reminder:

sample Java components integrated in Matlab figure window (click for details)

sample Java components integrated in Matlab figure window (click for details)

Matlab is highly integrated with Java, and Java classes can seamlessly be accessed from Matlab. However, displaying Java GUI objects, as opposed to using computational (non-displayable) Java classes, requires using Matlab’s built-in javacomponent function. I have often used this function in past articles here, and today I would like to describe it in more detail.

javacomponent

javacomponent, available since R14 (Matlab 7.0), is yet another semi-documented built-in function. This means that the function is explained in a comment within the function (which can be seen via the edit(‘javacomponent’) command), but nonetheless does not have official help or doc pages. It is an unsupported function originally intended only for internal Matlab use (which of course doesn’t mean we can’t use it).

javacomponent accepts a component class name (a string) or a reference to a previously-created component object, an optional pixel position parameter (default=[20,20,60,20], just like uicontrol; may also contain the strings ‘North’, ‘South’, ‘East’ or ‘West’), and an optional parent container handle (defaults to the current figure). javacomponent then adds the requested component as a child of the requested parent container and wraps it in a Matlab Handle-Graphics (HG) container. javacomponent returns two handles: the Matlab HG container handle and a reference (handle) to the Java component. Here are some sample invocation formats:

>> [jButton, hButton] = javacomponent('javax.swing.JButton')
hButton =
	javahandle_withcallbacks.javax.swing.JButton
jButton =
          158.002197265625
 
>> javacomponent('javax.swing.JButton','North');
>> javacomponent(javax.swing.JButton('Click me!'),[50,40,80,30]);
>> javacomponent(javax.swing.JButton('Click me!'),'East',hFig);

Note the difference between Java object creation and javacomponent: A pre-created Java object only resides in JVM (Java Virtual Machine) memory, not onscreen, until javacomponent is called to display it. javacomponent only creates objects when a class name (string) parameter is passed to it, as a convenience service to programmers. In practice, it is better to separate these two actions: create the Java object separately, and then pass the object’s reference handle to javacomponent for display. This enables easier error-trapping if the Java object cannot be created or fails to initialize, before attempting to display the object:

% Create and initialize a JScrollBar object
try
   jScrollbar = javaObjectEDT('javax.swing.JScrollBar');
   jScrollbar.setOrientation(jScrollbar.HORIZONTAL);
catch
   error('Cannot create Java-based scroll-bar!');
end
% Display the object onscreen
try
   javacomponent(jScrollbar,'South');
catch
   error('Cannot display Java-base scroll-bar!');
end

Note that Java GUI object should always use the EDT (Event Dispatch Thread). The reasons for this were outlined in the recent Matlab-EDT article. For this reason, the JScrollBar is created using the built-in javaObjectEDT function, which exists since R2008a and became documented/supported in R2009a.

javacomponent accepts parent handles that are figures, toolbars, uipanels or uicontainers. Unfortunately, frames are not uicontainers and therefore cannot be used as javacomponent parents. Addendum Aug 6 2010: I made an incorrect statement in the original post here regarding uipanels, which has now been removed. I thank the reader who pointed this out to me.

Once the component has been created, even before it has been placed onscreen, it can be manipulated just like any other Java object. For example:

jButton.setText('Click again!');  % or: set(jButton,'text','…')

The component can also be manipulated to some extent via its HG container, which is of a special Matlab type (class) called hgjavacomponent. This includes getting/setting the component position, position units, visibility, resizing callback, tag, UserData etc:

set(hButton,'units','norm', 'position',[0.2,0.3,0.1,0.05]);
set(hButton,'visible','off'); %note: on/off, not true/false as in Java
set(hButton,'ResizeFcn',{@resizeCallbackFunc,param1,param2});

When adding Java components which are container classes (descendants of java.awt.Container), it is important to remember that only other Java components can be added to these containers. Matlab objects such as axes (for plots or images) and uicontrols cannot be added since they do not have a Container wrapper. Therefore, feel free to use these Java containers as long as their contained GUI is limited to Java components (JButton, JComboBox etc.). This limitation is very annoying – it would be very useful to be able to place Matlab axes or uicontrols within a JTabbedPane or JSplitPane. Instead, we need to rely on Matlab-based workarounds (uitab and uisplitpane) which are cumbersome compared to their Java counterparts.

javacomponent can be used to place not only Swing components but also Swing-extended components onscreen. Matlab itself almost never uses Swing components as-is, instead preferring to use MathWorks-derived extensions of these components, generally in the com.mathworks.mwswing or com.mathworks.widgets packages. These packages and their classes are all in the static Java classpath and are therefore automatically available for use by Matlab programmers.

Just like Matlab components, javacomponent can also display third-party or your own Swing-derived components. There are quite a few online sources for Swing components that can easily be incorporated in your Matlab application. Simply download the relevant class files, add them to your static (via classpath.txt) or dynamic (via javaaddpath) Java classpath, use javacomponent to display them, then use their reference handle to manipulate their appearance and behavior.

javacomponent, useful as it is, has several limitations. In its string variant (classname) it requires a fully-qualified classname that is not inferred automatically. It also has a different parameters format than uicontrol, which may confuse users. javacomponent also cannot display java.awt.Window components. Finally, it returns two handles – one is a handle() reference of the Java object; the second an HG handle (a double numeric value) of the automatically-created HG container – users are often confused as to which property should be set on which of these handles.

javacomponent-based utility functions

To overcome these limitations, I created UIComponent – a utility that merges uicontrol and javacomponent, available for download on the File Exchange. It accepts all uicontrol parameters and styles, as well as any other displayable Java (Swing/AWT) class. uicontrol‘s calling syntax was preserved for full backwards compatibility. uicomponent uses the built-in uicontrol whenever possible (for standard Matlab styles), and javacomponent for all other Java classes.

uicomponent returns the same two handles that javacomponent returns (namely, a Java reference handle and a numeric HG handle), modified to include each other’s properties and handles (yet another undocumented trick that merits a dedicated article). Here are some examples (more can be found in uicomponent‘s help comment):

uicomponent('style','edit', 'String','hello');  % a regular uicontrol
uicomponent(hFig, 'style','edit', 'String','hello'); % specify parent
uicomponent('style','jspinner','value',7);
uicomponent('style','javax.swing.jslider','tag','myObj'); 
uicomponent('style','JComboBox',{1,pi,'text'},'editable',true);

Another File Exchange submission which aims to tackle some of javacomponent‘s limitations is Malcolm Lidierth’s JCONTROL. jcontrol uses Matlab’s new object-oriented class approach and has the benefit of returning just a single handle object, which aggregates the handles for both HG container and the contained Java object.

Related posts:

  1. Common javacomponent problems The javacomponent function is very useful for placing Java components on-screen, but has a few quirks. ...
  2. Javacomponent background color This article explains how to align Java component background color with a Matlab color....
  3. The hgfeval function The semi-documented hgfeval function can be useful for callback chaining - this article explains how...
  4. ismembc – undocumented helper function Matlab has several undocumented internal helper functions that can be useful on their own in some cases. This post presents the ismembc function....
  5. Undocumented feature() function Matlab's undocumented feature function enables access to some internal experimental features...
  6. Matlab and the Event Dispatch Thread (EDT) The Java Swing Event Dispatch Thread (EDT) is very important for Matlab GUI timings. This article explains the potential pitfalls and their avoidance using undocumented Matlab functionality....

Categories: GUI, Handle graphics, Java, Medium risk of breaking in future versions, Semi-documented function, Stock Matlab function, UI controls

Tags: , , , , ,

Bookmark and SharePrint Print

11 Responses to The javacomponent function

  1. cdm says:

    Is it possible to get html links working using this method?
    Something like the following (which doesn’t work):
    **[edited for clarity]**

    hEdit = uicontrol('style','edit','max',80,'pos',[20,20,150,20]);
    jEdit = findjobj(hEdit);
    vEdit = jEdit.getViewport;
    wEdit = vEdit.getComponent(0);
    wEdit.setEditorKit(javax.swing.text.html.HTMLEditorKit);
    set(wEdit,'Text','<a href="http://www.google.com" rel="nofollow">Go to Google!</a>');

    This works, even underlines the links and colors them blue, but won’t open a browser if you click on them. Thoughts?

  2. Pingback: Fixing a Java focus problem | Undocumented Matlab

  3. MJJ says:

    Are there any work-arounds to get a component to fill the entire figure area (pane), so resizing works well?
    e.g.

    javacomponent('javax.swing.JButton','East');

    would create a button but it would only be attached to the right-handed side of the pane. If a button is created in pure Java with borderlayout and is placed in the center, it will expand to fill the entire parent, and also resize with it.

    • @Martin (MJJ) – yes, this is possible: javacomponent returns two handles if you use its regular invocation form: javacomponent(component,position,container) (i.e., not the form that you have used) – the second handle is a handle to the regular HG Matlab container. You can easily modify this HG container’s Units property to ‘normalized’ and this will keep your component’s size and position synchronized with its container. If the container if the figure, you’re all set. If not, then you need to also fix the container and so on, just as you would do for any Matlab HG control.

      If you need finer-grained control (for example: attach to bottom-right, while preserving the pixel size), you can always trap the container’s ResizeFcn and modify the component size and/or position programmatically.

      Side-note: the 2-argument javacomponent form that you mentioned does not return an HG container because the JButton is attached to the figure’s content directly, not via a java.awt.Panel container which is assigned to the HG handle. Using this method is actually a topic for an entire future article, due to the possibilities that it enables…

    • MJJ says:

      Thanks for the quick reply!

      I guess it kinda works:

      f = figure('menuBar','none','toolBar','none','handleVisibility','off');
      pos = getpixelposition(f);
      [b c] = javacomponent({'javax.swing.JButton','I''d hit that!'}, [0 0 pos(3:4)], f)
      set(c,'Units', 'normalized');

      will give you a nice big button (or small if you resize) but if you make it really big you can see that it is really anchored to the SW borders and that there actually is a small gap in the NE borders.

      Will I just have to live with that or do you have more tricks up your sleeve?

    • @Martin (MJJ) – The gap is due to external margins that each control has, and internal margins (insets) of the containing RootPane. They are only a few pixels in size – is it that bothersome?

    • MJJ says:

      I guess I can live with that :)

      I made a blunder somewhere in my larger GUI app, which gave a larger gap, now it’s only a few pixels.

  4. GDL says:

    I have been unsuccessful in actually changing the contents of a the editable JComboBox specified by your example above. Can you please suggest a procedure for this? Thanks!

    • @GDL – updating the JComboBox is easy:

      h = uicomponent('style','JComboBox',{1,pi,'text'}, 'editable',true);
      set(h,'SelectedItem','text');
  5. Julien says:

    hello,
    Is it possible to set the background of javacomponents transparent ? I have 2 JLabel which overlay (this is deliberate) so that one is hiding a text part of the other one… Could you help me please ?

    • @Julien – all Matlab GUI controls, including uicontrols and javacomponents, use a heavyweight java.awt.Panel container, rather than a lightweight javax.swing.JPanel. Unfortunately, the heavyweight Panels, unlike lightweight JPanels, cannot be made transparent. This means that even if the control or component is made transparent, this would still have no effect since their containing Panel is opaque. See an interesting discussion on this here. Note that while individual controls are opaque, the entire figure window can be made fully or partially transparent, as I have recently shown.

      To solve your immediate question about overlapping labels, you could perhaps simply use overlapping text labels that are displayed on an invisible axes (i.e., no grids, no x/y labels etc.).

Leave a Reply

Your email address will not be published. Required fields are marked *

*

<pre lang="matlab">
a = magic(3);
sum(a)
</pre>