Lay Out a UI Programmatically

You can adjust the size and location of components, and manage front-to-back order of grouped components by setting certain property values. This topic explains how to use these properties to get the layout you want. It also explains how to use the SizeChangedFcn callback to control the UI’s resizing behavior.

Component Placement and Sizing

A UI layout consists of a figure and one or more components that you place inside the figure. Accurate placement and sizing of each component involves setting certain properties and understanding how the inner and outer boundaries of the figure relate to each other.

Location and Size of Outer Bounds and Drawable Area

The area inside the figure, which contains the UI components, is called the drawable area. The drawable area excludes the figure borders, title bar, menu bar, and tool bars. You can control the location and size of the drawable area by setting the Position property of the figure as a four-element row vector. The first two elements of this vector specify the location. The last two elements specify the size. By default, the figure’s Position values are in pixels.

This command creates a figure and sets the Position value. The left edge of the drawable area is 258 pixels from the left side of the screen. Its bottom edge is 132 pixels up from the bottom of the screen. Its size is 560 pixels wide by 420 pixels high:

f = figure('Position',[258 132 560 420]);

You can query or change the outer bounds of the figure by using the OuterPosition property. The region enclosed by the outer bounds of the figure includes the figure borders, title bar, menu bar, and tool bars. Like the Position property, the OuterPosition is a four element row vector:

f.OuterPosition
ans =

   250   124   576   512
The left outer edge of this figure is 250 pixels from the left side of the screen. Its bottom outer edge is 124 pixels up from the bottom of the screen. The area enclosed by the outer bounds of the figure is 576 pixels wide by 512 pixels high.

Explicitly changing the Position or OuterPosition causes the other property to change. For example, this is the current Position value of f:

f.Position
ans =

   258   132   560   420
Changing the OuterPosition causes the Position to change:
f.OuterPosition = [250 250 490 340];
f.Position
ans =

   258   258   474   248

Other UI components, such as uicontrols, uitables, and uipanels have a Position property, which you can use to set their location and size.

Units of Measure

The default units associated with the Position property depend on the component you are placing. However, you can change the Units property to lay out your UI in the units of your choice. There are six different units of measure to choose from: inches, centimeters, normalized, points, pixels, and characters.

Always specify Units before Position for the most predictable results.

f = figure('Units','inches','Position',[4 3 6 5]);

Your choice of units can affect the appearance and resizing behavior of the UI:

  • If you want the UI components to scale proportionally with the figure when the user resizes the figure, set the Units property of the components to 'normalized'.

  • UI Components do not scale proportionally inside the figure when their Units property is set to 'inches', 'centimeters', 'points', 'pixels', or 'characters'.

  • If you are developing a cross-platform UI, then set the Units property to 'points' or 'characters' to make the layout consistent across all platforms.

Example of a Simple Layout

Here is the code for a simple app containing an axes and a button. To see how it works, copy and paste this code into the editor and run it.

function myui
   % Add the UI components
   hs = addcomponents;
   
   % Make figure visible after adding components
   hs.fig.Visible = 'on';
   
   function hs = addcomponents
       % add components, save handles in a struct
       hs.fig = figure('Visible','off',...
                  'Resize','off',...
                  'Tag','fig');
       hs.btn = uicontrol(hs.fig,'Position',[10 340 70 30],...
                  'String','Plot Sine',...
                  'Tag','button',...
                  'Callback',@plotsine);
       hs.ax = axes('Parent',hs.fig,...
                 'Position',[0.20 0.13 0.71 0.75],...
                 'Tag','ax');
   end

   function plotsine(hObject,event)
       theta = 0:pi/64:6*pi;
       y = sin(theta);
       plot(hs.ax,theta,y);
   end
end
This code performs the following tasks:

  • The main function, myui, calls the addcomponents function. The addcomponents function returns a structure, hs, containing the handles to all the UI components.

  • The addcomponents function creates a figure, an axes, and a button, each with specific Position values.

    • Notice that the Resize property of the figure is 'off'. This value disables the resizing capability of the figure.

    • Notice that the Visible property of the figure is 'off' inside the addcomponents function. The value changes to 'on' after addcomponents returns to the calling function. Doing this delays the figure display until after MATLAB® adds all the components. Thus, the resulting UI has a clean appearance when it starts up.

  • The plotsine function plots the sine function inside the axes when the user clicks the button.

Managing the Layout in Resizable UIs

To create a resizable UI and manage the layout when the user resizes the window, set the figure’s SizeChangedFcn property to be a handle to a callback function. Code the callback function to manage the layout when the window size changes.

If your UI has another container, such as a uipanel or uibuttongroup, you can manage the layout of the container’s child components in a separate callback function that you assign to the SizeChangedFcn property.

The SizeChangedFcn callback executes only under these circumstances:

  • The container becomes visible for the first time.

  • The container is visible while its drawable area changes.

  • The container becomes visible for the first time after its drawable area changes. This situation occurs when the drawable area changes while the container is invisible and becomes visible later.

Note

Typically, the drawable area changes at the same time the outer bounds change. However, adding or removing menu bars or tool bars to a figure causes the outer bounds to change while the drawable area remains constant. Therefore, the SizeChangedFcn callback does not execute when you add or remove menu bars or tool bars.

This app is a resizable version of the simple app defined in Example of a Simple Layout. This code includes a figure SizeChangedFcn callback called resizeui. The resizeui function calculates new Position values for the button and axes when the user resizes the window. The button appears to be stationary when the user resizes the window. The axes scales with the figure.

function myui
   % Add the UI components
   hs = addcomponents;
   
   % Make figure visible after adding components
   hs.fig.Visible = 'on';
   
   function hs = addcomponents
       % Add components, save handles in a struct
       hs.fig = figure('Visible','off',...
                  'Tag','fig',...
                  'SizeChangedFcn',@resizeui);
       hs.btn = uicontrol(hs.fig,'String',...
                  'Plot Sine',...
                  'Callback',@plotsine,...
                  'Tag','button');
       hs.ax = axes('Parent',hs.fig,...
                  'Units','pixels',...
                  'Tag','ax');
   end

   function plotsine(hObject,event)
       theta = 0:pi/64:6*pi;
       y = sin(theta);
       plot(hs.ax,theta,y);
   end

   function resizeui(hObject,event)
           
       % Get figure width and height
       figwidth = hs.fig.Position(3);
       figheight = hs.fig.Position(4);
       
       % Set button position
       bheight = 30; 
       bwidth = 70;
       bbottomedge = figheight - bheight - 50;
       bleftedge = 10;
       hs.btn.Position = [bleftedge bbottomedge bwidth bheight];
       
       % Set axes position
       axheight = .75*figheight;
       axbottomedge = max(0,figheight - axheight - 30);
       axleftedge = bleftedge + bwidth + 30;
       axwidth = max(0,figwidth - axleftedge - 50);
       hs.ax.Position = [axleftedge axbottomedge axwidth axheight];
   end
end
The resizeui function sets the location and size of the button and axes whenever the user resizes the window:

  • The button height, width, and left edge stay the same when the window resizes.

  • The bottom edge of the button, bbottomedge, allows 50 pixels of space between the top of the figure and the top of the button.

  • The value of the axes height, axheight, is 75% of the available height in the figure.

  • The value of the axes bottom edge, axbottomedge, allows 30 pixels of space between the top of the figure and the top of the axes. In this calculation, the max function limits this value to nonnegative values.

  • The value of the axes width, axwidth, allows 50 pixels of space between the right side of the axes and the right edge of the figure. In this calculation, the max function limits this value to nonnegative values.

Notice that all the layout code is inside the resizeui function. It is a good practice to put all the layout code inside the SizeChangedFcn callback to ensure the most accurate results.

Also, it is important to delay the display of the entire UI window until after all the variables that a SizeChangedFcn callback uses are defined. Doing so can prevent the SizeChangedFcn callback from returning an error. To delay the display of the window, set the Visible property of the figure to 'off'. After you define all the variables that your SizeChangedFcn callback uses, set the Visible property to 'on'.

Manage the Stacking Order of Grouped Components

The default front-to-back order, or stacking order, of components in a UI is as follows:

  • Axes and other graphics objects appear behind other components. UI components and containers (uipanels, uibuttongroups, and uitabs) appear in front of them.

  • UI components and containers appear in the order in which you create them. New components appear in front of existing components.

You can change the stacking order at any time, but there are some restrictions. Axes and other graphics objects can stack in any order with respect to each other. However, axes and other graphics objects cannot stack in front of UI components and containers. They always appear behind UI components and containers.

You can work around this restriction by grouping graphics objects into separate containers. Then you can stack those containers in any order. To group a graphics object into a container, set its Parent property to be that container. For example, you can group an axes into a uipanel by setting the Parent property of the axes to be the uipanel.

The Children property of a uipanel, uibuttongroup, or uitab lists the child objects inside the container according to their stacking order.

Related Topics