With the virtually boundless graphics capabilities of low-level MATLAB programming, if you happen to find that the standard set of MATLAB user interface objects does not suit all of your needs, or if you just want to spice up your GUI and make it more interesting, you can always create your own interface objects. In this section, we will look at creating two custom user interface objects. If you follow along and understand how these operate, you should then be able use your imagination and create just about any type of interface object you want. The key to designing functional interface or display objects is to make use of your knowledge of the available tools (i.e., the properties of the objects and different types of events that can be recognized). There is never one best solution. Therefore, some of the techniques that we have been able to successfully use will be presented. Also bear in mind that these examples are coded for clarity and you might be able to make enhances that use MATLAB more efficiently.
Most of the techniques we will show here rely heavily on the ButtonDownFcn of a graphics object. When the user clicks the mouse on the object, that object’s ButtonDownFcn callback will be evaluated. Since all graphics objects have this property, you can make an interface with any one you want. For example, you could easily make one out of text object with
and you have a little game that you can play for hours on end. Like trying to swat a fly, every time you click on the text object it will move to some new and random location.
If a 2-dimensional looking flat button suits your needs, create an interface with a patch and text object. However, if that’s all you need, you should probably stick with the uicontrol objects since they are easy to program and look a lot better than any patch/text object combination. Also, remember that you can put pictures on your buttons by using the button’s CData (See Section 10.7.6). Of course, the patch object doesn’t need to be a simple square; in fact, you can create any shape you need and turn it into a button. That in itself may already provide the feature you wanted that uicontrols and uimenus could not offer, so that is the first custom component we will demonstrate.
Simulating Buttons with Image Objects
The easiest way to create your own custom 3-dimensional-looking push buttons is to create two images positioned in the same location (i.e., one on top of the other). One represents the appearance of the button in its "off" state and the other represents its appearance in the "on" state (i.e., when the user clicks on the object). Remember that you can achieve similar results by using the CData property of a uicontrol object (see Section 10.7.6); however, to create non-standard shaped buttons, you still will need to do something like the method described next.
Usually the hardest or most time-consuming aspect of creating these types of buttons is generating the images. This can be done several ways and you will have to experiment and find the one that works best for you.
1. You can create your own image and color map matrix by typing in the numbers that represent indices to the map of RGB values you have specified. This is probably the most time-consuming and most difficult method because you have to make a mental image of what the numbers represent, but it can be done. Another option is to use an image that is already in RGB format, perhaps created in some image editing software; if you have a color mapped format image you could use something like makergb (see section 5.3.3) to create the data for your button.
2. You can piece together axes, patch objects, text, and anything else you want. Size the object the way you want it and then take an image snapshot with F = getframe. When used in this manner getframe will return a structure in F where F.cdata is an M-by-N-by-3 snapshot. (If your computer does not support truecolor, you will get data in F.colormap.) Alter the colors to represent the figure in its opposite state and take another snapshot. Combine the two color maps so that both image objects can be shown simultaneously without color distortion (see example below). To use this technique, you must be able to have multiple software packages up on your machine (i.e., MATLAB and your favorite drawing package). Use your favorite software drawing package and create the button icons. Then use X = getframe(reference_fig, capture_rectangle), where reference_fig is the handle to a figure that is purely used as a location reference point and capture_rectangle is a [left bottom width height] vector that defines the region that will be captured with respect to the lower left corner of the reference_fig figure. If you position the drawing package window in a way so that you can see the icons even when you are in MATLAB, you can experimentally determine the correct capture_rectangle vector which captures the portion of the button icons you want. Execute the getframe command and then see what you captured by typing
In the next example, we will use the following code to help generate the two images shown in Figure 10.51. To achieve a 3-dimensional look, we use light and dark shades of a particular color. Decide on a corner from which it should appear that a light source is located with respect to the button. The two sides adjacent to this corner should use light shading for the button’s up state image and a dark shading for the button’s down state. The opposite two sides can use a thin dark border for the button’s up state and a lighter border in the button’s down state. Choosing the shaded edge’s relative thickness in the two button states is useful, too; your personal preferences and creativity will guide you.
Combine the two maps so that you will be able to use the two images in the same figure without distorting their colors:
You will now have the two buttons shown in Figure 10.51.
Figure 10.51 Up and Down custom buttons using images.
Now you have developed a pair of images that you can save for future use.
To create a button that will toggle between the states represented by the above two images, use something like the following:
Since the ButtonDownFcn is a little difficult to read when it is placed into a string, this code is presented below, as it would exist as actual MATLAB code in a program.
To make the button act more like a push button in the sense that the off state is maintained only while the user holds down the button, all you need to do is add the following line (assuming that the button is in the state in which you want it to normally remain when you set the WindowButtonUpFcn property).
This single line will work even if you have several custom buttons in the interface. However, it is usually a good idea to make a button quickly set the WindowButtonUpFcn it requires when the button down occurs. Continue with the above example by making the ButtonDownFcn set the WindowButtonUpFcn. In addition, have the WindowButtonUpFcn clear itself after it has been evaluated. This should be done in one of the GUI structures previously discussed; otherwise, you will be endlessly frustrated with errors because a quote or parenthesis is missing.
When using images to create multiple user interface buttons make sure:
1. A single color map is applicable for all the images. Create all buttons with a graphics drawing package. Place the images that represent the button’s on and off states next to one another and arrange all of the buttons so that a single capture image can be executed. This makes it easy to keep a small-sized color map that works for all the button images. Then break out the individual images by determining which indices of the large captured matrix correspond to the individual button images.
2. Use one of the GUI programming approaches to make it easy to keep track of all the image object graphics handles and to make the code readable.
3. When you have many custom buttons, it becomes important that you know what state each object button is in. Consider creating a matrix that has 3-by-M elements for the M custom buttons in your GUI. Each column of the matrix could be dedicated to maintaining information about a particular button. For example, row one of column one could be the handle to the on-state image for a particular button, row 2 could be the handle to the off-state image for that button, and row 3 could be used to indicate the current state of the button (much like the Value property of a uicontrol). Keeping track of this kind of information will make it simple to reset, automatically set certain button states, make all your custom buttons mutually exclusive, etc.
4. Make your callbacks as independent as possible so that you don’t need to rely on another object’s callback, since it may have been changed from what you might expect it to be.
Creating a Dial
Let’s step through the process of creating a dial like the one shown in Figure 10.52. We want the user to be able to click on the dial and graphically move the arrow about the arrow’s hinge. To move the arrow in a continuous fashion, the user must click down and hold the mouse button while moving about the arrow’s hinge and then release when the arrow points to the desired value.
Figure 10.52 A custom dial control.
This program may be altered so that the dial could be used as a means of displaying values from an application, rather than just as an application input device. In addition, it would also be nice to be able to specify the position that the dial should occupy within any given figure so that multiple dials could be created as part of a GUI. Adding these features would be a good exercise.