Rich Matlab editbox contents

In an earlier post, I mentioned that most Matlab uicontrols support HTML strings. Unfortunately, HTML is not supported in multi-line editbox contents. Today I will show how this limitation can be removed for a multi-line editbox, thereby enabling rich contents (enabling HTML for a single-line editbox needs a different solution).

We first need to get the editbox’s underlying Java object, as explained in my previous article about the findjobj utility. Since a multi-line editbox is contained within a scroll-pane, we need to dig within the scrollpane container to find the actual editable area object:

In this listing, we see that jScrollPane contains a JViewport and two scrollbars (horizontal and vertical), as expected from standard Java scroll-panes. We need the internal hgTextEditMultiline object:

The retrieved jEditbox reference, is an object of class com.mathworks.hg.peer.EditTextPeer$hgTextEditMultiline, which indirectly extends the standard javax.swing.JTextPane. The default Matlab implementation of the editbox uicontrol simply enables a multi-line vertical-scrollable text area using the system font. However, the underlying JTextPane object enables many important customizations, including the ability to specify different font attributes (size/color/bold/italic etc.) and paragraph attributes (alignment etc.) for text segments (called style runs) and the ability to embed images, HTML and other controls.

Setting rich contents can be done in several alternative ways. From easiest to hardest:

Setting page URL

Use the setPage(url) method to load a text page from the specified URL (any pre-existing editbox content will be erased). The page contents may be plain text, HTML or RTF. The content type will automatically be determined and the relevant StyledEditorKit and StyledDocument will be chosen for that content. Additional StyledEditorKit content parsers can be registered to handle additional content types. Here’s an example loading an HTML page:

jEditbox.setPage('http://tinyurl.com/c27zpt');

where the URL’s contents are:

<html><body><imgsrc="images/dukeWaveRed.gif"width="64"height="64">
This is an uneditable <code>JEditorPane</code>, which was
<em>initialized</em> with <strong>HTML</strong> text
<fontsize=-2>from</font> a <fontsize=+2">URL</font>.
<p>An editor pane uses specialized editor kits to read, write,
display, and edit text of different formats. The Swing text
package includes editor kits for plain text, HTML, and RTF.
You can also develop custom editor kits for other formats.
<scriptlanguage="JavaScript"src="/js/omi/jsc/s_code_remote.js"></script></body></html>

Matlab editbox initialized from an HTML webpage URL

Setting the EditorKit and ContentType

Set the requested StyledEditorKit (via setEditorKit()) or ContentType properties and then use setText() to set the text, which should be of the appropriate content type. Note that setting EditorKit or ContentType clears any existing text and left-aligns the contents (hgTextEditMultiline is center aligned by default). Also note that HTML <div>s get their own separate lines and that <html> and <body> opening and closing tags are accepted but unnecessary. For example:

Let’s show another usage example, of an event log file, spiced with icons and colored text based on event severity. First, define the logging utility function (the icon filenames may need to be changed based on your Matlab release):

HTML editboxes are normally editable, images included. In actual applications, we may wish to prevent editing the display log. To do this, simply call jEditbox.setEditable(false).

Setting a hyperlink handler is easy: first we need to ensure that we’re using an HTML content-type document. Next, set the editbox to be uneditable (hyperlinks display correctly when the editbox is editable, but are unclickable), using jEditbox.setEditable(false). Finally, set the callback function in the editbox’s HyperlinkUpdateCallback property:

Setting the style runs programmatically

Setting the styles programmatically, one style run after another, can be done via the text-pane’s Document property object. Individual character ranges can be set using the Document’s setCharacterAttributes method, or entire style runs can be inserted via insertString. Attributes are updated using the static methods available in javax.swing.text.StyleConstants. These methods include setting character attributes (font/size/bold/italic/strike-through/underline/subscript/superscript and foreground/background colors), paragraph attributes (indentation/spacing/tab-stops/bidi), image icons and any Swing Component (buttons etc.). Here is the end result:

Rich editbox contents: images, controls & font styles

Note that if a styled multi-line editbox is converted to a single-line editbox (by setting hEditbox’s Max property to 1), it loses all style information, embedded images and components. Returning to multi-line mode will therefore show only the plain-text.

Related posts:

Rich-contents log panel – Matlab listboxes and editboxes can be used to display rich-contents HTML-formatted strings, which is ideal for log panels. ...

@Amichay – if you use style runs then you can try to use getCharacterAttributes(); if you use HTML you don’t have an easy solution AFAIK, but if you are in control of the data that is placed in the editbox then you can keep meta-data information stored where it can later be retrieved (for example, in the control’s appdata).

Yair, I actually want to get (by copy paste) a text with colored text (such for example as some editros like matlab m-file editor) into the editbox (or if you can suggest something better) and process the text also according to the text color. Can you suggest what to do?

@Amichay – when you copy a styled Matlab text, it gets copied as Rich-Text Formatted (RTF) data. Some applications, like MS Word, automatically know how to use RTF data when you paste sch contents into them. If you need to paste into your own application, you need to create a dedicated RTF-sensitive CCP drop target. This is a very technical issue that is well outside the boundaries of this comment (or blog). You can start here.

Hello, first I would like to thank you for the usefull information I found in your blog. And now to my question: Do you know an easy way to have a matlab editor like features (syntax highliting, smart indent, …) in an editable multiline text box?

thank you very much for your fast response. The code you posted worked quite well, with one exception, which is probably Matlab version dependent. The statement: codeType = com.mathworks.widgets.text.mcode.MLanguage.M_MIME_TYPE;

led in Matlab 2008b to the following Matlab error: ??? Undefined variable “com” or class “com.mathworks.widgets.text.mcode.MLanguage.M_MIME_TYPE”.

Instead of it I used: codeType = com.mathworks.widgets.SyntaxTextPane.M_MIME_TYPE;

Hi Thank you very much for the useful info. In my GUI, I first read a long string from an editbox (multiple lines) and then I’d like to change the font color of a portion of this text and display it in the same editbox. I’m not familiar with HTML coding but that’s what I did using your example above:

the formatted string is displayed in the editbox however, it is no longer divided nicely between multiple lines! There is a very long first line where most of the string is out of the right margin. I was wondering is there is another setting that I need to tune for this to be properly displayed?

@Noushin – of course; HTML is not multi-line by default, as you will notice if you prepare a multi-line HTML file and load it in your browser. To separate lines, you can use the HTML <p> or <br> tags. The W3Schools website is a good reference & tutorial for HTML and related technologies.

Hi Yair, I’m creating a message log on an application I’m working on. I appreciate your tutorial on how to do this using HTML tags. I saw on the w3school website that the HTML “font” tag has been depricated. It says to use style tags instead. I tried modifying your logMessage function to use styles instead of the depricated tags. When I do this, it only works for the most recent line. When I looked closer, it appeared that either “setText” or “getText” is removing a bunch of the HTML tags I put in. As a result, all the previous lines show up unformatted. Please let me know your thoughts. Thanks! ~Andrew

@Andrew – only a subset of CSS is processed correctly by Swing (which is used for Matlab’s controls). I showed a simple example of using CSS styles in the EditorKit section of the article, but note that many style directives are simply ignored. The Font tag may be deprecated but it works great…

Re setText(), remember that it sets the entire text, so you must preserve the previous hyper-text tags and styles when you add new lines. There’s no magic in there, recheck your code.

Hi Yair, Thanks for the feedback. I’ve got one more question for ya. I’m using your logMessage function (modified for my purposes). Any idea on how I could keep the log window from flickering when it updates? It looks like, when you set the text, it jumps to the top, then when setting the caret position, it jumps back down. Is there any way to default it to the bottom of the text? Thanks! ~Andrew

@Andrew – try calling drawnow only after you update the underlying Java component. Also, keep the Java handle cached in the listbox’s UserData or ApplicationData properties (or some other place) so that you don’t need to call findjobj each time you update the log.

How did you get the text to wrap in the “Setting the style runs programmatically” section above? When I place a long line in a multiline editbox formatted for HTML, it continues past the right boundary of the box without wrapping. Did you manually insert breaks in the HTML? Or did the box handle wrapping automatically via some setting?

I forgot to mention: this only applies when a line has no spaces. Otherwise text wraps properly. For instance, if a single word is longer than the width of the box, the editbox expands to the size of that word without providing horizontal sliders. Ideally, there would be horizontal sliders created or the long word would be split onto multiple lines. Can either of those options be achieved?

Here’s an example of “Setting the style runs programmatically”. I thought it might save folks a little time if they want to, for instance, highlight a certain character or do other formatting without involving HTML.

I have modified your logMessage function for my purposes. I am able to show a text on the edit box like what I want by logMessage function , but I don’t know how to remove all the text from the edit box. Actually, I can remove all text by first time to use “set(handles.edit,’String’,”)”. But if I implement logMessage to show text again, the code “set(handles.edit,’String’,”)” is not working any more! Could you please to help me sovle this problem? Thank you in advance!

Thank you again for this post, this is very useful! I was wondering if I could do the same thing for a msgbox() application? Like is there a way similar to this to also edit the text in java/html using a msgbox?

@Hanna – a msgbox is simply a small figure window that has a text label, uicontrol button and (optionally) an axes that displays an icon. Take a look at msgbox.m, it’s pretty simple. You can do the same thing in your own figure window, placing an editbox in there. Then you can customize it as shown in the article.

I’m new to matlab but i have been working on a project where a data from the gui login frame have to be saved on word file(.doc) i have created login frame but unable to get the data into word file. can u please help me on this.

I suspect that either your editbox or its containing figure is hidden (in which case findjobj cannot find it), or has not yet had time to fully render (in which case, adding a simple drawnow; pause(0.2);might help). The latter is more probable, since it could be a direct consequence of one of the changes introduced in 14b, namely that figures are now created asynchronously.

It is worth noting that from time to time for no apparent reason I get the following exception. The GUI still works fine though. Any suggestions?

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.plaf.basic.BasicTextUI$RootView.paint(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.paintSafely(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.paint(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$700(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

I have an easy question, I think. I’ve created an edit box and placed a simple HTML text on it. I also have created a button to copy this formatted text to the clipboard when you push on it. But as we are working within the ‘java space’ and the function “get(hObject,’String’)” no longer works, I have no clue on how to do it.

Recent Comments

Yair Altman (1 day 9 hours ago): yes, this post was originally posted in 2011, more than 5 years ago – Matlab has changed a lot since then, including an entirely revised graphics system (HG2). The current...

Andrew (1 day 9 hours ago): I figured it out…actually found it elsewhere but then realized it is mentioned in this original post as well. You can still use getcursorinfo(dcmObject) to get a list of all...

Andrew (1 day 10 hours ago): Hello, Did MATLAB recently change the syntax to this? I am trying to get access to the current list of datacursors programatically, but nothing I have tried seems to work. >>...

Yair Altman (2 days 12 hours ago): @Alex – there is no immediate answer. If you want me to look at your specific code, then email me (altmany at gmail) for a dedicated consulting session.

Yair Altman (2 days 12 hours ago): Perhaps you have an outdated version of export_fig. Try to download the latest version from https://github.com/altmany/exp ort_fig

mimi sam (2 days 13 hours ago): I have “GPL Ghostscript” installed on my PC and I get this : In export_fig at 660 export_fig error. Please ensure: that you are using the latest version of export_fig...

Jaap Nienhuis (3 days 7 hours ago): I frequently make images in Matlab. Is it possible, to render the raster component of the image as a bitmap (image in illustrator) and to render the axes labels etc as vector...

Yair Altman (6 days 9 hours ago): @DavidB + @Guillaume + @TheBlackCat – if I remember correctly, my client wanted the code to continue processing only when the 2 inputs were both vectors, although possibly...

David B (6 days 16 hours ago): @TheBlackCat From the limited information we have available we are assuming the data is a vector. If that is the case then I think something like this code snippet would work nicely...

TheBlackCat (7 days 9 hours ago): It is hard to say without seeing more code. It may very well be that the data can only come in a few formats, so transposing it is the correct thing to do.

Guillaume (7 days 10 hours ago): Well, presumably, the code is operating on vectors, so the alternative could be dataA(:) + dataB(:) But really, the proper alternative would have been to find out why the data...