ScanImage was developed using theĀ Model-View-Controller design pattern. As a demonstration of the scripting-flexibility that ScanImage provides us, this article will show an example of how to set up a simple GUI for a specific ScanImage-based task. This article uses the ScanImage API, which is described in more detail here.
Suppose we were to run a hypothetical experiment/procedure that only requires the user to change the name of a file and start a frame acquisition based on clicking. For this purpose the following \GUIDE GUI would be more than sufficient for our needs:

We shall now see how we can tie the ScanImage core to perform the desired task through this GUI. First of all, let's link a new controller-view to ScanImage. To do this, we can inspect the scanimage startup script. In the Matlab command window, type:
>> edit scanimage
Find the following section in the startup script:
try
hSI = scanimage.SI(mdf);
hSI.initialize();
% NOTE: This is the original scanimage controller
%hSICtl = scanimage.SIController(hSI);
%hSICtl.initialize(usr);
% This is the new basic controller:
hSICtl = scanimage.SILiteController(hSI);
assignin('base','hSI',hSI);
assignin('base','hSICtl',hSI.hController{1});
catch ME
...
Now we can set up the new controller
classdef SILiteController < handle
% CYCLEMANAGERCONTROLLER Controller class for cycle mode
properties
model
view
end
% CONSTRUCTOR
methods
function obj = SILiteController(model)
obj.model = model;
obj.view = scanimage.SILiteView(obj);
end
end
% USER METHODS
methods
function setLogFileName(obj,val)
obj.model.hResScan.logFileStem = val;
end
function setEnableLoggingMode(obj,val)
obj.model.hChannels.loggingEnable = logical(val);
end
function startGrabAcquisition(obj)
obj.model.startGrab();
end
function abortAcquisition(obj)
obj.model.abort();
end
end
end
Next comes the View. Here will choose explicit names for each element in the GUI.
| GUI Tags | Description |
|---|---|
cbEnableLogging | Check-box for toggling logging-enabled state |
etLogFileName | Edit-box for setting the logging filename |
pbGrab | Push-button for initiating a GRAB acquisition (not set in the view) |
pbAbort | Push-button for stopping an acqusition (not set in the view) |
classdef SILiteView < handle
% CYCLEMANAGER Model class for cycle mode
properties
gui
model
controller
end
methods
function obj = SILiteView(controller)
obj.controller = controller;
obj.model = controller.model;
obj.gui = SILiteGUI('controller',obj.controller);
% Initialization call goes here
obj.initializeGUIFromModel(obj.gui);
addlistener(obj.model.hResScan,'logFileStem',...
'PostSet',@(src,evnt)scanimage.SILiteView.handlePropEvents(obj,src,evnt));
addlistener(obj.model.hChannels,'loggingEnable',...
'PostSet',@(src,evnt)scanimage.SILiteView.handlePropEvents(obj,src,evnt));
end
function delete(obj)
disp('View destructor');
if ishandle(obj.gui)
close(obj.gui);
end
end
function initializeGUIFromModel(obj, hGUI)
handles = guidata(hGUI);
% Check the model's initial state
set(handles.cbEnableLogging, 'Value', obj.model.hChannels.loggingEnable);
set(handles.etLogFileName, 'String', obj.model.hResScan.logFileStem);
end
end
methods (Static)
function handlePropEvents(obj,src,evnt)
evntobj = evnt.AffectedObject;
handles = guidata(obj.gui);
switch src.Name
case 'logFileName'
set(handles.etLogFileName, 'Value', evntobj.logFileStem);
case 'loggingEnable'
set(handles.cbEnableLogging, 'Value', evntobj.loggingEnable);
end
end
end
end
function varargout = SILiteGUI(varargin)
...
% --- Executes just before SILiteGUI is made visible.
function SILiteGUI_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to SILiteGUI (see VARARGIN)
% Choose default command line output for SILiteGUI
handles.output = hObject;
% get handle to the controller
for i = 1:2:length(varargin)
switch varargin{i}
case 'controller'
handles.controller = varargin{i+1};
otherwise
error('unknown input')
end
end
% Update handles structure
guidata(hObject, handles);
...
After constructing
function varargout = SILiteGUI(varargin) ... function pbGrab_Callback(hObject, eventdata, handles) % hObject handle to pbGrab (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.controller.startGrabAcquisition(); % --- Executes on button press in pbAbort. function pbAbort_Callback(hObject, eventdata, handles) % hObject handle to pbAbort (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.controller.abortAcquisition(); % --- Executes on button press in cbEnableLogging. function cbEnableLogging_Callback(hObject, eventdata, handles) % hObject handle to cbEnableLogging (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of cbEnableLogging handles.controller.setEnableLoggingMode(get(hObject, 'Value')); function etLogFileName_Callback(hObject, eventdata, handles) % hObject handle to etLogFileName (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'String') returns contents of etLogFileName as text % str2double(get(hObject,'String')) returns contents of etLogFileName as a double handles.controller.setLogFileName(get(hObject, 'String')); ...
This concludes our simple implementation of the MVC approach for creating simple ScanImage user interfaces. This should be considered a starting point, given that error-checking and proper destructors should still be added to this implementation.