schema – Undocumented Matlab https://undocumentedmatlab.com/blog_old Charting Matlab's unsupported hidden underbelly Tue, 29 Oct 2019 15:26:09 +0000 en-US hourly 1 https://wordpress.org/?v=4.4.1 Handle Graphics Behaviorhttps://undocumentedmatlab.com/blog_old/handle-graphics-behavior https://undocumentedmatlab.com/blog_old/handle-graphics-behavior#comments Wed, 06 Mar 2013 18:00:19 +0000 https://undocumentedmatlab.com/?p=3665 Related posts:
  1. Plot LimInclude properties The plot objects' XLimInclude, YLimInclude, ZLimInclude, ALimInclude and CLimInclude properties are an important feature, that has both functional and performance implications....
  2. Uitable sorting Matlab's uitables can be sortable using simple undocumented features...
  3. Draggable plot data-tips Matlab's standard plot data-tips can be customized to enable dragging, without being limitted to be adjacent to their data-point. ...
  4. Customizing print setup Matlab figures print-setup can be customized to automatically prepare the figure for printing in a specific configuration...
]]>
Matlab’s Handle Graphics (HG) have been around for ages. Still, to this day it contains many hidden gems. Today I discuss HG’s Behavior property, which is a standard undocumented hidden property of all HG objects.

Behavior is not normally updated directly (although there is absolutely nothing to prevent this), but rather via the semi-documented built-in accessor functions hggetbehavior and hgaddbehavior. This manner of accessing Behavior is similar to its undocumented sibling property ApplicationData, which is accessed by the corresponding getappdata and setappdata functions.

Using HB behaviors

hggetbehavior with no input args displays a list of all pre-installed HG behaviors:

>> hggetbehavior
 
   Behavior Object Name         Target Handle
   --------------------------------------------
   'Plotedit'...................Any Graphics Object   
   'Print'......................Any Graphics Object   
   'Zoom'.......................Axes                  
   'Pan'........................Axes                  
   'Rotate3d'...................Axes                  
   'DataCursor'.................Axes and Axes Children
   'MCodeGeneration'............Axes and Axes Children
   'DataDescriptor'.............Axes and Axes Children
   'PlotTools'..................Any graphics object   
   'Linked'.....................Any graphics object   
   'Brush'......................Any graphics object

hggetbehavior can be passed a specific behavior name (or cell array of names), in which case it returns the relevant behavior object handle(s):

>> hBehavior = hggetbehavior(gca, 'Zoom')
hBehavior =
	graphics.zoombehavior
 
>> hBehavior = hggetbehavior(gca, {'Zoom', 'Pan'})
hBehavior =
	handle: 1-by-2

As the name indicates, the behavior object handle controls the behavior of the relevant action. For example, the behavior object for Zoom contains the following properties:

>> hBehavior = hggetbehavior(gca, 'Zoom');
>> get(hBehavior)
       Enable: 1        % settable: true/false
    Serialize: 1        % settable: true/false
         Name: 'Zoom'   % read-only
        Style: 'both'   % settable: 'horizontal', 'vertical' or 'both'

By setting the behavior’s properties, we can control whether the axes will have horizontal, vertical, 2D or no zooming enabled, regardless of whether or not the toolbar/menu-bar zoom item is selected:

hBehavior.Enable = false;         % or: set(hBehavior,'Enable',false)
hBehavior.Style  = 'horizontal';  % or: set(hBehavior,'Style','horizontal')

This mechanism is used internally by Matlab to disable zoom/pan/rotate3d (see %matlabroot%/toolbox/matlab/graphics/@graphics/@zoom/setAllowAxesZoom.m and similarly setAllowAxesPan, setAllowAxesRotate).

At this point, some readers may jump saying that we can already do this via the zoom object handle that is returned by the zoom function (where the Style property was renamed Motion, but never mind). However, I am just trying to show the general usage. Not all behaviors have similar documented customizable mechanisms. In fact, using behaviors we can control specific behaviors for separate HG handles in the same figure/axes.

For example, we can set a different callback function to different HG handles for displaying a plot data-tip (a.k.a. data cursor). I have explained in the past how to programmatically control data-tips, but doing so relies on the figure datacursormode, which is figure-wide. If we want to display different data-tips for different plot handles, we would need to add logic into our custom update function that would change the returned string based on the clicked handle. Using HG behavior we can achieve the same goal much easier:

% Use dataCursorLineFcn() for the line data-tip
bh = hggetbehavior(hLine,'DataCursor');
set(bh,'UpdateFcn',@dataCursorLineFcn);
 
% Use dataCursorAnnotationFcn() for the annotation data-tip
bh = hggetbehavior(hAnnotation,'DataCursor');
set(bh,'UpdateFcn',{@dataCursorAnnotationFcn,extraData});

Note: there is also the related semi-documented function hgbehaviorfactory, which is used internally by hggetbehavior and hgaddbehavior. I do not see any need for using hgbehaviorfactory directly, only hggetbehavior and hgaddbehavior.

Custom behaviors

The standard behavior objects are UDD schema objects (i.e., the old object-oriented mechanism in MATLAB). They are generally located in a separate folder beneath %matlabroot%/toolbox/matlab/graphics/@graphics/. For example, the Zoom behavior object is located in %matlabroot%/toolbox/matlab/graphics/@graphics/@zoombehavior/. These behavior object folders generally contain a schema.m file (that defines the behavior object class and its properties), and a dosupport.m function that returns a logical flag indicating whether or not the behavior is supported for the specified handle. These are pretty standard functions, here is an example:

% Zoom behavior's schema.m:
function schema
% Copyright 2003-2006 The MathWorks, Inc.
 
pk = findpackage('graphics');
cls = schema.class(pk,'zoombehavior');
 
p = schema.prop(cls,'Enable','bool');
p.FactoryValue = true;
 
p = schema.prop(cls,'Serialize','MATLAB array');
p.FactoryValue = true;
p.AccessFlags.Serialize = 'off';
 
p = schema.prop(cls,'Name','string');
p.AccessFlags.PublicSet = 'off';
p.AccessFlags.PublicGet = 'on';
p.FactoryValue = 'Zoom';
p.AccessFlags.Serialize = 'off';
 
% Enumeration Style Type
if (isempty(findtype('StyleChoice')))
    schema.EnumType('StyleChoice',{'horizontal','vertical','both'});
end
p = schema.prop(cls,'Style','StyleChoice');
p.FactoryValue = 'both';
% Zoom behavior's dosupport.m:
function [ret] = dosupport(~,hTarget)
% Copyright 2003-2009 The MathWorks, Inc.
 
% axes 
ret = ishghandle(hTarget,'axes');

All behaviors must define the Name property, and most behaviors also define the Serialize and Enable properties. In addition, different behaviors define other properties. For example, the DataCursor behavior defines the CreateNewDatatip flag and no less than 7 callbacks:

function schema
% Copyright 2003-2008 The MathWorks, Inc.
 
pk = findpackage('graphics');
cls = schema.class(pk,'datacursorbehavior');
 
p = schema.prop(cls,'Name','string');
p.AccessFlags.PublicSet = 'off';
p.AccessFlags.PublicGet = 'on';
p.FactoryValue = 'DataCursor';
 
schema.prop(cls,'StartDragFcn','MATLAB callback');
schema.prop(cls,'EndDragFcn','MATLAB callback');
schema.prop(cls,'UpdateFcn','MATLAB callback');
schema.prop(cls,'CreateFcn','MATLAB callback');
schema.prop(cls,'StartCreateFcn','MATLAB callback');
schema.prop(cls,'UpdateDataCursorFcn','MATLAB callback');
schema.prop(cls,'MoveDataCursorFcn','MATLAB callback');
 
p = schema.prop(cls,'CreateNewDatatip','bool');
p.FactoryValue = false;
p.Description = 'True will create a new datatip for every mouse click';
p = schema.prop(cls,'Enable','bool');
p.FactoryValue = true;
 
p = schema.prop(cls,'Serialize','MATLAB array');
p.FactoryValue = true;
p.AccessFlags.Serialize = 'off';

Why am I telling you all this? Because in addition to the standard behavior objects we can also specify custom behaviors to HG handles. All we need to do is mimic one of the standard behavior object classes in a user-defined class, and then use hgaddbehavior to add the behavior to an HG handle. Behaviors are differentiated by their Name property, so we can either use a new name for the new behavior, or override a standard behavior by reusing its name.

hgaddbehavior(hLine,myNewBehaviorObject)

If you wish the behavior to be serialized (saved) to disk when saving the figure, you should add the Serialize property to the class and set it to true, then use hgaddbehavior to add the behavior to the relevant HG handle. The Serialize property is searched-for by the hgsaveStructDbl function when saving figures (I described hgsaveStructDbl here). All the standard behaviors except DataDescriptor have the Serialize property (I don’t know why DataDescriptor doesn’t).

Just for the record, you can also use MCOS (not just UDD) class objects for the custom behavior, as mentioned by the internal comment within the hgbehaviorfactory function. Most standard behaviors use UDD schema classes; an example of an MCOS behavior is PlotEdit that is found at %matlabroot%/toolbox/matlab/graphics/+graphics/+internal/@PlotEditBehavor/PlotEditBehavor.m.

ishghandle‘s undocumented type input arg

Note that the Zoom behavior’s dosupport function uses an undocumented format of the built-in ishghandle function, namely accepting a second parameter that specifies a specific handle type, which presumably needs to correspond to the handle’s Type property:

ret = ishghandle(hTarget,'axes');

The hasbehavior function

Another semi-documented built-in function called hasbehavior is located right next to hggetbehavior and hgaddbehavior in the %matlabroot%/toolbox/matlab/graphics/ folder.

Despite its name, and the internal comments that specifically mention HG behaviors, this function is entirely independent of the HG behavior mechanism described above, and in fact makes use of the ApplicationData property rather than Behavior. I have no idea why this is so. It may be a design oversight or some half-baked attempt by a Mathworker apprentice to emulate the behavior mechanism. Even the function name is misleading: in fact, hasbehavior not only checks whether a handle has some “behavior” (in the 2-input args format) but also sets this flag (in the 3-input args format).

hasbehavior is used internally by the legend mechanism, to determine whether or not an HG object (line, scatter group, patch, annotation etc.) should be added to the legend. This can be very important for plot performance, since the legend would not need to be updated whenever these objects are modified in some manner:

hLines = plot(rand(3,3));
hasbehavior(hLines(1), 'legend', false);   % line will not be in legend
hasbehavior(hLines(2), 'legend', true);    % line will be in legend

(for anyone interested, the relevant code that checks this flag is located in %matlabroot%/toolbox/matlab/scribe/private/islegendable.m)

hasbehavior works by using a dedicated field in the handle’s ApplicationData struct with a logical flag value (true/false). The relevant field is called [name,'_hgbehavior'], where name is the name of the so-called “behavior”. In the example above, it creates a field called “legend_hgbehavior”.

Do you know of any neat uses for HG behaviors? If so, please post a comment below.

]]>
https://undocumentedmatlab.com/blog_old/handle-graphics-behavior/feed 5
Extending a Java class with UDDhttps://undocumentedmatlab.com/blog_old/extending-a-java-class-with-udd https://undocumentedmatlab.com/blog_old/extending-a-java-class-with-udd#comments Thu, 29 Mar 2012 14:32:46 +0000 https://undocumentedmatlab.com/?p=2824 Related posts:
  1. Introduction to UDD UDD classes underlie many of Matlab's handle-graphics objects and functionality. This article introduces these classes....
  2. Creating a simple UDD class This article explains how to create and test custom UDD packages, classes and objects...
  3. UDD Events and Listeners UDD event listeners can be used to listen to property value changes and other important events of Matlab objects...
  4. 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....
]]>
Once again I welcome Donn Shull, with another article about Matlab’s internal UDD mechanism

Extending a Java class with UDD

During the series on UDD, we have mentioned the connection between UDD and Java. In UDD Events and Listeners we described how in Matlab, each Java object can have a UDD companion. In Hierarchical Systems with UDD we briefly noted that a UDD hierarchy may be passed to Java. In the numerous posts on handle graphics and callbacks, Yair has discussed the UDD packages javahandle and javahandle_withcallbacks. Based on this information, it seems reasonable to speculate that it may be possible to extend a Java class with UDD using UDD’s class inheritance mechanism.

This can be extremely useful in two cases:

  • You don’t know Java but found a Java class you would like to use in Matlab, it just needs minor modifications for your specific needs
  • You do know Java, but don’t have access to the original source code, and choose to extend the Java class with Matlab code, rather than Java code

Today I will show how this can be done using a simple example. Our example will illustrate the following things:

  1. Subclassing a Java class with UDD
  2. Adding UDD properties to the to the subclass
  3. Overloading a Java method with Matlab code
  4. Directly accessing the superclass methods

The example will show extending Java socket classes to provide a simple method for communication between two Matlab sessions. The protocol has been kept purposely simple and is not robust. Additional work would need to be done to create a real-life socket-based communication between Matlab systems (see for example this FEX submission).

Today’s example consists of two subclasses: a subclass of java.net.ServerSocket and a subclass of java.net.Socket. The protocol will be sending strings back and forth between the two sessions. In each direction the information exchange will consist of two bytes containing the string length, followed by the actual string. The entire source code can be downloaded from here.

Creating the simple.ServerSocket class

As in the UDD series, we will use the simple package for our classes and in this package create a ServerSocket class and a Socket class. Recall the simple package definition class is placed in a file named schema.m in a directory called @simple, placed somewhere on the Matlab path. schema.m consists of:

function schema()
%SCHEMA  simple package definition function.
   schema.package('simple');
end

In our ServerSocket class we will add three UDD properties and overload two of the Java class methods. It is worth noting that our final class will have all the parent Java classes public properties and methods and if necessary we can access the parent or super class methods directly. As before, we create a subfolder of the @simple folder named @ServerSocket; in this folder we place four files:

  1. schema.m – the class definition file
  2. ServerSocket.m – the class constructor
  3. accept.m – one of the Java methods that we will overload
  4. bind.m – the other Java method that we will overload

At the beginning of our schema.m file, we will use the following code to subclass the Java class:

function schema
%SCHEMA simple.ServerSocket class definition function.
 
    % parent schema.class definition
    javaPackage = findpackage('javahandle');
    javaClass = findclass(javaPackage, 'java.net.ServerSocket');
 
    % class package (schema.package)
    simplePackage = findpackage('simple');
 
    % class definition
    simpleClass = schema.class(simplePackage, 'ServerSocket', javaClass);

Here, we use findpackage and findclass to obtain the schema.class for the Java class that we are going to use as our parent. We then obtain a handle to the containing package, and finally use the subclass variation to define our ServerSocket as a variation of the Java parent’s schema.class.

Next, in the class definition file we place the code to define the signatures for the methods we are overloading:

    % accept.m overloads java accept method and adds communication protocol
    m = schema.method(simpleClass, 'accept');
    s = m.Signature;
    s.varargin    = 'off';
    s.InputTypes  = {'handle'};
    s.OutputTypes = {'string'};
 
    % bind.m overloads java bind method
    m = schema.method(simpleClass, 'bind');
    s = m.Signature;
    s.varargin    = 'off';
    s.InputTypes  = {'handle'};
    s.OutputTypes = {};be

Finally, we add three UDD properties to the class: The first will be used to hold a string representation of the address of our ServerSocket; the second will store the communication port number; the third is a handle property that will hold the reference to the socket used by the actual communication.

    % holds remote address as a matlab string
    p = schema.prop(simpleClass, 'address', 'string');
    p.FactoryValue = 'localhost';
 
    % holds remote port as a matlab int
    p = schema.prop(simpleClass, 'port', 'int16');
    p.FactoryValue = 2222;
 
    % holds a handle reference to the socket created in the accept method
    p = schema.prop(simpleClass, 'socket', 'handle');
end

We now need to write our overloaded methods. The bind method is simple: it first creates a Java internet address using the new address and port properties; then it uses the standard Java class methods to call the superclass’s bind method with the specified internet address:

function bind(this)
    % use the object socket and port port properties to bind this instance
    % to a address calling the superclass bind method
    inetAddress = java.net.InetSocketAddress(this.address, this.port);
    this.java.bind(inetAddress);
end

The overloaded accept method is a bit more complicated and crude: It starts by calling the superclass accept method to create a communication socket and stores the created socket in our class’s socket property. Then it goes into an infinite loop of waiting for incoming commands, uses evalc to execute them, and returns the captured result to the caller. The only way out of this loop is using Ctrl-C from the keyboard.

function accept(this)
 
    % use the superclass accept
    this.socket = handle(this.java.accept);
 
    % infinite loop use ctrl-c to exit
    while 1
        % wait for a command then execute it capturing output
        while this.socket.getInputStream.available < 2
        end
 
        msb = this.socket.getInputStream.read;
        lsb = this.socket.getInputStream.read;
 
        numChar = 256 * msb + lsb;
        cmd = uint8(zeros(1, numChar));
 
        for index = 1:numChar
            cmd(index) = this.socket.getInputStream.read;
        end
        result = evalc(char(cmd));
 
        % send the result back to the calling system
        len = numel(result);
        msb = uint8(floor(len/256));
        lsb = uint8(mod(len,256));
 
        this.socket.getOutputStream.write(uint8([msb, lsb, result]));
    end
end

Creating the simple.Socket class

The simple.Socket class is created like ServerSocket, this time in the @Socket folder under the @simple folder. In this subclass we add properties for the address and port, just as in ServerSocket. We overload the superclass’s connect method with our own variant, and add a new method to make the remote calls to the ServerSocket running in another Matlab instance. Beginning with the schema.m file we have:

function schema
%SCHEMA simple.Socket class definition function.
 
    % package definition
    simplePackage = findpackage('simple');
    javaPackage = findpackage('javahandle');
    javaClass = findclass(javaPackage, 'java.net.Socket');
 
    % class definition
    simpleClass = schema.class(simplePackage, 'Socket', javaClass);
 
    % define class methods
    % connect.m overloads java connect method
    m = schema.method(simpleClass, 'connect');
    s = m.Signature;
    s.varargin    = 'off';
    s.InputTypes  = {'handle'};
    s.OutputTypes = {};
 
    % remoteEval.m matlab method for remote evaluation of Matlab commands
    m = schema.method(simpleClass, 'remoteEval');
    s = m.Signature;
    s.varargin    = 'off';
    s.InputTypes  = {'handle', 'string'};
    s.OutputTypes = {'string'};
 
    % add properties to this class
    % holds remote address as a Matlab string
    p = schema.prop(simpleClass, 'address', 'string');
    p.FactoryValue = 'localhost';
 
    % holds remote port as a Matlab int
    p = schema.prop(simpleClass, 'port', 'int16');
    p.FactoryValue = 2222;
end

The class constructor Socket.m is simply:

function skt = Socket
%SOCKET constructor for the simple.Socket class
    skt = simple.Socket;
end

The overloaded connect method is almost identical to the overloaded bind method we used for ServerSocket. We form a Java internet address from our new properties and then invoke the superclass’s connect Java method:

function connect(this)
%CONNECT overload of the java.net.Socket connect method
    % use the object address and port properties to connect to the remote
    % session via the superclass connect method
    inetAddress = java.net.InetSocketAddress(this.address, this.port);
    this.java.connect(inetAddress);
end

Finally, our remoteEval method is very similar to the loop portion of the overloaded accept method we wrote for simple.ServerSocket. We take the command string input and convert it into a series of bytes prepended by the length of the string, send it to the other Matlab session and wait for a response:

function result = remoteEval(this, cmd)
%REMOTEEVAL evaluate a Matlab command on a remotely connected Matlab
 
    % The command string is sent as a series of bytes preceded by a pair of
    % bytes which represents the length of the string  
    cmd = uint8(cmd);
 
    len = numel(cmd);
    msb = uint8(floor(len/256));
    lsb = uint8(mod(len,256));
 
    this.getOutputStream.write([msb, lsb, cmd]);
 
    % We will expect the remote session to return a string in the same format
    % as the command
    while this.getInputStream.available < 2
    end
 
    msb = this.getInputStream.read;
    lsb = this.getInputStream.read;
 
    numChar = 256 * msb + lsb;
 
    result = uint8(zeros(1, numChar));
    for index = 1:numChar
        result(index) = this.getInputStream.read;
    end
    result = char(result);
end

Using simple.ServerSocket and simple.Socket to communicate between Matlab sessions

To use this example, add the zip contents to your Matlab path, then open an instance of Matlab and issue the following commands:

>> ss = simple.ServerSocket;
>> ss.bind;
>> ss.accept;

Then open another Matlab instance and issue these commands:

>> s = simple.Socket;
>> s.connect;

At this point you can send commands from this Matlab instance (the client) to the first instance (the server) using the remoteEval method. The command will then be transmitted to the server, executed, and the server will return the captured string result to the client:

>> remoteResult = s.remoteEval('pi')
remoteResult =
    3.1416

The defaults are for localhost and port 2222. These can be changed prior to using the server’s bind method and the client’s connect method. To keep things as simple as possible, error checking etc. has been left out, so this is just a demonstration and is far from robust.

There are some things to note about our new classes. If we type methods(s) or s.methods at the Matlab command prompt in our simple.Socket session we obtain:

>> s.methods
 
Methods for class simple.Socket:
 
Socket                     getOOBInline               isClosed                   setReuseAddress            
bind                       getOutputStream            isConnected                setSendBufferSize          
close                      getPort                    isInputShutdown            setSoLinger                
connect                    getReceiveBufferSize       isOutputShutdown           setSoTimeout               
equals                     getRemoteSocketAddress     java                       setSocketImplFactory       
getChannel                 getReuseAddress            notify                     setTcpNoDelay              
getClass                   getSendBufferSize          notifyAll                  setTrafficClass            
getInetAddress             getSoLinger                remoteEval                 shutdownInput              
getInputStream             getSoTimeout               sendUrgentData             shutdownOutput             
getKeepAlive               getTcpNoDelay              setKeepAlive               toString                   
getLocalAddress            getTrafficClass            setOOBInline               wait                       
getLocalPort               hashCode                   setPerformancePreferences  
getLocalSocketAddress      isBound                    setReceiveBufferSize

This shows that our simple.Socket class has all of the methods of the Java superclass, plus our added remoteEval method and the java method that was automatically added by Matlab. This means that all of the Java methods are methods of our class instance and the added java means that we can access the superclass methods from our class instance if the need arises. If we use the struct function which Yair has previously discussed, we obtain:

>> struct(s)
ans = 
              OOBInline: 0
                  Bound: 1
                Channel: []
                  Class: [1x1 java.lang.Class]
                 Closed: 0
              Connected: 1
            InetAddress: [1x1 java.net.Inet4Address]
          InputShutdown: 0
            InputStream: [1x1 java.net.SocketInputStream]
              KeepAlive: 0
           LocalAddress: [1x1 java.net.Inet4Address]
              LocalPort: 51269
     LocalSocketAddress: [1x1 java.net.InetSocketAddress]
         OutputShutdown: 0
           OutputStream: [1x1 java.net.SocketOutputStream]
      ReceiveBufferSize: 8192
    RemoteSocketAddress: [1x1 java.net.InetSocketAddress]
           ReuseAddress: 0
         SendBufferSize: 8192
               SoLinger: -1
              SoTimeout: 0
             TcpNoDelay: 0
           TrafficClass: 0
                address: 'localhost'
                   port: 2222

We see that we have access to all of the public properties of the Java superclass, as well as the UDD properties that we have added.

Conclusion

At the beginning of this post I said that this would be a simple non-robust communications method. In order to make this anything more than that, a number of things would need to be implemented, for example:

  • Improve the accept method to exit after a timeout or when a connection has been made and then terminated
  • Add checksums and timeouts for communication to determine the reliability of the communication
  • Add a retry request protocol for instances of communication failure
  • Add support for any serializable Matlab type, not just strings

The intent here was just to show that extending Java classes with Matlab is possible, relatively simple, and can be extremely useful. After all, with over 10 million Java developers out there, chances are that somebody somewhere has already posted a Java class that answers your exact need, or at least close enough that it can be used in Matlab with only some small modifications.

]]>
https://undocumentedmatlab.com/blog_old/extending-a-java-class-with-udd/feed 14
UDD Events and Listenershttps://undocumentedmatlab.com/blog_old/udd-events-and-listeners https://undocumentedmatlab.com/blog_old/udd-events-and-listeners#comments Wed, 16 Mar 2011 18:43:16 +0000 https://undocumentedmatlab.com/?p=2200 Related posts:
  1. Introduction to UDD UDD classes underlie many of Matlab's handle-graphics objects and functionality. This article introduces these classes....
  2. Creating a simple UDD class This article explains how to create and test custom UDD packages, classes and objects...
  3. UDD Properties UDD provides a very convenient way to add customizable properties to existing Matlab object handles...
  4. Multi-column (grid) legend This article explains how to use undocumented axes listeners for implementing multi-column plot legends...
]]>
Donn Shull continues his exploration of the undocumented UDD mechanism, today discussing the important and extremely useful topic of UDD events

The UDD event model

The UDD event model is very similar to the MCOS event model. There is an excellent discussion of the MCOS event model in Matlab’s official documentation. Most of the MCOS information also applies to UDD if you make the following substitutions:

MCOS Event ModelUDD Event Model
notifysend
event.EventDatahandle.EventData
events blockschema.event
event.listenerhandle.listener
PreGet, PreSetPropertyPreGet, PropertPreSet
PostGet, PostSetPropertyPostGet, PropertyPostSet

Event handler functions

To begin the UDD event model discussion we will start at the end, with the event handler. The event handler function requires at least two input arguments: the source object which triggered the event, and an object of type handle.EventData or a subclass of handle.EventData.

To demonstrate how this works, let’s write a simple event handler function. This event handler will display the class of the source event and the class of the event data:

function displayEventInfo(source, eventData)
%DISPLAYEVENTINFO display the classes of source, data objects
%
%   DISPLAYEVENTINFO(SOURCE, EVENTDATA) returns the classes
%   of the source object and the event data object
%
%   INPUTS:
%       SOURCE    : the event source
%       EVENTDATA : the event data
  if ~isempty(source)
    fprintf(1, 'The source object class is: %s',class(source));
  end
  if ~isempty(eventData)
    fprintf(1, 'The event data class is: %s',class(eventData));
  end
end

Creating a listener

In the section on Creating a Simple UDD Class we used schema.event in our simple.object class definition file to create a simpleEvent event. We now create an instance of simple.object, then use handle.listener to wait (“listen”) for the simpleEvent event to occur and call the displayEventInfo event handler function:

a = simple.object('a', 1);
hListener = handle.listener(a,'simpleEvent',@displayEventInfo);
setappdata(a, 'listeners', hListener);

Important: The hListener handle must remain stored somewhere in Matlab memory, or the listener will not be used. For this reason, it is good practice to attach the listener handle to the listened object, using the setappdata function, as was done above. The listener will then be alive for exactly as long as its target object is alive.

Creating an EventData object

Next, create the handle.EventData object. The handle.EventData object constructor requires two arguments: an instance of the events source object, and the name of the event:

evtData = handle.EventData(a, 'simpleEvent')

Generating an event

The last step is actually triggering an event. This is done by issuing the send command for the specified object, event name and event data:

>> a.send('simpleEvent', evtData)
The source object class is: simple.object
The event data class is: handle.EventData

If there is other information that you wish to pass to the callback function you can create a subclass of the handle.EventData. Add properties to hold your additional information and use your subclass as the second argument of the send method.

Builtin UDD events

The builtin handle package has six event data classes which are subclasses of the base handle.EventData class. Each of these classes is paired with specific UDD events that Matlab generates. Actions that trigger these events include creating/destroying an object, adding/removing objects from a hierarchy, and getting/setting property values. The following table lists the event names and handle.*EventData data types returned for these events:

event data typeevent trigger
handle.ClassEventDataClassInstanceCreated
handle.EventDataObjectBeingDestroyed
handle.ChildEventDataObjectChildAdded, ObjectChildRemoved
handle.ParentEventDataObjectParentChanged
handle.PropertyEventDataPropertyPreGet, PropertyPostGet
handle.PropertySetEventDataPropertyPreSet, PropertyPostSet

As an example of some of these events let’s look at a question recently asked on the CSSM newsgroup. The basic idea is that we want to monitor an axis, automatically make any added lines to be green in color, and prevent patches from being added.

The solution is to monitor the ObjectChildAdded event for an axis. We will write an event handler which checks the handle.ChildEventData to see what type of child was added. In the case of lines we will set their color to green; patch objects will be deleted from the axis. Here is our event handler function:

function modifyAxesChildren(~, eventData)
%MODIFYAXESCHILDREN monitor and axis and modify added children
%
%   MODIFYAXESCHILDREN(SOURCE,EVENTDATA) is an event handler to
%   change newly-added lines to green and remove added patches
%
%   INPUTS:
%       EVENTDATA : handle.ChildEventData object
   switch eventData.Child.classhandle.Name
      case 'line'
         eventData.Child.set('Color', 'green');
         disp('Color changed to green.')
      case 'patch'
         eventData.Child.delete;
         disp('Patch removed.')
   end
end

Next create an axis, and a listener which is triggered when children are added:

% create a new axes and get its handle
a = hg.axes;
 
% create the listener
listen = handle.listener(a, 'ObjectChildAdded', @modifyAxesChildren);
 
% add a line
>> hg.line;
Color changed to green.
 
% try to add a patch
>> hg.patch;
Patch removed.

Removing a child with either the delete or the disconnect method generates an ObjectChildRemoved event. The delete method also generates the ObjectBeingDestroyed event. Changing a child’s parent with the up method generates an ObjectParentChanged event.

Reading an object’s properties with either dot notation or with the get method generates PropertyPreGet and PropertyPostGet events.

Changing the value of a property generates the PropertyPreSet and PropertyPostSet events. As we saw in the section on UDD properties, when the AbortSet access flag is ‘on’, property set events are only generated when a set operation actually changes the value of the property (as opposed to leaving it unchanged).

Note that the handle.listener syntax is slightly different for property events:

hProp = findprop(a, 'Value');
hListener = handle.listener(a,hProp,'PropertyPreGet',@displayEventInfo);

Java events

The final specialized event data object in the handle package is handle.JavaEventData. In Matlab, Java classes are not UDD classes, but each Java instance can have a UDD peer. The peer is created using the handle function. The Java peers are created in either UDD’s javahandle package or the javahandle_withcallbacks package. As their names imply, the latter enables listening to Java-triggered events using a Matlab callback.

To illustrate how this works we will create a Java Swing JFrame and listen for MouseClicked events:

% Create the Java Frame
javaFrame = javax.swing.JFrame;
javaFrame.setSize(200, 200);
javaFrame.show;
 
% Create a UDD peer for the new JFrame (two alternatives)
javaFramePeer = javaFrame.handle('CallbackProperties');  % alternative #1
javaFramePeer = handle(javaFrame, 'CallbackProperties');  % alternative #2
 
% Create the a listener for the Java MouseClicked event
listen = handle.listener(javaFramePeer, 'MouseClicked', @displayEventInfo);

a simple Java Swing JFrame

a simple Java Swing JFrame

When we click on the JFrame, our UDD peer triggers the callback:

The source object class is: javahandle_withcallbacks.javax.swing.JFrame
The event data class is: handle.JavaEventData

Since we created our peer in the javahandle_withcallbacks package, it is not necessary to create a listener using handle.listener. If we place our callback function handle in the MouseClickedCallback property it will be executed whenever the MouseClicked event is triggered. Such *Callback properties are automatically generated by Matlab when it creates the UDD peer (details).

clear listen
javaFramePeer.MouseClickedCallback = @displayEventInfo

This will work the same as before without the need to create and maintain a handle.listener object. If we had created our UDD peer in the javahandle package rather than javahandle_withcallbacks, we would not have the convenience of the MouseClickedCallback property, but we could still use the handle.listener mechanism to monitor events.

Creating callback properties for custom UDD classes

It is easy to add callback properties to user created UDD objects. The technique involves embedding a handle.listener object in the UDD object. To illustrate this, we add a SimpleEventCallback property to our simple.object, then use a SimpleEventListener property to hold our embedded handle.listener. Add the following to simple.object‘s schema.m definition file:

   % Property to hold our callback handle
   prop = schema.prop(simpleClass, 'SimpleEventCallback', 'MATLAB callback');
   prop.setFunction = @setValue;
 
   % hidden property to hold the listener for our callback
   prop = schema.prop(simpleClass, 'SimpleEventListener', 'handle');
   prop.Visible = 'off';
end
 
function propVal = setValue(self, value)
   %SETVALUE function to transfer function handle from callback property to listener
   self.SimpleEventListener.Callback = value;
   propVal = value;
end

Next we add the following to our simple.object constructor file:

% set the hidden listener property to a handle.listener
simpleObject.SimpleEventListener = handle.listener(simpleObject, 'simpleEvent', []);

Now if we set the SimpleObjectCallback property to a function handle, the handle is transferred to the embedded handle.listener Callback property. When a simpleEvent event is generated, our SimpleEventCallback function will be executed.

This series will conclude next week with a look at the special relationship between UDD and Java.

]]>
https://undocumentedmatlab.com/blog_old/udd-events-and-listeners/feed 32
UDD Propertieshttps://undocumentedmatlab.com/blog_old/udd-properties https://undocumentedmatlab.com/blog_old/udd-properties#comments Wed, 09 Mar 2011 18:00:17 +0000 https://undocumentedmatlab.com/?p=2156 Related posts:
  1. Multi-column (grid) legend This article explains how to use undocumented axes listeners for implementing multi-column plot legends...
  2. Creating a simple UDD class This article explains how to create and test custom UDD packages, classes and objects...
  3. UDD Events and Listeners UDD event listeners can be used to listen to property value changes and other important events of Matlab objects...
  4. Introduction to UDD UDD classes underlie many of Matlab's handle-graphics objects and functionality. This article introduces these classes....
]]>
Donn Shull continues his series of articles on Matlab’s undocumented UDD mechanism. Today, Donn explains how to use and customize UDD properties.

Properties meta-data

The UDD system is a class system. UDD packages, classes, events, and properties are all classes. In this section we will take a closer look at property classes.

As we have already shown, properties are added to a UDD class by adding schema.prop calls to the schema.m class definition file. What this really means is that each property of a UDD class is itself a class object (schema.prop) with its own properties and methods. The methods of schema.prop are loadobj() and saveobj(), which are used to serialize objects of this class (i.e., storing them in a file or sending them elsewhere).

It is schema.prop‘s properties (so-called meta-properties) that interest us most:

PropertyData TypeDescription
AccessFlagsMatlab structureControls which objects can access (read/modify) the property
CaseSensitiveon/offDetermines if the exact case is required to access the property (i.e., can we use ‘casesensitive’ instead of ‘CaseSensitive’)
DataTypestringThe underlying object’s property data type, set by the constructor
DescriptionstringThis can hold a description of the property (normally empty)
FactoryValueAs specified by DataTypeThis is used to provide an initial or default property value
GetFunctionFunction handleA function handle that is called whenever the property value is read
NamestringThe name of the property, also set by the constructor
SetFunctionFunction handleA function handle that is called whenever the properties value is changed
Visibleon/offDetermines if a property will be displayed by the get method for a UDD object

We can manipulate the values of these meta-properties to control various aspects of our property:

% Create instance of simple.object
>> a = simple.object('a');
 
% Find the Value property and list its meta-properties
% We can manipulate these meta-properties within limits
>> a.findprop('Value').get
            Name: 'Value'
     Description: ''
        DataType: 'single'
    FactoryValue: 7.3891
     AccessFlags: [1x1 struct]
         Visible: 'on'
     GetFunction: []
     SetFunction: []
 
>> prop.Visible = 'off';  % i.e. hidden property (see below)
>> prop.AccessFlags.PublicSet = 'off';   % i.e. read-only
>> prop.AccessFlags.PublicGet = 'on';
 
% Find the DataType meta-property of the Value property
% This meta-property and all other schema.prop base class properties are fixed
>> a.findprop('Value').findprop('DataType').get
            Name: 'DataType'
     Description: ''
        DataType: 'string'
    FactoryValue: ''
           ...

Adding properties to existing objects in run-time

schema.prop is a very useful tool – it can be used to add new properties to existing object handles, even after these objects have been created. For example, let’s add a new property (MyFavoriteBlog) to a standard figure handle:

>> p=schema.prop(handle(gcf), 'MyFavoriteBlog','string')
p =
	schema.prop
 
>> set(gcf,'MyFavoriteBlog','UndocumentedMatlab.com')
 
>> get(gcf,'MyFavoriteBlog')
ans =
UndocumentedMatlab.com

Using this simple mechanism, we can add meaningful typed user data to any handle object. A similar functionality can be achieved via the setappdata/getappdata functions. However, the property-based approach above is much “cleaner” and more powerful, since we have built-in type checks, property-change event listeners and other useful goodies.

Property data types

In the article on creating UDD objects we saw that the Name and DataType meta-properties are set by the schema.prop constructor. Name must be a valid Matlab variable name (see isvarname).

DataType is more interesting: There are two equivalent universal data types, 'mxArray', and 'MATLAB array'. With either of these two data types a property can be set to a any Matlab type. If we use a more specific data type (e.g., ‘string’, ‘double’ or ‘handle’), Matlab automatically ensures the type validity whenever the property value is modified. In our simple.object we use ‘double’ and ‘string’. You can experiment with these and see that the Value property will only allow scalar numeric values and the Name property will only allow character values:

>> set(obj, 'Value', 'abcd')
??? Parameter must be scalar.
 
>> obj.Value='abcd'
??? Parameter must be scalar.
 
>> obj.Name=123
??? Parameter must be a string.

The following table lists the basic UDD data types:

CategoryData Type
UniversalMATLAB array, mxArray
Numeric Scalarsbool, byte, short, int, long, float, double
Numeric VectorsNints, NReals
Specialized Numericcolor, point, real point, real point3, rect, real rect
Enumerationon/off
Stringschar, string, NStrings, string vector
Handlehandle, handle vector, MATLAB callback, GetFunction, SetFunction
JavaAny java class recognized by Matlab

User-defined data types

While this is an extensive list, there are some obvious types missing. For example there are no unsigned integer types. To handle this UDD provides two facilities for creating your own data types. One is the schema.EnumType. As you can see, Matlab has had a form of enumerations for a really long time not just the last few releases. The other facility is schema.UserType.

With these two classes you can create any specialized data type you need. One word of caution: once you have created a new UDD data type it exists for the duration of that Matlab session. There is no equivalent of the clear classes mechanism for removing a data type. In addition once a new data type has been defined it cannot be redefined until Matlab is restarted.

Let’s use a problem discussed in the CSSM forum as example. The essence of the problem is the need to flag a graphic line object as either editable or not. The proposed proposed is to add a new Editable property to an existing line handle. We will use schema.EnumType to create a new type named 'yes/no' so that the new property could accept only ‘yes’ and ‘no’ values:

function tline = taggedLine(varargin)
%TAGGEDLINE create a line with Editable property
%
%   TLINE = TAGGEDLINE(VARARGIN) create a new handle graphics line
%   and add 'Ediatable' property to line. Default property value is 'yes'.
%
%   INPUTS:
%       VARARGIN  : property value pairs to pass to line
%
%   OUTPUTS:
%       TLINE     : hg line object with Editable property
 
    % If undefined define yes/no datatype</font>
    if isempty(findtype('yes/no'))
        schema.EnumType('yes/no', {'yes', 'no'});
    end
    tline = line(varargin{:});
    schema.prop(tline, 'Editable', 'yes/no');
end

It is necessary to test for the existence of a type before defining it, since trying to redefine a type will generate an error.

We can use this new taggedLine() function to create new line objects with the additional Editable property. Instead of adding a new property to the line class we could have defined a new class as a subclass of line:

function schema()
%SCHEMA  hg package definition function
    schema.package('hg');
end

We create our class definition as a subclass of the handle graphics line class:

function schema()
%SCHEMA  hg.taggedline class definition function
    % package definition
    superPackage = findpackage('hg');
    pkg = findpackage('hg');
 
    % class definition
    c = schema.class(pkg, 'taggedline', findclass(superPackage, 'line'));
 
    if isempty(findtype('yes/no'))
        schema.EnumType('yes/no', {'yes', 'no'});
    end
 
    % add properties to class
    schema.prop(c, 'Editable', 'yes/no');
end

And our constructor is:

function self = taggedline
%OBJECT constructor for the simple.object class
    self = hg.taggedline;
end

Here we have placed the schema.EnumType definition in the class definition function. It is usually better to place type definition code in the package definition function, which is executed prior to any of the package classes and available in all classes. But in this particular case we are extending the built-in hg package and because hg is already defined internally, our package definition code is never actually executed.

The schema.UserType has the following constructor syntax:

schema.UserType('newTypeName', 'baseTypeName', typeCheckFunctionHandle)

For example, to create a user-defined type for unsigned eight-bit integers we might use the following code:

schema.UserType('uint8', 'short', @check_uint8)
 
function check_uint8(value)
%CHECK_UINT8 Check function for uint8 type definition
    if isempty(value) || (value < 0) || (value > 255)
        error('Value must be a scalar between 0 and 255');
    end
end

Hidden properties

Visible is an 'on/off' meta-property that controls whether or not a property is displayed when using the get function without specifying the property name. Using this mechanism we can easily detect hidden undocumented properties. For example:

>> for prop = get(classhandle(handle(gcf)),'Properties')'
       if strcmpi(prop.Visible,'off'), disp(prop.Name); end
   end
 
BackingStore
CurrentKey
CurrentModifier
Dithermap
DithermapMode
DoubleBuffer
FixedColors
HelpFcn
HelpTopicMap
MinColormap
JavaFrame
OuterPosition
ActivePositionProperty
PrintTemplate
ExportTemplate
WaitStatus
UseHG2
PixelBounds
HelpTopicKey
Serializable
ApplicationData
Behavior
XLimInclude
YLimInclude
ZLimInclude
CLimInclude
ALimInclude
IncludeRenderer

Note that hidden properties such as these are accessible via get/set just as any other property. It is simply that they are not displayed when you run get(gcf) or set(gcf) – we need to specifically refer to them by their name: get(gcf,’UseHG2′). Many other similar hidden properties are described in this website.

You may have noticed that the CaseSensitive meta-property did not show up above when we used get to show the meta-properties of our Value property. This is because CaseSensitive has its own Visible meta-property set to 'off' (i.e., hidden).

Additional meta-properties

FactoryValue is used to set an initial value for the property whenever a new simple.object instance is created.

GetFunction and SetFunction were described in last week’s article, Creating a UDD Hierarchy.

AccessFlags is a Matlab structure of 'on/off' fields that control what happens when the property is accessed:

FieldnameDescription
PublicSetControls setting the property from code external to the class
PublicGetControls reading the property value from code external to the class
PrivateSetControls setting the property from internal class methods
PrivateGetControls reading the property value from internal class methods
InitControls initializing the property using FactoryValue in the class definition file
Default??? (Undocumented, no examples exist)
ResetControls initializing the property using FactoryValue when executing the built-in reset function
SerializeControls whether this object can be serialized
CopyControls whether to pass the property’s current value to a copy
ListenerControls whether property access events are generated or not
AbortSetControls whether property set events are generated when a set operation will not change the property’s value

The CaseSensitive meta-property has AccessFlag.Init = 'off'. This means that properties added to a class definition file are always case insensitive.

Another interesting fact is that properties can be abbreviated as long as the abbreviation is unambiguous. Using our simple.object as an example:

>> a = simple.object('a');
>> a.n  % abbreviation of Name
ans =
a
 
>> a.v  % abbreviation of Value
ans =
    0.0000

It is considered poor programming practice to use either improperly cased, or abbreviated names when writing code. It is difficult to read, debug and maintain. But show me a Matlab programmer who has never abbreviated Position as ‘pos’…

Note: for completeness’ sake, read yesterday’s post on MCOS properties on Loren’s blog, written by Dave Foti, author of the original UDD code. Dave’s post describes the fully-documented MCOS mechanism, which is newer than the undocumented UDD mechanism described here. As mentioned earlier, whereas UDD existed (and still exists) in all Matlab 7 releases, MCOS is only available since R2008a. UDD and MCOS co-exist in Matlab since R2008a. MCOS has definite advantages over UDD, but cannot be used on pre-2008 Matlab releases. Different development and deployment requirements may dictate using either UDD or MCOS (or both). Another pre-R2008a alternative is to use Matlab’s obsolete yet documented class system.

In the next installment of this series we will take a look at UDD events and listeners.

]]>
https://undocumentedmatlab.com/blog_old/udd-properties/feed 8
Hierarchical Systems with UDDhttps://undocumentedmatlab.com/blog_old/hierarchical-systems-with-udd https://undocumentedmatlab.com/blog_old/hierarchical-systems-with-udd#comments Wed, 02 Mar 2011 18:00:25 +0000 https://undocumentedmatlab.com/?p=2146 Related posts:
  1. Introduction to UDD UDD classes underlie many of Matlab's handle-graphics objects and functionality. This article introduces these classes....
  2. Creating a simple UDD class This article explains how to create and test custom UDD packages, classes and objects...
  3. UDD Properties UDD provides a very convenient way to add customizable properties to existing Matlab object handles...
  4. UDD Events and Listeners UDD event listeners can be used to listen to property value changes and other important events of Matlab objects...
]]>
Once again I welcome guest blogger Donn Shull, who continues his multi-part series about Matlab’s undocumented UDD objects.

We have looked at the tools for working with UDD classes, and created a simple UDD class. Today I shall show how to create a hierarchy of UDD objects.

Creating hierarchical structures with UDD objects

UDD is the foundation for both Handle Graphics (HG) and Simulink. Both are hierarchical systems. It stands to reason that UDD would offer support for hierarchical structures. It is straightforward to connect UDD objects together into searchable tree structures. All that is necessary is a collection of UDD objects that don’t have any methods or properties named 'connect', 'disconnect', 'up', 'down', 'left', 'right' or 'find'.

We illustrate the technique by creating a hierarchy of simple.objects as shown in the following diagram:

Sample UDD objects hierarchy

Sample UDD objects hierarchy

To begin we create five instances of the simple.object class from the previous article:

% Remember that simple.object accepts a name and a value
a = simple.object('a', 1);
b = simple.object('b', 1);
c = simple.object('c', 0);
d = simple.object('d', 1);
e = simple.object('e', 1);

To form the structure we use the connect method. We can use either dot notation or the Matlab syntax:

% Dot-notation examples:
a.connect(b, 'down');
b.connect(a, 'up');       % alternative to the above
 
% Matlab notation examples:
connect(a, b, 'down');
connect(b, a, 'up');      % alternative to the above

Next, connect node c into our hierarchy. There are several options here: We can use ‘down’ to connect a to c. Or we could use ‘up’ to connect c to a. Similarly, we can use either ‘left’ or ‘right’ to connect b and c. Here’s one of the many possible ways to create our entire hierarchy:

b.connect(a, 'up');
c.connect(b, 'left');
d.connect(b, 'up');
e.connect(d, 'left');

Inspecting UDD hierarchy structures

We now have our structure and each object knows its connection to other objects. For example, we can inspect b’s connections as follows:

>> b.up
ans =
  Name: a
 Value: 1.000000
 
>> b.right
ans =
  Name: c
 Value: 0.000000
 
>> b.down
ans =
  Name: d
 Value: 1.000000

We can search our structure by using an undocumented form of the built-in find command. When used with connected UDD structures, find can be used in the following form:

objectArray = find(startingNode, 'property', 'value', ...)

To search from the top of our hierarchy for objects of type simple.object we would use:

>> find(a, '-isa', 'simple.object')
ans =
        simple.object: 5-by-1    % a, b, c, d, e

Which returns all the objects in our structure, since all of them are simple.objects. If we repeat that command starting at b we would get:

>> find(b, '-isa', 'simple.object')
ans =
	simple.object: 3-by-1    % b, d, e

find searches the structure downward from the current node. Like many Matlab functions, find can be used with multiple property value pairs, so if we want to find simple.object objects in our structure with Value property =0, we would use the command:

>> find(a, '-isa', 'simple.object', 'Value', 0)
ans =
  Name: c
 Value: 0.000000

Visualizing a UDD hierarchy

Hierarchical structures are also known as tree structures. Matlab has an undocumented function for visualizing and working with trees namely uitree. Yair has described uitree in a series of articles. Rather than following the techniques in shown in Yair’s articles, we are going to use a different method that will allow us to introduce the following important techniques for working with UDD objects:

  • Subclassing, building your class on the foundation of a parent class
  • Overloading properties and methods of the superclass
  • Using meta-properties GetfFunction and SetFunction

Because the steps shown below will subclass an HG class, they will modify our simple.object class and probably make it unsuitable for general use. Yair has shown that uitree is ready made for displaying HG trees and we saw above that HG is a UDD system. We will use the technique from uitools.uibuttongroup to make our simple.object class a subclass of the HG class hg.uipanel. Modify the class definition file as follows:

% class definition
superPackage = findpackage('hg');
superClass = findclass(superPackage, 'uipanel');
simpleClass = schema.class(simplePackage, 'object',superClass);

Now we can either issue the clear classes command or restart Matlab and then recreate our structure. The first thing that you will notice is that when we create the first simple.object that a figure is also created. This is expected and is the reason that this technique is not useful in general. We will however use this figure to display our structure with the following commands:

t = uitree('v0', 'root', a);  drawnow;
t.expand(t.getRoot);  drawnow;
t.expand(t.getRoot.getFirstChild);

Simple structure presented in a Matlab uitree

Simple structure presented in a Matlab uitree

The label on each of our objects is ‘uipanel’ and this is probably not what we want. If we inspect our object or its hg.uipanel super-class (note: this would be a great time to use Yair’s uiinspect utility), we can see there is a Type property that has a value of ‘uipanel’. Unfortunately this property is read-only, so we cannot change it. We can however overload it by placing a schema.prop in our class definition named Type. This will allow us to overload or replace the parent’s Type property with our own definition:

p = schema.prop(simpleClass, 'Type', 'string');
p.FactoryValue = 'simple.object';

Once again, issue the clear classes command or restart Matlab, then recreate our structure. Our tree now has each node labeled with the ‘simple.object’ label:

Corrected node names for our UDD structure

Corrected node names for our UDD structure

This is a little more descriptive but what would really be nice is if we could label each node with the value of the Name property. As luck would have it, we can do just that. When we add a property to a UDD class we are adding an object of type schema.prop. So our properties have their own properties and methods (so-called meta-data). We are going to set the GetFunction property of our Type property. GetFunction holds a handle of the function to be called whenever the property is accessed:

p = schema.prop(simpleClass, 'Type', 'string');
p.GetFunction = @getType;

The prototype for the function that GetFunction references has three inputs and one output: The inputs are the handle of the object possessing the property, the value of that property, and the property object. The output is the value that will be supplied when the property is accessed. So our GetFunction can be written to supply the value of the Name property whenever the Type property value is being read:

function propVal = getType(self, value, prop)
   propVal = self.Name;
end

Alternately, as a single one-liner in the schema definition file:

p.GetFunction = @(self,value,prop) self.Name;

Similarly, there is a corresponding SetFunction that enables us to intercept changes to a property’s value and possibly disallow invalid values.

With these changes when we recreate our uitree we obtain:

Overloaded property GetFunction

Overloaded property GetFunction

A Java class for UDD trees

We will have more to say about the relationship between UDD and Java in a future article. For now we simply note that the com.mathworks.jmi.bean.UDDObjectTreeModel class in the JMI package provides some UDD tree navigation helper functions. Methods include getChild, getChildCount, getIndexOfChild and getPathToRoot. The UDDObjectTreeModel constructor requires one argument, an instance of your UDD tree root node:

% Create a UDD tree-model instance
>> uddTreeModel = com.mathworks.jmi.bean.UDDObjectTreeModel(a);
 
% Get index of child e and its parent b:
>> childIndex = uddTreeModel.getIndexOfChild(b, e)
childIndex =
     1
 
% Get the root's first child (#0):
>> child0 = uddTreeModel.getChild(a, 0)
child0 =
  Name: b
 Value: 1.000000
 
% Get the path from node e to the root:
>> path2root = uddTreeModel.getPathToRoot(e)
path2root =
com.mathworks.jmi.bean.UDDObject[]:
    [simple_objectBeanAdapter2]      % <= a
    [simple_objectBeanAdapter2]      % <= b
    [simple_objectBeanAdapter2]      % <= e
 
>> path2root(3)
ans =
  Name: e
 Value: 1.000000

We touched on a few of the things that you can do by modifying the properties of a schema.prop in this article. In the following article we will take a more detailed look at this essential class.

]]>
https://undocumentedmatlab.com/blog_old/hierarchical-systems-with-udd/feed 5
Creating a simple UDD classhttps://undocumentedmatlab.com/blog_old/creating-a-simple-udd-class https://undocumentedmatlab.com/blog_old/creating-a-simple-udd-class#comments Wed, 23 Feb 2011 17:29:05 +0000 https://undocumentedmatlab.com/?p=2130 Related posts:
  1. Introduction to UDD UDD classes underlie many of Matlab's handle-graphics objects and functionality. This article introduces these classes....
  2. UDD Properties UDD provides a very convenient way to add customizable properties to existing Matlab object handles...
  3. UDD Events and Listeners UDD event listeners can be used to listen to property value changes and other important events of Matlab objects...
  4. Hierarchical Systems with UDD UDD objects can be grouped in structured hierarchies - this article explains how...
]]>
Once again I welcome guest blogger Donn Shull, who continues his multi-part series about Matlab’s undocumented UDD objects.

Creating a new UDD package

To illustrate the construction of UDD classes with Matlab m-code, let’s create a simple class belonging to a new simple package. Our class will have two properties: a Name property of type string, and a Value property of type double. This class will have two methods that will illustrate overloading the built-in disp function, and using a dialog method to present a GUI. Our class will also have one event, to demonstrate UDD event handling.

To create this simple UDD class we need two directories and five m-files (downloadable here): The parent directory needs to be a directory on the Matlab path. A subdirectory of the parent directory is named with the symbol @ followed by our UDD package name – this is the package directory. In this example, the subdirectory is called @simple.

Within the @simple directory, place a file named schema.m, which is the package definition file. This is a very simple file, that merely calls schema.package to create a new package called ‘simple’:

function schema()
%SCHEMA simple package definition function.
   schema.package('simple');
end

If you place additional m-files in the package directory they will be called package function files. Those files will have package scope and can be accessed with the notation packagename.functionname. We will not use package functions in this example, so we will only have the schema.m file shown above.

Creating a new UDD class

Next, create another subdirectory beneath @simple, named with an @ symbol followed by the UDD class name. In this example we will create the directory @object (i.e., /@simple/@object/). We place four m-files in this directory:

The first file is yet another schema.m file, which is the class-definition file:

function schema()
%SCHEMA  simple.object class definition function.
 
   % Get a handle to the 'simple' package
   simplePackage = findpackage('simple');
 
   % Create a base UDD object
   simpleClass = schema.class(simplePackage, 'object');
 
   % Define the class methods:
 
   % dialog.m method
   m = schema.method(simpleClass, 'dialog');
   s = m.Signature;
   s.varargin    = 'off';
   s.InputTypes  = {'handle'};
   s.OutputTypes = {};
 
   % disp.m method
   m = schema.method(simpleClass, 'disp');
   s = m.Signature;
   s.varargin    = 'off';
   s.InputTypes  = {'handle'};
   s.OutputTypes = {};
 
   % Define the class properties:
   schema.prop(simpleClass, 'Name', 'string');
   schema.prop(simpleClass, 'Value', 'double');
 
   % Define the class events:
   schema.event(simpleClass, 'simpleEvent');
end

Here, we used the built-in findpackage function to identify our base package (simple). Then we used schema.class to define a new class ‘object’ within that base package. We next defined two class methods, two properties and finally an event.

Defining class methods

It is not mandatory to define the method signatures as we have done in our class definition file. If you omit the method signature definitions, Matlab will automatically generate default signatures that will actually work in most applications. However, I believe that it is bad practice to omit the method signature definitions in a class definition file, and there are cases where your classes will not work as you have intended if you omit them.

Now, place a file named object.m in the @object directory. This file contains the class constructor method, which is executed whenever a new instance object of the simple.object class is created:

function simpleObject = object()
%OBJECT constructor for the simple.object class
%
%   SIMPLEOBJECT = OBJECT(NAME, VALUE) creates an instance of the
%   simple.object class with the Name property set to NAME and the
%   Value property set VALUE
%
%   SIMPLEOBJECT = OBJECT(NAME) creates an instance of the simple.object
%   class with the Name property set to NAME. The Value property will be
%   given the default value of 0.
%
%   SIMPLEOBJECT = OBJECT creates an instance of the simple.object class
%   and executes the simple.object dialog method to open a GUI for editing
%   the Name and Value properties.
%
%   INPUTS:
%       NAME          : string
%       VALUE         : double
%
%   OUTPUTS:
%       SIMPLEOBJECT  : simple.object instance
   simpleObject = simple.object;
   switch nargin
      case 0
         simpleObject.dialog;
      case 1
         simpleObject.Name = name;
      case 2
         simpleObject.Name = name;
         simpleObject.Value = value;
   end
end

The two other m-files in the @object directory will be our class methods – a single file for each method. In our case they are disp.m and dialog.m:

function disp(self)
%DISP overloaded object disp method
%
%   DISP(SELF) or SELF.DISP uses the MATLAB builtin DISP function
%   to display the Name and Value properties of the object.
%
%   INPUTS:
%       SELF  : simple.object instance
   builtin('disp', sprintf('  Name: %s\n Value: %f', self.Name, self.Value));
   %Alternative: fprintf('\n  Name: %s\n Value: %f', self.Name, self.Value));
end

And the dialog method (in dialog.m):

function dialog(self)
%DIALOG dialog method for simple.object for use by openvar
%
%   DIALOG(SELF) or SELF.DIALOG where self is the name of the simple.object
%   instance opens a gui to edit the Name and Value properties of self.
%
%   INPUTS:
%       SELF  : simple.object
   dlgValues = inputdlg({'Name:', 'Value:'}, 'simple.object', 1, {self.Name, mat2str(self.Value)});
   if ~isempty(dlgValues)
      self.Name = dlgValues{1};
      self.Value = eval(dlgValues{2});
   end
end

Testing our new class

Now let’s test our new class by creating an instance without using any input arguments

a = simple.object

This calls the object’s constructor method, which launches the input dialog GUI:

UDD simple class GUI

UDD simple class GUI

Note the default empty string value for the Name property, and the default zero value for the Value property. In one of the following articles I will show how to control property values. For now let’s assign ‘a’ to Name and 1 to Value using the GUI. Selecting OK updates our object and closes the GUI. Matlab then calls the object’s disp method to display our object in the command window:

a = 
  Name: a
 Value: 1.000000

We can reopen our object’s GUI using three methods: The most obvious is to invoke the dialog method using a.dialog or dialog(a). Alternately, double click on a in the workspace explorer window – Matlab will automatically call the built-in openvar function with the variable name and value as arguments. Which leads us to the third method – simply call openvar(‘a’, a) directly:

% Alternatives for programmatically displaying the GUI
a.dialog();  % or simply: a.dialog
dialog(a);
openvar('a',a);

Accessing UDD help

You may have noticed that in our constructor and method files we have included help text. This is good practice for all Matlab files in general, and UDD is no exception. We can access the UDD class help as follows:

> help simple.object
 OBJECT constructor for the simple.object class
 
    SIMPLEOBJECT = OBJECT(NAME, VALUE) creates an instance of the 
    simple.object class with the Name property set to NAME and the 
    Value property set VALUE
 
    SIMPLEOBJECT = OBJECT(NAME) creates an instance of the simple.object
    class with the Name property set to NAME. The Value property will be
    given the default value of 0.
 
    SIMPLEOBJECT = OBJECT creates an instance of the simple.object class 
    and executes the simple.object dialog method to open a GUI for editing
    the Name and Value properties.
 
    INPUTS:
        NAME          : string
        VALUE         : double
 
    OUTPUTS:
        SIMPLEOBJECT  : simple.object instance
 
>> help simple.object.disp
 DISP overloaded object disp method
 
    DISP(SELF) or SELF.DISP uses the MATLAB builtin DISP function
    to display the Name and Value properties of the object.
 
    INPUTS:
        SELF  : simple.object instance

One of the best ways to learn how Matlab works is to examine code written by the Matlab development team. openvar is a good example: By looking at it we can see that if a variable is a handle object and is opaque, then openvar will check to see if it has a dialog method. If so, it will use that to open the variable for editing. With this information we can guess that MCOS, UDD and even java objects can all launch their own dialog editors simply by having an appropriate dialog method.

An excellent source of UDD information is available in the Matlab toolbox folders. The base Matlab toolbox contains sixteen different UDD packages to explore. Yummy!

In the next article of this UDD series we will look at creating hierarchical structures using our simple.object and a unique UDD method.

]]>
https://undocumentedmatlab.com/blog_old/creating-a-simple-udd-class/feed 3
Introduction to UDDhttps://undocumentedmatlab.com/blog_old/introduction-to-udd https://undocumentedmatlab.com/blog_old/introduction-to-udd#comments Wed, 16 Feb 2011 18:00:09 +0000 https://undocumentedmatlab.com/?p=2036 Related posts:
  1. Creating a simple UDD class This article explains how to create and test custom UDD packages, classes and objects...
  2. UDD Events and Listeners UDD event listeners can be used to listen to property value changes and other important events of Matlab objects...
  3. New information on HG2 More information on Matlab's new HG2 object-oriented handle-graphics system...
  4. Multi-column (grid) legend This article explains how to use undocumented axes listeners for implementing multi-column plot legends...
]]>
I would like to welcome guest blogger Donn Shull. Donn will present a series of articles about UDD classes and objects, on which many undocumented Matlab features and functions are based.

Background on UDD

Matlab has used objects for a long time. In R8 (Matlab 5.0), their first user accessible class system was introduced. Andy Register wrote a detailed reference on using this system. Although that original system is obsolete, it is still available in R24 (R2010b).

UDD objects (also referred to as schema objects) were introduced with R12 (Matlab 6.0). UDD has been a foundation platform for a number of core Matlab technologies. MathWorks have consistently maintained that UDD is only meant for internal development and not for Matlab users. So, while UDD has no formal documentation, there are plenty of examples and tools to help us learn about it.

It is somewhat odd that despite Matlab’s new object-oriented system (MCOS)’s introduction 3 years ago, and the ongoing concurrent development of HG2 classes, the older-technology UDD is still being actively developed, as evidenced by the increasing number of UDD classes in recent releases. More background on the differences between these different sets of classes can be found here.

Why should we bother learning UDD?

There are some things to consider before deciding if you want to spend the time to learn about the UDD class system:

The case against studying UDD classes

  • There is no documentation from The MathWorks for these classes
  • You will not get any help from The MathWorks in applying these classes
  • The UDD system is now more than a decade old and may be phased out in future Matlab releases (perhaps in HG2?)

The case for studying UDD classes

  • UDD is currently the foundation of handle graphics, Java integration, COM, and Simulink
  • The m code versions of UDD may be considered a forerunner of the newer MCOS class system
  • To avoid memory leaks when using Callbacks in GUI applications you currently need to use UDD
  • UDD techniques facilitate Matlab interaction with Java GUIs
  • UDD directly supports the Matlab style method invocation as well as dot notation for methods without the need to write subsasgn and subsref routines

Tools for Learning about UDD

We start by describing some undocumented Matlab tools that will help us investigate and understand UDD classes.

  • findpackage – All UDD Classes are defined as members of a package. findpackage takes the package name as an input argument and returns a schema.package object which provides information about the package
  • findclass – This method of the schema.package object returns a schema.class object of the named class if the class exists in the package
  • classhandle – For a given UDD object classhandle returns a schema.class object with information about the class. classhandle and findclass are two ways of getting the same information about a UDD class. findclass works with a schema.package object and a class name and does not require an instance of the class. classhandle works with an instance of a class
  • findprop – This method of the schema.class object returns a schema.prop object which contains information about the named property
  • findevent – This method of the schema.class object returns a schema.prop object which contains information about the named event
  • handle – handle is a multifaceted and unique term for The MathWorks. There are both UDD and MCOS handle classes. There is a UDD handle package. In terms of the tools we need, handle is also an undocumented function which converts a numeric handle into a UDD handle object. Depending on your background you may want to think of handle as a cast operator which casts a numeric handle into a UDD object.
  • methods – This is used to display the methods of an object
  • methodsview – Provides a graphic display of an objects methods
  • uiinspect – Yair Altman’s object inspection tool, which can be used for COM, Java and Matlab classes (uiinspect will be described in a separate article in the near future).

Before we apply these tools we need to discuss the basic structure of UDD classes. Let’s compare them with the newer, well documented MCOS classes:

MCOS classes can be defined simply as a standalone class or scoped by placing the class in a package or a hierarchy of packages. With UDD, all classes must be defined in a package. UDD Packages are not hierarchical so a UDD package may not contain other packages. UDD classes can always be instantiated with syntax of packageName.className. By default MCOS classes are value classes. With MCOS you can subclass the handle class to create handle classes. UDD classes are handle classes by default, but it is possible to create UDD value classes.

Exploring some important built-in UDD Classes

The current versions of Matlab include a number of built-in UDD packages. We will use our new tools to see what we can learn about these packages. Let us begin by inspecting the two packages that form the basis of the UDD class system.

The schema package

The built-in schema package contains the classes for creating user written UDD classes. It also is used to provide meta information about UDD classes. Using findpackage we will obtain a schema.package object for the schema package and then use it obtain information about the classes it contains:

>> pkg = findpackage('schema')
pkg =
        schema.package
 
>> pkg.get
               Name: 'schema'
    DefaultDatabase: [1x1 handle.Database]
            Classes: [9x1 schema.class]
          Functions: [0x1 handle]
        JavaPackage: ''
         Documented: 'on'

Note that here we have used the dot-notation pkg.get – we could also have used the Matlab notation get(pkg) instead.

We have now learned that that there are nine classes in the schema package. The information about them in a schema package’s Classes property. To see the information about individual classes we inspect this property:

>> pkg.Classes(1).get
               Name: 'class'
            Package: [1x1 schema.package]
        Description: ''
        AccessFlags: {0x1 cell}
             Global: 'off'
             Handle: 'on'
       Superclasses: [0x1 handle]
    SuperiorClasses: {0x1 cell}
    InferiorClasses: {0x1 cell}
            Methods: [4x1 schema.method]
         Properties: [13x1 schema.prop]
             Events: []
     JavaInterfaces: {0x1 cell}

Not surprisingly, the first class in the schema.package is ‘class’ itself. Here we can see that schema.class has 4 methods and 13 properties. We can also see that the schema.class objects have a Name property. Let’s use that information to list all the classes in the schema package:

>> names = cell(numel(pkg.Classes), 1);
>> for index = 1:numel(names), names{index} = pkg.Classes(index).Name; end;
>> names
names =
    'class'
    'method'
    'signature'
    'package'
    'event'
    'prop'
    'type'
    'EnumType'
    'UserType'

These are the base classes for the UDD package schema. To illustrate a different way to get information, let’s use the findclass method of schema.package to get information about the schema.prop class:

>> p = findclass(pkg, 'prop')
p =
        schema.class
 
>> get(p)
               Name: 'prop'
            Package: [1x1 schema.package]
        Description: ''
        AccessFlags: {0x1 cell}
             Global: 'off'
             Handle: 'on'
       Superclasses: [0x1 handle]
    SuperiorClasses: {0x1 cell}
    InferiorClasses: {0x1 cell}
            Methods: [2x1 schema.method]
         Properties: [9x1 schema.prop]
             Events: []
     JavaInterfaces: {0x1 cell}

The handle package

The second basic UDD package is the handle package. Handle holds a special place in Matlab and has multiple meanings: Handle is a type of Matlab object that is passed by reference; handle is a function which converts a numeric handle to an object; handle is an abstract object in the new MCOS class system and handle is also a UDD package as well as the default type for UDD objects.

There is an interesting connection between UDD and MCOS that involves handle. In Matlab releases R12 through R2007b, the UDD handle package had up to 12 classes and did not have any package functions (package functions are functions which are scoped to a package; their calling syntax is [outputs] = packageName.functionName(inputs)).

Beginning with the formal introduction of MCOS in R2008a, the abstract MCOS class handle was introduced. The MCOS handle class has 12 methods. It also turns out that beginning with R2008a, the UDD handle package has 12 package functions which are the MCOS handle methods.

The 12 UDD classes in the handle package fall into two groups: The database and transaction classes work with the schema.package to provide a UDD stack mechanism; the listener and family of EventData classes work with schema.event to provide the UDD event mechanism:

>> pkg = findpackage('handle')
pkg =
        schema.package
 
>> pkg.get
               Name: 'handle'
    DefaultDatabase: [1x1 handle.Database]
            Classes: [12x1 schema.class]
          Functions: [12x1 schema.method]
        JavaPackage: ''
         Documented: 'on'
 
>> names = cell(numel(pkg.Classes), 1);
>> for index = 1:numel(names), names{index} = pkg.Classes(index).Name; end
>> names
names =
    'Operation'
    'transaction'
    'Database'
    'EventData'
    'ClassEventData'
    'ChildEventData'
    'ParentEventData'
    'PropertyEventData'
    'PropertySetEventData'
    'listener'
    'JavaEventData'
    'subreference__'

The hg package

Arguably the most important UDD package in Matlab is the handle graphics package hg. Among the built-in UDD packages, hg is unique in several respects. As Matlab has evolved from R12 through R2011a, the number of default classes in the hg package has nearly doubled going from 17 classes to 30 (UDD has a mechanism for automatically defining additional classes as needed during run-time).

The hg package contains a mixture of Global and non Global classes. These classes return a numeric handle, unless they have been created using package scope. The uitools m-file package provides a great example of extending built-in UDD classes with user written m-file UDD classes.

The UDD class for a Handle-Graphics object can be obtained either by explicitly creating it with the hg package, or using the handle function on the numeric handle obtained from normal hg object creation. Using figure as an example, you can either use figh = hg.figure or fig = figure followed by figh = handle(fig):

>> pkg = findpackage('hg')
pkg =
        schema.package
 
>> pkg.get
               Name: 'hg'
    DefaultDatabase: [1x1 handle.Database]
            Classes: [30x1 schema.class]
          Functions: [0x1 handle]
        JavaPackage: 'com.mathworks.hg'
         Documented: 'on'
 
>> for index = 1:numel(names), names{index} = pkg.Classes(index).Name; end
>> names
names =
    'GObject'
    'root'
    'LegendEntry'
    'Annotation'
    'figure'
    'uimenu'
    'uicontextmenu'
    'uicontrol'
    'uitable'
    'uicontainer'
    'hgjavacomponent'
    'uipanel'
    'uiflowcontainer'
    'uigridcontainer'
    'uitoolbar'
    'uipushtool'
    'uisplittool'
    'uitogglesplittool'
    'uitoggletool'
    'axes'
    'hggroup'
    'text'
    'line'
    'patch'
    'surface'
    'rectangle'
    'light'
    'image'
    'hgtransform'
    'uimcosadapter'

So far we have just explored the very basic concepts of UDD. You may well be wondering what the big fuss is about, since the information presented so far does not have any immediately-apparent benefits.

The following set of articles will describe more advanced topics in UDD usage and customizations, using the building blocks presented today. Hopefully you will quickly understand how using UDD can help achieve some very interesting stuff with Matlab.

]]>
https://undocumentedmatlab.com/blog_old/introduction-to-udd/feed 7