- Undocumented Matlab - https://undocumentedmatlab.com -

Rich-contents log panel

Posted By Yair Altman On September 18, 2013 | 15 Comments

I often include a log panel in Matlab applications that process data. By sending messages to the log panel, I can avoid msgbox popups and Command Window messages that interfere with the regular workflow. In Matlab, such log panels typically use a simple listbox or editbox control. The problem with this is that all text messages in the log panel look the same. Matlab does not have a documented way to highlight specific messages or words. Well, this has never stopped us before, has it? 🙂

The listbox solution

I have often noted in past articles that most Matlab uicontrols support HTML formatting [1]. We can use a listbox control for our log panel, and use HTML formatting for the various log messages, based on their severity or content. For example:

Listbox with HTML'ed items
Listbox with HTML colored items

uicontrol('Style','list', 'Position',[10,10,70,70], 'String', ...
   {'Hello', 'world', ...
    'What a', ...   % note:  are not needed
    'nice day!'});   % note:  is not needed

Rich listboxes such as this are very easy to set up and use. As I just showed, all it takes is sending an HTML string to a regular listbox. The down-side is that listboxes only display single-line messages, so if our message is too long we need to manually split it into separate listbox lines, which is rather inconvenient. Using HTML <br/> does not work since the allocated line height remains unchanged. We can fix this by playing around with the underlying Java object [2]‘s RowHeight property, but that again is rather inconvenient.

The editbox solution

Instead of a listbox, I often use a multi-line editbox. Unfortunately, HTML is not as-easy to use in multi-line editbox contents, but as I have shown before [3], it is indeed possible and actually quite powerful. In fact, I am using such an editbox-based log panel’s in my online presentation at the MATLAB Computational Finance Virtual Conference [4] tomorrow (Thursday Sep 19, 2013 at 2pm EST / 8pm CEST, see details below):

Real-time trading system demo in Matlab (click to zoom) [5]
Real-time trading system demo in Matlab (click to zoom)

We can see in the screenshot that some log messages (the red warning message) can span multiple lines. Moreover, the panels can be interactively dragged/resized, making the multi-line log messages “flow” based on available space. So using an editbox is preferable to a listbox. The solution implemented in the demo is quite simple:

First we define the logging utility function (the icon filenames may need to be changed based on your Matlab release):

function logMessage(jEditbox,text,severity)
   % Ensure we have an HTML-ready editbox
   HTMLclassname = 'javax.swing.text.html.HTMLEditorKit';
   if ~isa(jEditbox.getEditorKit,HTMLclassname)
      jEditbox.setContentType('text/html');
   end
   % Parse the severity and prepare the HTML message segment
   if nargin < 3,  severity='info';  end
   switch lower(severity(1))
      case 'i',  icon = 'greenarrowicon.gif'; color='gray';
      case 'w',  icon = 'demoicon.gif';       color='black';
      otherwise, icon = 'warning.gif';        color='red';
   end
   icon = fullfile(matlabroot,'toolbox/matlab/icons',icon);
   iconTxt =[''];
   msgTxt = [' ',text,''];
   newText = [iconTxt,msgTxt];
   endPosition = jEditbox.getDocument.getLength;
   if endPosition>0, newText=['
' newText]; end % Place the HTML message segment at the bottom of the editbox currentHTML = char(jEditbox.getText); jEditbox.setText(strrep(currentHTML,[60 '/body>'],newText)); endPosition = jEditbox.getDocument.getLength; jEditbox.setCaretPosition(endPosition); % end of content end

Next, we initialize the log panel editbox and store the editbox’s underlying Java component (jEditbox) using the findjobj [2] utility:

% Prepare the log editbox
hLogPanel = uicontrol('style','edit', 'max',5, 'Parent',hLeftBottomPanel, 'Units','norm', 'Position',[0,0.2,1,0.8], 'Background','w');
% Get the underlying Java editbox, which is contained within a scroll-panel
jScrollPanel = findjobj(hLogPanel);
try
    jScrollPanel.setVerticalScrollBarPolicy(jScrollPanel.java.VERTICAL_SCROLLBAR_AS_NEEDED);
    jScrollPanel = jScrollPanel.getViewport;
catch
    % may possibly already be the viewport, depending on release/platform etc.
end
jEditbox = handle(jScrollPanel.getView,'CallbackProperties');

Now, we can use this logging utility function to log messages in our application. For example:

logMessage(jEditbox, 'a regular info message...');
logMessage(jEditbox, 'a warning message...', 'warn');
logMessage(jEditbox, 'an error message!!!', 'error');
logMessage(jEditbox, 'a regular message again...', 'info');

Rich editbox contents (a log file)
Rich editbox contents (a log file)

HTML editboxes are normally editable, images included. In actual applications, we usually wish to prevent editing the displayed log. To do this, we simply call jEditbox.setEditable(false). Similarly, it is easy to set-up a Matlab callback-function to handle hyperlink clicks in the log panel (unlike what we might think, this is not handled automatically by the HTML processing engine):

% Prevent user editing in the log-panel
jEditbox.setEditable(false);
% Set-up a Matlab callback function to handle hyperlink clicks
set(jEditbox,'HyperlinkUpdateCallback',@linkCallbackFcn);

About the MATLAB Computational Finance Virtual Conference and my presentation

The MATLAB Computational Finance Virtual Conference is a one-day (Thursday Sep 19, 2013) event of hour-long presentations by industry professionals that showcase real-world examples demonstrating how financial-industry researchers and developers can excel at their jobs, improve their research and business processes, reduce costs, and mitigate risks by using Matlab. Registration [6] to the conference is free and it’s a virtual conference, so there’s no need for a tie and jacket and you’re welcome to join…

MATLAB Computational Finance Conference 2013 [4]

My presentation on “A Real-Time Trading System in MATLAB“, is scheduled for 2pm EST / 8pm CEST. Following a half-hour presentation, I will answer audience questions online. The presentation slides can be downloaded here [7]. Here [8] is the recorded presentation video:

The demo system’s user interface showcases the hidden visualization and interactivity potential of Matlab for tracking order executions and charting financial time-series in real time. The undocumented features used in the demo include:

So, even if you’re not interested in real-time financial trading with Matlab, you might find it interesting to see the neat things that Matlab can do using a Java API interface and a few undocumented GUI tricks (such as the rich-contents log that I explained above).
The demo source code is provided here [14] (tradingDemo.m and supporting files). Note that this is provided as-is, free of charge but without any warranty or support. You would naturally need IB-Matlab [15] and an Interactive Brokers account to run it. But you can reuse parts of the source code in your Matlab programs even without an IB account or IB-Matlab.

Categories: GUI, Icons, Low risk of breaking in future versions, UI controls, Undocumented feature


15 Comments (Open | Close)

15 Comments To "Rich-contents log panel"

#1 Comment By Sven On September 18, 2013 @ 10:13

Wonderful timing, Yair. I’m building a complex gui with a lot of my debugging just printing to the screen. My next task/idea was to implement such a log panel. I want to make debugging easier, so I was thinking of making each of my logged messages also have a “debugLevel”. While testing, my application can have a low “debugThreshold”, so that all messages get shown. For production, I can set a higher debugThreshold so that only user-relevant message get shown.

In your experience, have you preferred something like this (ALL messages are generated by the application and sent to the logger, but they’re only printed if they have a high enough debugLevel), or something where you wrap each of your debug strings with:

 
if debugThreshold>3
    logMessage('hey ho')
end

The first method has the highest cost (all messages are created), while the second method is just a little more cumbersome (needing to wrap messages in if-statements inline with your application code).

By the way, there’s a little hiccup in the html parsing of “nargin<3" printing the full code of "nargin<3"

#2 Comment By Yair Altman On September 19, 2013 @ 09:40

@Sven – thanks, the HTML hickup is fixed.

I normally prefer setting some global config indicating the minimal display level. Within the logging function, I then compare the severity of the reported message to the config value and bail out of the function if the message should not be logged. I normally use either 3 severity levels (INFO, WARN, ERROR) or 5 (DEBUG, INFO, WARN, ERROR, FATAL), with the default config level being either INFO or WARN. Naturally this can and should be wrapped in some nice logging class, but I never took the time to do this until now…

#3 Comment By Sven On September 19, 2013 @ 11:10

Thanks Yair, makes sense to me.

I’ve also mused about how, in the production version of any code, it would be great to just snip out all debug-level commands. I’ve considered putting in my own comment-based markup such as:

 
a = magic(3);
% $DEBUG-BEGIN$
if DEBUG_LEVEL > 0
  aStr = sprintf('%g,',a);
  fprintf('Contents of ''a'' are: %s\n',aStr)
end
% $DEBUG-END$
... % rest of code

With syntax like that, you could have the best both worlds. During testing you can run the original code and set the DEBUG_LEVEL to whatever prints your chosen output. Then for production you can have a script that automatically comments out code between $DEBUG-BEGIN$ and $DEBUG-END$ tags, which means that in the production version, you don’t even get the (minor) overhead of checking debug levels throughout the code.

But yes… sometimes it’s easier to think of a good idea than find the time to implement it 🙂

#4 Comment By Chris On October 3, 2013 @ 11:11

Hi Yair,

Another great post. I was just wondering if you could explain the following lines, which seem to do nothing.

currentHTML = char(jEditbox.getText);
jEditbox.setText(strrep(currentHTML,'',newText));

Is this a typo/bug, or am I missing something?

#5 Comment By Yair Altman On October 3, 2013 @ 12:56

@Chris – it’s good that you noticed. This is in fact due to problematic rendering of the code by my blog server engine. The original code in the second line was jEditbox.setText(strrep(currentHTML,'</body>',newText)); and the purpose is to replace the HTML body-end tag with the new text.

Since I couldn’t get around my blog engine’s limitation, I have now replaced that line with the equivalent (although a little more obscure):

jEditbox.setText(strrep(currentHTML,[60 '/body>'],newText));

#6 Comment By Chris On October 7, 2013 @ 07:14

I’ve implemented this log, but I had a few questions about it. [22], and I was hoping you would weigh-in.

#7 Comment By Chris On October 8, 2013 @ 08:07

After getting some feedback on stackexchange, I have a way to dramatically improve performance. Instead of performing getText and setText, you can insert the new HTML at the end of the document in the following way

function logMessage(jEditbox, text)
text = [text ''];

% Place the HTML message segment at the bottom of the editbox
Doc = jEditbox.getDocument();
jEditbox.getEditorKit().read(java.io.StringReader(text), Doc, Doc.getLength());
jEditbox.setCaretPosition(Doc.getLength());
end

#8 Pingback By CopyQuery | Question & Answer Tool for your Technical Queries On October 7, 2013 @ 07:17

[…] to Yair Altman’s excellent post on undocumentedmatlab.com, I’ve tried to implement a GUI logging program using a rich editbox […]

#9 Comment By Holger On October 8, 2013 @ 03:30

Hi Yair,

I was using this for some time (from older posts).
But in R2013b (all prior versions work), the hyperlink feature broke. Not completely, but the mouse cursor doesn’t change to a hand when hovering over a hyperlink.

In addition the following code also does nothing:

jHelpLinkButton = java(findjobj(hButton));
jHelpLinkButton.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.HAND_CURSOR));

When using a “com.mathworks.widgets.HyperlinkTextLabel” (from your book), also the hand cursor doesn’t appear, but at least, the label changes color when hovering.

Any idea, how I can get this working again?
An acceptable workaround would be to change the hyperlink style, so it has an alternate color when hovering over it. But I think I would have to change the default style for hyperlinks in the HTMLEditorKit

#10 Comment By Yair Altman On October 17, 2013 @ 12:32

@Holger – this is probably related to the fact thar R2013b started using Java 7, which is a major overhaul over the previous Java 6. I assume that this broke some functionality of the editbox. Since the underlying Java control is a standard [23], you can easily search the net for relevant reports of (and possible workarounds for) this issue. Let us know if you find something relevant.

#11 Comment By Carsten On August 11, 2014 @ 17:12

Hello Yair,

is there a way to get rid of the vertical scrollbar? I tried to do so using

jScrollPane.setVerticalScrollBarPolicy(javax.swing.JScrollPane.VERTICAL_SCROLLBAR_NEVER)

but this has no effect.

Thanks,
Carsten

#12 Comment By Yair Altman On August 12, 2014 @ 01:28

@Carsten – it should work, you’re probably doing something wrong. Perhaps you are updating the wrong handle, or updating the editbox’s contents via Matlab not Java (this resets the Java customizations).

#13 Pingback By CheckboxList | Undocumented Matlab On September 18, 2014 @ 03:25

[…] is to use small icon images checked and unchecked as part of the listbox item labels. As I explained last year, listboxes (like all other Matlab uicontrols that rely on underlying Java Swing […]

#14 Comment By Daisuke On November 2, 2014 @ 11:45

This is a cool stuff! I need to use rather text than html and am having a problem with getting the code to work. Since I need to put so many lines in the log, I thought something to append a new line would be computationally less demanding than setText (is that true?). I mean something like,

jEditbox.append(new_text);

Would this be possible?
Another question: Since I don’t know Java, I have no clue about what kind of member functions are available. How can one know that?

#15 Comment By Yair Altman On November 2, 2014 @ 11:59

@Daisuke – there is no append method (by this or any other name) that I know of.

To list a Java object’s methods, you can use the builtin methods or methodsview functions, or one of my utilities: [24] or [25].


Article printed from Undocumented Matlab: https://undocumentedmatlab.com

URL to article: https://undocumentedmatlab.com/articles/rich-contents-log-panel

URLs in this post:

[1] most Matlab uicontrols support HTML formatting: http://undocumentedmatlab.com/blog/html-support-in-matlab-uicomponents/

[2] underlying Java object: http://undocumentedmatlab.com/blog/findjobj-find-underlying-java-object/

[3] shown before: http://undocumentedmatlab.com/blog/rich-matlab-editbox-contents/

[4] MATLAB Computational Finance Virtual Conference: http://engage.vevent.com/index.jsp?eid=1972&seid=900

[5] Image: http://undocumentedmatlab.com/images/demo_screenshot2.png

[6] Registration: http://engage.vevent.com/registr_form.jsp?eid=1972&seid=900&language-code=en&country-code=US&page=1&no-login=false

[7] downloaded here: http://undocumentedmatlab.com/files/Matlab%20real-time%20trading%20presentation.pdf

[8] Here: https://www.youtube.com/watch?v=e4bdKcFl4GA

[9] Animated GIF logo image: http://undocumentedmatlab.com/blog/displaying-animated-gifs/

[10] Customized data table: http://undocumentedmatlab.com/blog/uitable-customization-report/

[11] Draggable (resizable) panel borders: http://undocumentedmatlab.com/blog/uisplitpane/

[12] HG2: http://undocumentedmatlab.com/blog/hg2-update/

[13] Maximized figure window: http://undocumentedmatlab.com/blog/minimize-maximize-figure-window/

[14] here: http://undocumentedmatlab.com/files/Matlab%20trading%20demo.zip

[15] IB-Matlab: http://undocumentedmatlab.com/ib-matlab/

[16] Rich Matlab editbox contents : https://undocumentedmatlab.com/articles/rich-matlab-editbox-contents

[17] Aligning uicontrol contents : https://undocumentedmatlab.com/articles/aligning-uicontrol-contents

[18] GUI integrated HTML panel : https://undocumentedmatlab.com/articles/gui-integrated-html-panel

[19] Panel-level uicontrols : https://undocumentedmatlab.com/articles/panel-level-uicontrols

[20] Customizing help popup contents : https://undocumentedmatlab.com/articles/customizing-help-popup-contents

[21] Editbox data input validation : https://undocumentedmatlab.com/articles/editbox-data-input-validation

[22] : http://stackoverflow.com/questions/19227073/improve-performance-on-gui-log

[23] : http://docs.oracle.com/javase/7/docs/api/javax/swing/JTextPane.html

[24] : https://undocumentedmatlab.com/blog/uiinspect

[25] : https://undocumentedmatlab.com/blog/checkclass

Copyright © Yair Altman - Undocumented Matlab. All rights reserved.