Skip to content

# MIB Plugin with GUI

Back to MIB | User Interface | Plugins | Tutorials

## Overview

The MIB Plugin is a tutorial example for creating plugins for Microscopy Image Browser (MIB) with a graphical interface.
It demonstrates how to build a simple plugin that takes a threshold value from an input in the main plugin window to generate a mask layer by thresholding the current image slice.

This plugin serves as a starting point for developers to understand MIB plugin architecture with GUI and customize functionality for their needs.

## Understanding of sections

### Filenames

The plugin with GUI has the following files:

- `[PLUGIN-NAME]Controller.m`, controller of the plugin with the main logic and functions
- `[PLUGIN-NAME]GUI.fig`, figure file generated using MATLAB guide tool for framework development.
- `[PLUGIN-NAME]GUI.m`, m-file automatically created by guide. This file serves as a View to handle basic logic of widgets

Info

where `[PLUGIN-NAME]` is the name of the plugin.

Warning

This plugin name (`[PLUGIN-NAME]`) should match with the name of the directory where the plugin is located.

Example

For example `mibPluginController.m`:

- `[PLUGIN-NAME]` -> `mibPlugin`, located under `Plugins/Tutorials/mibPlugin` directory
- Full path: `MIB/Plugins/Tutorials/mibPlugin/mibPluginController.m` The same applies to `mibPluginGUI.m` and `mibPluginGUI.fig`

Plugins with GUI made using appdesigner

AppDesigner is a newer MATLAB framework for development of GUI applications. Plugins that are created using appdesigner are also compatible with MIB

- AppDesigner based plugins have `[PLUGIN-NAME]GUI.mlapp` created by MATLAB appdesigner editor. (e.g. `MyPluginGUI.mlapp`. This file, together with `MyPluginController.m` should be placed under `MyPlugin` directory). See more here.

Plugins without GUI

The plugin without GUI has only a single file that is called as `[PLUGIN-NAME]Controller.m`, where `[PLUGIN-NAME]` is the name of the plugin. See more here.

### properties

This section can be used to define properties of the plugin class. These properties will be available to all functions withing the plugin class.

Code for properties

    properties
        mibModel
        % handles to the model
        View
        % handle to the view
        listener
        % a cell array with handles to listeners
    end

### events

This plugin has a single event that is triggered when the plugin is closed.

Code for events

    events
        %> Description of events
        closeEvent
        % event firing when plugin is closed
    end

### Methods (static)

This section contains a function that listens for `updateGuiWidgets` event from mibModel. When it comes, the plugin refreshes itself using `obj.updateGuiWidgets()` function.

Code for static methods

    function ViewListner_Callback2(obj, src, evnt)
        switch evnt.EventName
            case {'updateGuiWidgets'}
                obj.updateWidgets();
        end
    end

### constructor

Constructor is the first function (`function obj = mibPluginController(mibModel)`) that is initialized when the plugin starts.

`mibModel` that holds data classes of MIB is passed as a parameter and assigned into `obj.mibModel` variable available to all functions of the plugin.

`obj.View = mibChildView(obj, guiName);` initialize the view provided by mibPluginGUI.m and the widgets of the GUI can be accessed using `obj.View.handles.[widgetTag]`. For example, the threshold value can be acquired by
`value = obj.View.handles.thresholdValue.String;`

The following section checks whether MIB is in the virtual stack mode and closes the plugin in this case without any output.

`mibRescaleWidgets(obj.View.gui);` resized the widgets based on settings in Menu->File->Preferences

`obj.updateWidgets();` can be used to update the GUI with some default settings

It is possible to specify various listeners that are triggered depending on events in the main MIB window:
`obj.listener{1} = addlistener(obj.mibModel, 'updateGuiWidgets', @(src,evnt) obj.ViewListner_Callback2(obj, src, evnt));`

Code of the constructor

    function obj = mibPluginController(mibModel)
        obj.mibModel = mibModel;    % assign model
        guiName = 'mibPluginGUI';
        obj.View = mibChildView(obj, guiName); % initialize the view

        % check for the virtual stacking mode and close the controller
        if isprop(obj.mibModel.I{obj.mibModel.Id}, 'Virtual') && obj.mibModel.I{obj.mibModel.Id}.Virtual.virtual == 1
            warndlg(sprintf('!!! Warning !!!\n\nThis plugin is not compatible with the virtual stacking mode!\nPlease switch to the memory-resident mode and try again'), ...
                'Not implemented');
            obj.closeWindow();
            return;
           end

        % resize all elements of the GUI
        mibRescaleWidgets(obj.View.gui);

        obj.updateWidgets();

        % obj.View.gui.WindowStyle = 'modal';     % make window modal

        % add listner to obj.mibModel and call controller function as a callback
        % option 1: recommended, detects event triggered by mibController.updateGuiWidgets
        obj.listener{1} = addlistener(obj.mibModel, 'updateGuiWidgets', @(src,evnt) obj.ViewListner_Callback2(obj, src, evnt));    % listen changes in MIB

        % option 2: in some situations
        % obj.listener{1} = addlistener(obj.mibModel, 'Id', 'PostSet', @(src,evnt) obj.ViewListner_Callback(obj, src, evnt));     % for static
        % obj.listener{2} = addlistener(obj.mibModel, 'newDatasetSwitch', 'PostSet', @(src,evnt) obj.ViewListner_Callback(obj, src, evnt));     % for static
    end

### close window function

It is possible to specify some custom steps that are done when user is closing the plugin.
By default, the plugin notifies the main MIB controller that it gets closed: `notify(obj, 'closeEvent');`

Code of closeWindow function

    function closeWindow(obj)
        % closing mibPluginController window
        if isvalid(obj.View.gui)
            delete(obj.View.gui);   % delete childController window
        end

        % delete listeners, otherwise they stay after deleting of the
        % controller
        for i=1:numel(obj.listener)
            delete(obj.listener{i});
        end

        notify(obj, 'closeEvent');      % notify mibController that this child window is closed
    end

### updateWidgets function

This function is triggered when `updateGuiWidgets` event comes from mibModel. Typically, it is used to update the dataset specific settings within the plugin.

Code of updateWidgets function

    function updateWidgets(obj)
        % function updateWidgets(obj)
        % update widgets of this window

        fprintf('childController:updateWidgets: %g\n', toc);
    end

### calculateBtn_Callback

`calculateBtn_Callback` is the main calculation function of the plugin. It is linked to the `obj.View.handles.calculateBtn`, which is the Calculate button that starts computation.

Code of calculateBtn_Callback function

    function calculateBtn_Callback(obj)
        % start main calculation of the plugin

        % get the user provided threshold value from the GUI
        value = obj.View.handles.thresholdValue.String;
        % convert it from string to double
        threhsoldValue = str2double(value);
        wb = waitbar(0, 'Please wait'); % add a waitbar to follow the progress

        [height, width, ~, depth] = obj.mibModel.I{obj.mibModel.Id}.getDatasetDimensions('image');  % get dataset dimensions
        img = cell2mat(obj.mibModel.getData2D('image'));    % get the currently displayed image
        waitbar(0.5, wb);   % update the waitbar

        mask = zeros([height, width, depth], 'uint8'); % allocate space for the mask layer
        mask(img<threhsoldValue) = 1; % threshold image
        waitbar(0.95, wb);     % update the waitbar

        obj.mibModel.setData2D('mask', mask); % send the mask layer back to MIB
        delete(wb);         % delete the waitbar

        % notify mibModel to switch on the Show mask checkbox,
        % which also redraws the image
        % alternatively,
        % notify(obj.mibModel, 'plotImage');
        % can be used to force image redraw
        notify(obj.mibModel, 'showMask');
    end

### mibPluginGUI

`mibPluginGUI.m` contains callbacks for widgets in `mibPluginGUI.fig` those can be modified by opening the file using guide.

Type `guide mibPluginGUI.fig` in the main MATLAB workspace to start guide and modify the plugin layout and callbacks.

## Adapting the function to a new plugin

Perform the following operations to use this plugin as a template for a new plugin.

- Create a folder for your plugins under `MIB/Plugins/` for example `MyPlugins` so that the full path is
  `MIB/Plugins/MyPlugins`
- Create a subfolder under `MIB/Plugins/MyPlugins` and name it with the name of your new plugin (e.g.`MIB/Plugins/MyPlugins/mySecondPlugin`)
- Copy `mibPluginController.m`, `mibPluginGUI.m` and `mibPluginGUI.fig` to `MIB/Plugins/MyPlugins/mySecondPlugin`
- Rename `mibPluginController.m` to `mySecondPluginController.m`
- Open `mySecondPluginController.m` in MATLAB
- Do Find and Replace to search for `mibPlugin` and replace with `mySecondPlugin`, `Ctrl`+`F` key shortcut.
- Edit `calculateBtn_Callback`to implement your desired functionality
- Save the plugin
- Type `guide mibPluginGUI.fig` to open it in MATLAB guide.

Warning

You may need to change the current MATLAB folder to the plugin directory otherwise it may open the previous version of the plugin in `Tutorials\mibPlugin\mySecondPlugin`

- Resave the fig-file under the new name: `mySecondPluginGUI.fig`
- Restart MIB to refresh the list of plugins.
- Run your plugin from `Menu → Plugins → MyPlugins → mySecondPlugin`.

Note

You can remove the copied files `mibPluginGUI.m` and `mibPluginGUI.fig` from the plugin directory

## Credits

Author: Ilya Belevich, University of Helsinki (ilya.belevich@helsinki.fi)

Part of: Microscopy Image Browser

Back to MIB | User Interface | Plugins | Tutorials