ActiveX – Undocumented Matlab https://undocumentedmatlab.com Charting Matlab's unsupported hidden underbelly Fri, 20 Oct 2017 09:57:44 +0000 en-US hourly 1 https://wordpress.org/?v=4.4.1 CheckboxListhttps://undocumentedmatlab.com/blog/checkboxlist https://undocumentedmatlab.com/blog/checkboxlist#comments Wed, 10 Sep 2014 18:00:55 +0000 http://undocumentedmatlab.com/?p=5012
 
Related posts:
  1. Tri-state checkbox Matlab checkboxes can easily be made to support tri-state functionality....
  2. 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....
  3. Advanced JIDE Property Grids JIDE property grids can use complex cell renderer and editor components and can signal property change events asynchronously to Matlab callbacks...
  4. Color selection components Matlab has several internal color-selection components that can easily be integrated in Matlab GUI...
 
]]>
Several years ago I blogged about using a checkbox-tree in Matlab. A few days ago there was a question on the Matlab Answers forum asking whether something similar can be done with Matlab listboxes, i.e. add checkboxes next to each list item. There are actually several alternatives for this and I thought this could be a good opportunity to discuss them:

MathWorks CheckBoxList

MathWorks CheckBoxList


The HTML image variant

The simplest alternative 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 components), support HTML and can be formatted using HTML images. For example:

Matlab listbox with HTML image icons

Matlab listbox with HTML image icons

In order to check/uncheck items in the listbox, we can trap the underlying Java component’s MouseClickedCallback using the findjobj utility:

% Assume checked.gif, unchecked.gif are 16x16 icons
prefix = ['<html><img src="file:///' strrep(path_of_icon_files),'\','/') '/unchecked.gif" height=16 width=16 />'];
sampleData = strcat(prefix, {'first', 'Second', 'Third', 'and last'});  % all items are unchecked at first
hListbox = uicontrol(...);
jScrollPane = findjobj(hListbox);
jListbox = handle(jScrollPane.getViewport.getView, 'CallbackProperties');
jListbox.MouseClickedCallback = {@mouseClickedFcn,hListbox};
 
function mouseClickedFcn(jListbox, jEventData, hListbox)
   % Get the clicked item and row index
   clickedX = jEventData.getX;
   clickedY = jEventData.getY;
   if clickedX > 15,  return;  end  % did not click a checkbox so bail out
   clickedRow = jListbox.locationToIndex(java.awt.Point(clickedX,clickedY)) + 1;  % Matlab row index = Java row index+1
   if clickedRow <= 0,  return;  end  % clicked not on an item - bail out
   strs = get(hListbox,'String');
   clickedItem = strs{clickedRow};
 
   % Switch the icon between checked.gif <=> unchecked.gif
   if strfind(clickedItem,'unchecked')
       strs{clickedRow} = strrep(clickedItem,'unchecked','checked');
   else
       strs{clickedRow} = strrep(clickedItem,'checked','unchecked');
   end
   set(hListbox,'String',strs);  % update the list item
end

Finally, when we process the selected list item(s), we can simply check whether they contain ‘unchecked.gif’ or ‘checked.gif’. Pretty straight-forward stuff.

MathWorks CheckBoxList

com.mathworks.mwswing.checkboxlist.CheckBoxList is a JList extension that displays a list of labels in a list with a checkbox next to each label. The labels’ checkboxes can be set, unset and queried using methods supplied by the CheckBoxList class or its com.mathworks.mwswing.checkboxlist.DefaultListCheckModel model:

% First create the data model
jList = java.util.ArrayList;  % any java.util.List will be ok
jList.add(0,'First');
jList.add(1,'Second');
jList.add(2,'Third');
jList.add(3,'and last');
 
% Next prepare a CheckBoxList component within a scroll-pane
jCBList = com.mathworks.mwswing.checkboxlist.CheckBoxList(jList);
jScrollPane = com.mathworks.mwswing.MJScrollPane(jCBList);
 
% Now place this scroll-pane within a Matlab container (figure or panel)
[jhScroll,hContainer] = javacomponent(jScrollPane,[10,10,80,65],gcf);
 
% Update some items' state programmatically
jCBModel = jCBList.getCheckModel;
jCBModel.checkAll;
jCBModel.uncheckIndex(1);
jCBModel.uncheckIndex(3);
 
% Respond to checkbox update events
jhCBModel = handle(jCBModel, 'CallbackProperties');
set(jhCBModel, 'ValueChangedCallback', @myMatlabCallbackFcn);

This results in the following image:

MathWorks CheckBoxList

MathWorks CheckBoxList

We can query the various checked/unchecked states programmatically:

>> jCBList.getCheckedValues
ans =
[First, Third]
 
>> jCBList.getCheckedIndicies'
ans =
           0       2
 
>> jCBModel.isIndexChecked(0)
ans =
     1    % =true

JIDE’s CheckBoxList

There is also an unrelated JIDE equivalent: com.jidesoft.swing.CheckBoxList. Readers are referred to the JIDE documentation for additional details.

The basic idea is the same as with the MathWorks CheckBoxList: we create the data model, then create a CheckBoxList component within a JScrollPane and place this onscreen using the javacomponent function. We can then modify or query the data model programmatically, and set various callback functions to process user events.

% Prepare the data model as above
 
% Now display onscreen:
jCBList = com.jidesoft.swing.CheckBoxList(jList.toArray)
jScrollPane = com.mathworks.mwswing.MJScrollPane(jCBList);
[jhScroll,hContainer] = javacomponent(jScrollPane, [120,10,80,65], gcf);
 
% Do some programmatic updates:
jCBList.selectAll;  % reverse: jCBList.selectNone
jCBList.setCheckBoxListSelectedIndices([0,2]);

The appearance is very similar to the MathWorks CheckBoxList, except that JIDE’s CheckBoxList has slightly less space between the list rows, and between the checkboxes and labels. The main difference between these components is not in their visual appearance but rather in their supported functionalities (internal methods) – some people might prefer the MathWorks component, others might like JIDE better. To see these functionalities, use my uiinspect and/or checkClass utilities.

For additional information on the MathWorks and JIDE components, and how to investigate and customize them, see Chapter 5 of my Matlab-Java programming book.

ActiveX and other alternatives

If you are running on Windows, you could use ActiveX controls that implement checkbox list functionality. One such control that is pretty standard is Microsoft’s MSComctlLib.ListViewCtrl.2. I showed an example of ListViewCtrl usage a few years ago, and readers are referred there for details. Here is the end result:

Sorted ListViewCtrl

Sorted ListViewCtrl

Granted, this is more of a table having a checkbox column than a listbox, but you can easily make the ListViewCtrl have only a single column.

In addition to this standard ListViewCtrl control, there are plenty of other third-party ActiveX or Java controls that can more-or-less easily be integrated in our Matlab GUI. The drawback of ActiveX is that it only works on a limited set of platforms, whereas the Java-based components (either MathWorks or JIDE) work on all Matlab installations.

Matlab uitable in disguise

As a variant of the idea of using a table with a checkbox first column, we could use Matlab’s builtin uitable function, as suggested by Sebastian below. Here is a simple code snippet illustrating this idea:

data = {true,'First'; false,'Second'; true,'Third'; false,'and last'};
hTable = uitable('Data',data,'RowName',[],'ColumnName',[],'BackgroundColor',[1,1,1],'Position',[10,10,100,70],'ColumnWidth',{20,60});

Matlab uitable with checkbox column

Matlab uitable with checkbox column

Anyway, let no one say ever again that Matlab GUI is boring. It is not. It is only limited by our imagination and our willingness to find and customize components that implement our requirements. There are plenty of alternatives out there, we just need to reach out and use them. If you can’t do it yourself, you could always use an external consultant like me to help you.

]]>
https://undocumentedmatlab.com/blog/checkboxlist/feed 19
Fixing Matlab’s actxserverhttps://undocumentedmatlab.com/blog/fixing-matlabs-actxserver https://undocumentedmatlab.com/blog/fixing-matlabs-actxserver#comments Wed, 19 Dec 2012 18:00:32 +0000 http://undocumentedmatlab.com/?p=3416
 
Related posts:
  1. tic / toc – undocumented option Matlab's built-in tic/toc functions have an undocumented option enabling multiple nested clockings...
  2. Matrix processing performance Matrix operations performance is affected by internal subscriptions in a counter-intuitive way....
  3. Allocation performance take 2 The clear function has some non-trivial effects on Matlab performance. ...
  4. uicontextmenu performance Matlab uicontextmenus are not automatically deleted with their associated objects, leading to leaks and slow-downs. ...
 
]]>
Matlab’s built-in actxserver function provides access to COM/DCOM server applications on Microsoft Windows platforms. This enables us, for example, to open a Microsoft Office document programmatically, and modify it from within Matlab. This in turn can be used, for example, to prepare professional PDF reports, relying on Office’s ability to save documents in PDF format. Alternately, we could programmatically update cell formatting (colors, fonts, borders etc.) and embed images and graphs in an Excel workbook – something that the standard xlswrite cannot do (my officedoc utility does this, using the same COM interface).

Note: For some reason, COM servers are called an ActiveX server in Matlab, although the term ActiveX is normally used for clients (i.e., controls), for which we have the actxcontrol* set of built-in functions.

Today I will focus on two changes that I made to Matlab’s built-in actxserver function:

Reusing an active server (no pun intended…)

By default, actxserver starts a new instance of the specified COM server whenever it is called. Sometimes this is indeed useful. However, I find that in the vast majority of cases, I actually want to reuse an existing server instance if it is currently running. For example, it is much faster and more memory-efficient to open an Excel workbook file in an existing Excel process, than to open it in a new dedicated process.

In R2007a, Matlab introduced the actxGetRunningServer function. Unfortunately, it did not see fit to set it as the default behavior for actxserver, nor even as an optional additional parameter (although MathWorks *did* change the actxserver function in that very same release, to accept a custom interface parameter). Users need to change their programs to first call actxGetRunningServer, check whether it works or fails, and then call actxserver if it fails (meaning that a server process is not currently running and a new one needs to be started):

% Try to reuse an existing COM server instance if possible
try
    hServer = actxGetRunningServer('excel.application');
    % no crash so probably succeeded to connect to a running server
catch
    % Never mind - continue normally to start the COM server and connect to it
    hServer = actxserver('excel.application');
end

This is downright silly, I must say.

Moreover, all the existing user and Matlab code that uses actxserver will continue to start a new server instance rather than reuse existing ones. For example, the widely-used xlsread and xlswrite functions.

Instead of fixing Matlab’s installed actxserver.m file, which could be problematic when deploying applications to end-users, I created a copy of actxserver.m somewhere in my user folders that is high on the Matlab path. This way I can modify the file and bundle it with any application that I send to clients. The change to this file is simply to add a variant of the code above at the very top of the actxserver.m file, as follows (the new lines are highlighted):

function h = actxserver(progID, varargin)
%ACTXSERVER Creates a COM Automation server.
...
% Copyright 2006-2007 The MathWorks, Inc.
% $Revision: 1.8.6.12 $ $Date: 2011/08/13 17:30:50 $
 
error(nargchk(1, 5, nargin, 'struct'));
 
% Yair 17/5/2009: Try to reuse an existing COM server instance if possibletry    h = actxGetRunningServer(progID);    return;  % no crash so probably succeeded - returncatch    % Never mind - continue normally to start the COM server and connect to itend 
machinename = '';
interface = 'IDispatch';
...

This simple change means that all exiting code, including Matlab’s built-in xlsread and xlswrite functions, now try to reuse a running COM server process if possible, starting a new one only if this fails. The code is fault-tolerant in that it also works on old Matlab releases where the actxGetRunningServer is not available.

Fix of the progID

The %matlabroot%/toolbox/matlab/winfun/private/newprogid.m function, a private function used by actxserver, normalizes COM program identifiers (progIDs), which is the string used to locate the COM server. Unfortunately, until R2011a (or specifically, when this was fixed by some MathWorker on June 10, 2010), this function had a bug that caused the normalization to fail. In order to correct this, I simply added the fixed function to the bottom of my modified actxserver.m file:

% Taken from: [matlabroot '\toolbox\matlab\winfun\private\newprogid.m']
function convertedProgID = newprogid(progID)
% Copyright 1984-2004 The MathWorks, Inc.
% $Revision: 1.1.8.5 $ $Date: 2004/04/15 00:07:00 $
 
convertedProgID = lower(progID);  % Yair: in the new version (after 2010/06/10) this line is missing i.e. case-sensitive progID
convertedProgID = regexprep(convertedProgID, '_', '__');  % Yair 17/5/2009: was progId - probably a bug
convertedProgID = regexprep(convertedProgID, '-', '___');
convertedProgID = regexprep(convertedProgID, '\.', '_');
convertedProgID = regexprep(convertedProgID, ' ', '____');
convertedProgID = regexprep(convertedProgID, '&', '_____');

Note that when MathWorks fixed %matlabroot%/toolbox/matlab/winfun/private/newprogid.m in 2010, they removed the conversion of progID to lower-case, making it case-sensitive. In my modified version above, I have kept the older conversion to lowercase for case-insensitivity.

Public-service announcements

Matlab open training day (Israel) - click for details

Matlab open training day (Israel) - click for details

Readers in Israel are invited to attend a free training seminar that I will present on advanced Matlab topics in Herzliya, on Tuesday Jan 8, 2013. The seminar is free, but requires registration. Additional details here. I will speak in Hebrew, but the presentation will be in English and I will be happy to answer questions in English.

I wish to point readers’ attentions to the recent announcement by AccelerEyes and MathWorks, that they will now merge their parallel-processing solutions into Matlab’s product line. I assume this also means an out-of-court settlement of MathWorks’ patent-infringement lawsuit. On the one hand, this is bad news for competition, removing Matlab PCT’s major competitor from the market. On the other hand, it could mean improved PCT/DCS products, merging Jacket’s superior performance and functionality directly within Matlab. If I may venture a guess, 2013 will herald a better, faster, more integrated parallel computing solution for Matlab, but we should probably (and quite sadly) say goodbye to Jacket’s price levels. Such collaborations, generally portrayed as exciting for consumers, are typically much more exciting for the respective shareholders…

This blog will now take a short winter break, and will return following the New-Year. Happy Holidays/New-Year everyone! Let this upcoming year be another year filled with discoveries, innovation and success!

 

]]>
https://undocumentedmatlab.com/blog/fixing-matlabs-actxserver/feed 3
xlswrite for Mac, Linuxhttps://undocumentedmatlab.com/blog/xlswrite-for-mac-linux https://undocumentedmatlab.com/blog/xlswrite-for-mac-linux#comments Thu, 02 Aug 2012 09:44:35 +0000 http://undocumentedmatlab.com/?p=3041
 
Related posts:
  1. GUI automation using a Robot This article explains how Java's Robot class can be used to programmatically control mouse and keyboard actions...
  2. Converting Java vectors to Matlab arrays Converting Java vectors to Matlab arrays is pretty simple - this article explains how....
  3. Using spinners in Matlab GUI Spinner controls can easily be added to Matlab GUI. This article explains how. ...
  4. The Java import directive The import function can be used to clarify Java code used in Matlab. ...
 
]]>
Numerous Matlab users have expressed frustration over the years at the fact that the xlswrite function, used for saving/updating Excel files, is only supported on the Windows platform. Matlab uses Excel COM to implement xlswrite functionality, and since COM is a Windows-specific technology, xlswrite does not work on non-Windows platforms.

In such cases, Matlab users normally save the data into a CSV (comma-separated values) file, using the built-in csvwrite or dlmwrite functions, or File-Exchange utilities such as Any2CSV. This enables saving the data, but does not enable saving formatting information or graphic objects (e.g., plots or images). As a side note, xlswrite also does not allow saving formatting information or graphic objects, but at least on Windows we can use direct COM to add them (or use my OfficeDoc utility).

Java solutions for spreadsheet access

Luckily, the community of Java developers, which is an order of magnitude larger than the Matlab community, has developed several utilities that we can easily use in Matlab to implement xlswrite‘s functionality on Macs, Linux, and wherever else Matlab may run – even Windows, if we really wish. Most articles on this website that deal with Java focus on its GUI aspects, i.e., how to use Java to improve Matlab’s plain-vanilla appearance/behavior. But Java is in fact a very broad programming platform that has an enormous repository of non-GUI solutions: networking, database support, data structures, computational algorithms, etc. etc. – and a huge number of them are open-source. Unlike Java’s GUI goodies, these Java packages, being non-GUI in nature, are fully supported by Matlab.

The Excel spreadsheets support, and Office support in general, is just another example of the wide range of non-GUI packages available in Java. In fact there are full-fledged Office lookalikes written in Java (most notably the open-source OpenOffice). We can either use these applications directly, or interact with them from Matlab (via Java), just as we can interact with Excel on Windows.

There are several Java packages that enable reading and writing spreadsheet data, without the full-blown Office support. One such open source project is the ODF (Open Document Foundation) Toolkit, which has plenty of online resources. In 2010 a Matlab user contributed a utility to use the ODF Java package for reading and writing ODF-format spreadsheets (*.ods). Other users have also provided ODF utilities for Matlab.

Using ODF is excellent and cross-platform, but does not solve the Excel problem directly, because the ODF format is incompatible with the XLS format. We can use another open-source Java package, JExcelApi, for this. JExcelApi is relatively easy to use and has several online tutorials (example1, example2), although it is not as widely used as ODF.

Another open-source Java package that can be used to directly read and write XLS files is Apache POI. An informal comparison of POI and JExcelApi can be found here.

xlwrite

Very recently, Marin Deresco has posted a Matlab utility called xlwrite that uses JExcelApi for implementing an xlswrite variant that can be used on all Matlab platforms.

After downloading xlwrite, we need to add its two contained JAR files (jxl.jar, MXL.jar) to the Java classpath:

javaaddpath('C:/Yair/Utils/JExcelAPI/jxl.jar')
javaaddpath('C:/Yair/Utils/JExcelAPI/MXL.jar')

We can now use xlwrite to store data in a real *.xls file:

xlwrite('my_data.xls', magic(3))

xlwrite has similar syntax and inputs to Matlab’s xlswrite. It can also write 3-d arrays (which xlswrite cannot), of cell and double type (the third dimension is simply stored in separate worksheets).

Note: Matlab’s decimal separator is ‘.’ – in order to be able to work with exported data on Macs, Mac users may need to change Mac decimal separator preferences. To do so you need to go to System Preferences > International > Formats and click on Customize button in the number zone, then type ‘.’ in the required field.

xlwrite is a real working solution. However, it may need further refinements, that will hopefully be added in future updates to this utility:

  • automatically add the javaaddpath commands to xlwrite so that users won’t need to do them
  • manage Java heap space, as Java heap memory saturates for large arrays exported many times (possible memory leak)
  • format dates and strings, as all numbers appear as text in Excel
  • optimize performance (the culprit appears to be a non-vectorized Cell2JavaString function)
  • include formatting and other goodies that the current xlswrite does not
]]>
https://undocumentedmatlab.com/blog/xlswrite-for-mac-linux/feed 9
Waiting for asynchronous eventshttps://undocumentedmatlab.com/blog/waiting-for-asynchronous-events https://undocumentedmatlab.com/blog/waiting-for-asynchronous-events#comments Wed, 18 Jul 2012 18:50:57 +0000 http://undocumentedmatlab.com/?p=3017
 
Related posts:
  1. setPrompt – Setting the Matlab Desktop prompt The Matlab Desktop's Command-Window prompt can easily be modified using some undocumented features...
  2. Matlab callbacks for Java events Events raised in Java code can be caught and handled in Matlab callback functions - this article explains how...
  3. Uitable sorting Matlab's uitables can be sortable using simple undocumented features...
  4. Disabling menu entries in deployed docked figures Matlab's standard menu items can and should be removed from deployed docked figures. This article explains how. ...
 
]]>
It often happens that we need our program to wait for some condition to occur. This condition may depend on some external process that updates the condition asynchronously, meaning in a non-predictable (non-specific) time. A typical example is user mouse or keyboard actions in a GUI dialog window, or a specific signal that is received from hardware.

waitfor and other built-in functions

Matlab has a couple of built-in functions for blocking Matlab’s main processing thread until certain asynchronous GUI events occurs. waitfor is documented to block code execution until either the specified GUI handle object is deleted, or is updated (possibly to a specified value), or Ctrl-C is pressed in matlab’s Command Window. uiwait similarly blocks execution, until a specified figure handle is deleted/closed, or a separate processing thread (typically, a callback function) calls the corresponding uiresume (I discussed uiwait/uiresume, together with their uisuspend/uirestore siblings, last year). uiwait, unlike waitfor, has an optional timeout parameter; on the other hand, uiwait cannot wait for a non-deletion event on a regular uicontrol property, as waitfor can.

Other related built-in Matlab functions are waitforbuttonpress, pause (which awaits user mouse/keyboard clicks), and ginput, gtext, rbbox, dragrect (which awaits mouse clicks in a plot/image axes). Some toolboxes have other similar blocking functions, for example roipoly in the Image Processing toolbox.

Waiting for events on non-HG objects

But what if we need to wait for an event to happen on a non-Matlab (HG) object? Say on an ActiveX control property or even on a non-graphical Java object?

It turns out that waitfor can also be used in these cases. Although not documented, waitfor actually accepts handles not only of HG objects (e.g., figure handles) but also of other types of handles, such as regular Java reference handles. The usage is the same as for regular HG handles:

waitfor(objectHandleOrReference, 'propertyName', propertyValue);

For example, to wait for data to be available in a java.util.Hashtable object, which has a public boolean isEmpty() method and therefore returns a value of ‘on’ or ‘off’ for get(object,’Empty’):

waitfor(javaHashTableReference, 'Empty', 'off');

(Note that Matlab automatically converts a Java boolean into ‘on’/’off’ in such cases, so we need to use ‘on’/’off’ rather than true/false; this is not always the case – a counter-case is presented immediately below)

Setting a timeout on waitfor

To set a timeout on our blocked wait, a feature of uiwait that is missing in the built-in waitfor, we can use a dedicated one-time timer object. Timer callbacks use a separate thread from the main Matlab processing thread, and are therefore processed even when the Main thread is blocked. The implementation is quite easy, as shown below:

% Wait for data updates to complete (isDone = false if timeout, true if data ok)
function isDone = waitForDone(object,timeout)
    % Initialize: timeout flag = false
    object.setDone(false);
 
    % Create and start the separate timeout timer thread
    hTimer = timer('TimerFcn',@(h,e)object.setDone(true), 'StartDelay',timeout);
    start(hTimer);
 
    % Wait for the object property to change or for timeout, whichever comes first
    waitfor(object,'Done',true);
 
    % waitfor is over - either because of timeout or because the data changed
    % To determine which, check whether the timer callback was activated
    isDone = (hTimer.TasksExecuted == 0);
 
    % Delete the time object
    try stop(hTimer);   catch, end
    try delete(hTimer); catch, end
 
    % Return the flag indicating whether or not timeout was reached
end  % waitForDone

Polling

In some cases (for example, waiting on a specific field value within a struct, which waitfor does not support), we need to revert to using plain-ol’ polling, rather than the more efficient blocked wait. In such cases, I strongly advice to place a certain pause within the polling loop:

delay = 0.01;  % 10 milliseconds
while ~object.isDone  % set by the callback
    pause(delay);  % a slight pause to let all the data gather
end

Or, a variant with timeout:

delay = 0.01;
for idx = 1 : (timeout/delay)  % wait up to N secs before giving up
    if object.isDone  % set by the callback
        break;
    end
    pause(delay);  % a slight pause to let all the data gather
end

The reason we need this deliberate pause is to enable the CPU to process other processing threads, namely that thread which is responsible for updating the field value in due time. Without this pause, it would take the CPU much longer (if at all) to get to that thread, and our overall application performance will actually degrade, since the event will take longer to get processed.

Adding deliberate pause delays as a mechanism to improve overall performance may sound counter-intuitive, but this is in fact the case here. Performance tuning can indeed be counter-intuitive sometimes, until you learn the underlying reasons when it becomes clear (I’ve shown several examples of this in the past, here, here, here and here).

We should take care not to set too high a pause delay, since that will unnecessarily delay processing of the incoming event; on the other hand, setting it too low will return the thread-starvation issue explained above. A pause value of 5-50 millisecs (0.005-0.05) should be about right for the vast majority of applications. Note that different platforms run your application at different speeds, so be careful not to over-tune this delay to a particular computer.

Interested in learning more Matlab performance or advanced programming tricks? Then consider joining my Matlab Performance Tuning, Advanced Matlab GUI and/or Matlab-Java programming seminars in Geneva on August 21-23, 2012 – email me (altmany at gmail dot com) for details.

]]>
https://undocumentedmatlab.com/blog/waiting-for-asynchronous-events/feed 31
Running VB code in Matlabhttps://undocumentedmatlab.com/blog/running-vb-code-in-matlab https://undocumentedmatlab.com/blog/running-vb-code-in-matlab#comments Wed, 20 Jul 2011 19:36:05 +0000 http://undocumentedmatlab.com/?p=2174
 
Related posts:
  1. COM/ActiveX tips & tricks This article describes several little-known tips useful for COM / ActiveX programming in Matlab...
  2. Multi-line tooltips Multi-line tooltips are very easy to set up, once you know your way around a few undocumented hiccups....
  3. A couple of internal Matlab bugs and workarounds A couple of undocumented Matlab bugs have simple workarounds. ...
  4. Performance: accessing handle properties Handle object property access (get/set) performance can be significantly improved using dot-notation. ...
 
]]>
Matlab has a variety of interfaces to external programming languages. We can easily access ActiveX and COM-enabled applications from Matlab. Matlab also provides easy access to most COM/ActiveX functionalities, with a few exceptions and limitations.

Unfortunately, Microsoft’s VBScript is not one of the supported interface languages in Matlab. Therefore, if we need to use VBScript to customize ActiveX or COM functionality or appearance, we have a problem. In some cases, the ActiveX/COM application provides internal methods or properties that enables us to bypass the need for direct VBScript. But in other cases, VBScript is unavoidable.

Today I’ll show one such example, and how we can run the required VBScript code in Matlab. Note that the entire discussion is Microsoft oriented, and therefore only applicable to Microsoft Windows. And yes – not a single word today about Java…

The need

One of the standard controls in Microsoft Windows is ListViewCtrl (more precisely, MSComctlLib.ListViewCtrl.2), which provides a simple sortable table ActiveX. ListViewCtrl should be available on practically all Windows installations, in \Windows\System32\MSCOMCTL.OCX. It is an ancient control (over a decade old), yet still widely used in the ActiveX world.

While Matlab includes a built-in uitable function, it is sometimes beneficial to use ListViewCtrl instead. For example, ListViewCtrl enables easy setting of cell-specific tool-tips (ok, yes, this can also be done in uitables but it’s not as easy as in ListViewCtrl). ListViewCtrl also enables easy setting of row color and other goodies.

So ok – all of these can be overcome in uitable which is cross-platform (not just Windows-specific) and has some very important features missing from ListViewCtrl (perhaps most importantly, uitable doesn’t look a decade old, as ListViewCtrl does). Still, when maintaining legacy code you sometimes don’t have the luxury of using modern controls.

Indeed, I once needed to use ListViewCtrl, when I ran into today’s issue. Here’s a simple usage example:

% Set the control's position to be just inside
% the container's pixel position
initPos = getpixelposition(hParent) + [2,3,-5,-5];
[hActiveX,hContainer] = actxcontrol('MSComctlLib.ListViewCtrl.2', ...
                                    initPos, gcf, ...
                                    @lbEventHandler);
bgColor = get(hContainer,'backgroundColor');
bgColorDec = sum(floor(bgColor*256).*(256.^[0:2]));  %#ok
 
% Customize the control's appearance
set(hActiveX, 'view','lvwReport', 'BorderStyle','ccNone', ...
              'AllowColumnReorder',0, 'Appearance','ccFlat', ...
              'Sorted',0, 'Checkboxes',1, 'FullRowSelect',1, ...
              'HotTracking',1, 'HoverSelection',0, ...
              'HideColumnHeaders',0, 'BackColor',bgColorDec);
 
% Set the column headers
panelPos = hgconvertunits(gcf, ...
                          get(hContainer,'Position'), ...
                          get(hContainer,'Units'), ...
                          'centimeters', hParent);
panelWidth = panelPos(3)*955;  % [Microsoft units...]
colWidths = panelWidth * [0.2,0.2,0.6];
hColHeaders = get(hActiveX,'ColumnHeaders');
hColHeaders.Add(1,'Name','Name',colWidths(1));
hColHeaders.Add(2,'Type','Type',colWidths(2));
hColHeaders.Add(3,'Comment','Comment',colWidths(3));
 
% Add some data
blue = hex2dec('FF0000');  % reverse HTML hex color: BBGGRR
data = { 'Orange', 'Fruit',     'My favorite fruit'; ...
         'Onion',  'Vegetable', 'An onion a day keeps everybody else away'; ...
         'Apple',  'Fruit',     'An apple a day keeps the doctor away'; ...
         'Tomato', 'Vegetable', 'You say tomato, I say tomato, let''s call the whole thing off'};
for rowData = data'
    row = hActiveX.ListItems.Add([],rowData{1},rowData{1});
    row.ListSubItems.Add([],[],rowData{2},[],rowData{2});
    row.ListSubItems.Add([],[],rowData{3},[],rowData{3});
    row.ListSubItems.Item(1).ForeColor = blue;
end

Unsorted ListViewCtrl

Unsorted ListViewCtrl

While most of ListViewCtrl’s features are accessible as internal properties and methods, one particular aspect requires VBScript. Which finally brings us to today’s topic:

Apparently, ListViewCtrl supports data sorting by simply clicking the column headers. Unfortunately, the sort icons (up/down arrows) have to be specified using an ImageListCtrl (MSComctlLib.ImageListCtrl.2) that holds the images. ImageListCtrl in turn requires using the internal built-in VB function LoadPicture() to load the images.

Unfortunately, Matlab does not enable direct invocation of VB code. So unless we find a way of calling VB’s internal LoadPicture() directly from Matlab, we cannot use sorting icons in our ListViewCtrl.

An ugly workaround

An ugly workaround for this problem is to modify the column name in run-time, so that clicking a column header (e.g., “Name”) will sort its data and also modify the column name to “Name ^” or “Name v”, depending on the sorting order:

% Event handler for ListBox item click
% Note: see documentation within %matlabroot%\toolbox\matlab\winfun\private\comeventcallback.m
function lbEventHandler(obj,eventId,item,eventArgs,eventName,varargin)
  try
    if (nargin<5) || ~ischar(eventName)
      return;   % can't tell which event this is
    end
 
    switch eventName
      case 'ItemClick',
        item.Checked = 1 - item.Checked;
        doSomethingUseful(item);
 
      case 'ItemCheck',
        % do nothing
 
      case 'ColumnClick',
        % Update the sorting order for the new (clicked) column
        obj.Sorted = 1;
        newSortKey = item.Index - 1;
        if strcmpi(obj.SortOrder,'lvwAscending') && (newSortKey == obj.SortKey)
          obj.SortOrder = 'lvwDescending';
          sortStr = ' v';
        else
          obj.SortOrder = 'lvwAscending';
          sortStr = ' ^';
        end
 
        % Update the column header text with the sort "icon" string
        if (obj.SortKey ~= newSortKey)
          oldColHeader = obj.ColumnHeaders.Item(obj.SortKey + 1);
          oldColHeader.Text = strrep(oldColHeader.Text,' v','');
          oldColHeader.Text = strrep(oldColHeader.Text,' ^','');
          newColHeader = obj.ColumnHeaders.Item(newSortKey + 1);
          newColHeader.Text = [newColHeader.Text sortStr];
        end
        obj.SortKey = newSortKey;
 
      otherwise,
        % do nothing
    end  % switch eventName
  catch
    handleError;
  end
 
end  % lbEventHandler

As can be seen, the result does not look very professional:

Sorted ListViewCtrl (ugly)

Sorted ListViewCtrl (ugly)

The solution

The solution to the problem is to use a not-well-known COM server component called ScriptControl (MSScriptControl.ScriptControl). By using ScriptControl’s eval() function we can call the built-in function and everybody’s happy:

% Load the images using ScriptControl
hScriptControl = actxserver('MSScriptControl.ScriptControl');
hScriptControl.Language = 'VBScript';
picUp   = hScriptControl.Eval('LoadPicture("..\Icons\UpIcon.gif")');
picDown = hScriptControl.Eval('LoadPicture("..\Icons\DownIcon.gif")');
 
% Now prepare an ImageList with these images
[hImageListActiveX, hContainer2] = actxcontrol('MSComctlLib.ImageListCtrl.2',initPos);
set(hContainer2,'Pos',[initPos(1:2),1,1]);  % hide the control
hImageListActiveX.ListImages.Add([],[],picUp);
hImageListActiveX.ListImages.Add([],[],picDown);
 
% Finally, attach the images to the ListViewCtrl headers
hActiveX.ColumnHeaderIcons = hImageListActiveX;

And now modify the sorting icon whenever a column header is clicked:

% Event handler for ListBox item click
% Note: see documentation within %ML\toolboc\matlab\winfun\private\comeventcallback.m
function lbEventHandler(obj,eventId,item,eventArgs,eventName,varargin)
  try
    if (nargin<5) || ~ischar(eventName)
      return;   % can't tell which event this is
    end
 
    switch eventName
      case 'ItemClick',
        item.Checked = 1 - item.Checked;
        doSomethingUseful(item);
 
      case 'ItemCheck',
        % do nothing
 
      case 'ColumnClick',
        % Update the sorting order for the new (clicked) column
        obj.Sorted = 1;
        newSortKey = item.Index - 1;
        if strcmpi(obj.SortOrder,'lvwAscending') && (newSortKey == obj.SortKey)
          obj.SortOrder = 'lvwDescending';
          sortIconIndex = 1;
        else
          obj.SortOrder = 'lvwAscending';
          sortIconIndex = 0;
        end
 
        % Remove sort icon from previous column
        setSortIcon(obj.hWnd,obj.SortKey,-1);
 
        % Add the sort icon to the clicked column header
        setSortIcon(obj.hWnd,newSortKey,sortIconIndex);
 
        % Update the previous column header text, to remove '...' due to the sort icon
        if (obj.SortKey ~= newSortKey)
          oldColHeader = obj.ColumnHeaders.Item(obj.SortKey + 1);
          oldColHeader.Text = oldColHeader.Text;
        end
        obj.SortKey = newSortKey;
 
      otherwise,
        % do nothing
    end  % switch eventName
  catch
    handleError;
  end
 
end  % lbEventHandler

Sorted ListViewCtrl (much better)

Sorted ListViewCtrl (much better)

This code uses the MEX utility setSortIcon, which was developed (not by me, I can’t remember by whom) based on this. Simply unzip the setSortIcon.zip file into your favorite folder on the Matlab path. The zip file contains the c source code, that you can modify and mex-recompile if you wish.

Running VBA Macros

A related issue is running VBA macros from Matlab. This was very recently asked and answered on the CSSM forum, so I’ll just provide Peter Lorin Rasmussen’s code (read higher up in that CSSM thread for more details):

% Initiate active X component
powerPoint = actxserver('PowerPoint.Application');
 
% Visible
powerPoint.Visible=1;
 
% Minimize powerpoint
powerPoint.WindowState=2;
 
% Load presentations object
presentations = powerPoint.presentations;
 
% Open file
presentation = invoke(presentations,'open',fileName);
 
% Load VBA project
k = presentation.VBProject.Collection.get();
 
% Run Macro
k = invoke(presentation.application,'run',macroName,varargin{:});
 
% Close all
presentation.Save;
presentation.Close;
powerPoint.Quit;
powerPoint.delete;

Do you have any favorite code in another programming language that you run from Matlab? Don’t be shy – please tell us all about it in a comment below.

]]>
https://undocumentedmatlab.com/blog/running-vb-code-in-matlab/feed 10
COM/ActiveX tips & trickshttps://undocumentedmatlab.com/blog/com-activex-tips https://undocumentedmatlab.com/blog/com-activex-tips#comments Wed, 28 Jul 2010 08:43:26 +0000 http://undocumentedmatlab.com/?p=1781
 
Related posts:
  1. Running VB code in Matlab Matlab does not natively enable running VB code, but a nice trick enables us to do just that...
  2. Fixing Matlab’s actxserver Matlab's COM (ActiveX) server behavior can be fixed in a couple of useful manners. ...
  3. xlswrite for Mac, Linux Several Matlab utilities enable reading/writing spreadsheet data (including XLS files) in Macs, Linux. ...
  4. ishghandle’s undocumented input parameter The built-in function ishghandle accepts a second input argument with the expected handle type....
 
]]>
Matlab’s COM/ActiveX interface has been supported and well-documented for many releases. However, there are still some aspects that are either not detailed, or that escape the casual documentation reader.

Accessing collection items

COM collections is a COM interface for sets of similar objects such as the worksheets in an Excel file or the images in a PowerPoint document. The items in a collection can be accessed using a numeric index (starting at 1) or the item’s string name.

The “normal” way to access collection items is using the Item() method that accepts a numeric index or the item’s name (a string).

Since collections are so common, Microsoft devised a short-cut of passing the parameter directly to the collection. For example, in our Excel VB code, instead of using Worksheets.Item(2) or Worksheets.Item(‘Sheet2’), we could write Worksheets(2) or Worksheets(‘Sheet2’). This shortcut is so common that the “normal” way of using Item() is rarely seen.

Unfortunately, Matlab’s implementation of the COM interface does not recognize this shortcut. Instead, we must use the more verbose way of using the Item():

% Invalid - shortcut is not recognized by Matlab
>> hSheet = hWorkbook.Worksheets(2);
??? Index exceeds matrix dimensions
 
% Valid
>> hSheet = hWorkbook.Worksheets.Item(2);
>> hSheet = hWorkbook.Worksheets.Item('Sheet2')
hSheet =
	Interface.Interface.Microsoft_Excel_11.0_Object_Library._Worksheet

Note that the dot-notation used above only works on recent Matlab 7 releases. Earlier releases (for example, Matlab 6.0 R12) have bugs that prevent it from functioning properly. The workaround is to use the following even-more-verbose way, which work on all Matlab releases:

hSheet = invoke(get(hWorkbook,'Worksheets'),'Item',2);

Matlab’s documentation actually has a short section describing the valid way to access COM collection. IMHO, a special warning about the invalid but widely-used short-cut would have been useful. In any case, the issue of accessing collection items has often appeared on CSSM (for example, here and here), so I guess many programmers have overlooked this.

Using enumerated values

When setting COM property values, Matlab supports some enumerated (constant) values but not all (read here). In practice, this can be very frustrating since the VB code and documentation almost always refers to the enumerated values only. Without the ability to set enumeration values, some properties become unusable in Matlab.

Well, not really. There’s a workaround: Since every enumerated COM value hides a numeric value, we can pass the numeric values rather than the enumerated (string) value when setting such properties. The numeric values are seldom documented, but can often be easily found online (use Google!). Quite often, they appear in C header-files that #define the enumerated values as pre-processor items with the required numeric value. For example, the numeric value for xlXYScatterLines is easily found to be 74.

Some of the enumerated constants are harder to find in this manner. You can use one of the following resources to search for your requested constant: Excel, PowerPoint (or here), OLE/Office (includes Word, Access and Internet Explorer), and an even larger list.

Again, old Matlab versions have problems understanding string enumerations, but the numeric values are always accepted and so are backward-compatible. If your application needs to support old Matlab versions, always use the numeric values (add a comment with the enumerated name, for maintainability).

Office 2010

Microsoft Office 2010 has apparently changed its COM interface, so accessing it from Matlab cannot easily be done. Luckily, Samuel Foucher has posted a workaround to this problem on CSSM yesterday. The trick is basically to have both an older Office and Office 2010 installed at the same time. As Samuel notes, “This is far from an optimal solution but it seems to work so far“.

]]>
https://undocumentedmatlab.com/blog/com-activex-tips/feed 2