www.gusucode.com > mbctools 工具箱 matlab 源码程序 > mbctools/+xregdatagui/SweepsetList.m
classdef SweepsetList < mbcgui.widget.BasicContainer %xregdatagui.sweepsetlist class % xregdatagui.sweepsetlist extends mbcgui.widget.BasicContainer. % % xregdatagui.sweepsetlist properties: % Parent - Property is of type 'MATLAB array' % Position - Property is of type 'rect' % Enable - Property is of type 'on/off' % Visible - Property is of type 'on/off' % Userdata - Property is of type 'MATLAB array' % Tag - Property is of type 'string' % Sweepset - Property is of type 'MATLAB array' % ColumnFcns - Property is of type 'MATLAB array' (read only) % ColumnHeaders - Property is of type 'string vector' (read only) % Editable - Property is of type 'bool' % ShowUnits - Property is of type 'bool' % DisplayFormat - Property is of type 'string' % UIContextMenu - Property is of type 'MATLAB array' % MultiSelect - Property is of type 'bool' % SelectedRows - Property is of type 'MATLAB array' % Listview - Property is of type 'MATLAB array' (read only) % % xregdatagui.sweepsetlist methods: % editVariable - Edit a variable definition in the sweepset % getStandardColumnFunctions - Provide standard set of column functions. % pDisplaySweepset - Display the given sweepset % pInitialiseListview - Listview initialiser % pPostSetEditable - A short description of the function % pPostSetMultiSelect - A short description of the function % pSetSelectedRows - A short description of the function % pSetSweepset - Set function to ensure that this property contains a sweepsepset % pSweepsetChanged - update routine to call if the sweepset changes % setColumnHeaders - set the list column headers % Copyright 2015-2015 The MathWorks, Inc. and Ford Global Technologies, Inc. properties (SetObservable) %SWEEPSET Property is of type 'MATLAB array' Sweepset = sweepset; %EDITABLE Property is of type 'bool' Editable = false; %SHOWUNITS Property is of type 'bool' ShowUnits = true; %DISPLAYFORMAT Property is of type 'string' DisplayFormat = '%.3g'; %MULTISELECT Property is of type 'bool' MultiSelect = false; end properties(Dependent) %UICONTEXTMENU Property is of type 'MATLAB array' UIContextMenu = []; %SELECTEDROWS Property is of type 'MATLAB array' SelectedRows = []; end properties (Access=protected, AbortSet) %COMLISTENERS Property is of type 'handle vector' COMListeners = []; end properties (SetAccess=protected, AbortSet, SetObservable) %COLUMNFCNS Property is of type 'MATLAB array' (read only) ColumnFcns = []; %COLUMNHEADERS Property is of type 'string vector' (read only) ColumnHeaders %LISTVIEW Property is of type 'MATLAB array' (read only) Listview = []; end events ButtonDown DoubleClick KeyUp SweepsetChanged SelectionChanged end % events methods % constructor block function [obj] = SweepsetList(varargin) %SWEEPSETLIST Construtor for the sweepsetlist object % % OBJ = SWEEPSETLIST % OBJ = SWEEPSETLIST(OBJ) % OBJ = SWEEPSETLIST('Property', Value) % Call the inherited constructor obj@mbcgui.widget.BasicContainer(varargin{ : }); % converted super class constructor call % Create the listview obj.Listview = mbcwidgets.List('Parent',obj.Parent,... 'Enable', obj.Enable,... 'BorderType','beveledin'); obj.ContentHandle = obj.Listview; % Set up property listeners obj.storeListeners([event.proplistener(obj,obj.findprop('MultiSelect'),'PostSet',@obj.pPostSetMultiSelect) event.proplistener(obj,obj.findprop('Editable'),'PostSet',@obj.pPostSetEditable)]); % Force an update of the listview obj.pInitialiseListview; end % sweepsetlist end % constructor block methods function set.Sweepset(obj,value) obj.Sweepset = obj.pSetSweepset(value); end function value = get.SelectedRows(obj) value = obj.Listview.getSelectedRows; end function set.SelectedRows(obj,value) obj.Listview.selectRows(value); end function set.UIContextMenu(obj,value) set(obj.Listview,'UIContextmenu',value); end end % set and get functions methods (Static) function [ss,OK] = dialog(ss,Owner) %dialog edit variables in dialog % [ss,OK]= xregdatagui.SweepsetList.dialog(ss,Owner); if nargin<2 Owner = []; end dlg = mbcgui.container.Dialog('Name','Data Variable Editor',... 'Size',[550 450],... 'Owner',Owner,... 'Buttons','OK_CANCEL'); localData.newSweepset = ss; localData.mergeSweepset = []; localData.filename = get(ss,'filename'); dlg.Content = xregdatagui.SweepsetList.createLayout(dlg.Figure,localData); closeAction = dlg.showDialog(); if strcmp(closeAction,'OK') OK = true; % get updated sweepset from layout userdata layoutUD = get(dlg.Content, 'UserData'); ss = layoutUD.lvVariables.Sweepset; else OK = false; end delete(dlg); end function layout = createLayout(Parent,localData) %createLayout create a layout for editing variables % layout = xregdatagui.SweepsetList.createLayout(Parent,ss); if isa(Parent, 'xregcontainer') % allow reuse of layout within xregwizard layout = Parent; layoutUD = get(layout, 'UserData'); else % create a new layout txRecords = uicontrol('Parent', Parent,... 'Style', 'text',... 'String', '',... 'Visible', 'off',... 'HorizontalAlignment', 'left'); txFilename = uicontrol('Parent', Parent,... 'Style', 'list',... 'String', '',... 'Visible', 'off',... 'HorizontalAlignment', 'left'); btEdit = uicontrol('Parent',Parent,... 'String', 'Edit...',... 'TooltipString', 'Edit variable name and units', ... 'Enable', 'off',... 'Tag','btEdit',... 'Callback', @iEditClicked); btRemove = uicontrol('Parent',Parent,... 'String', 'Remove',... 'TooltipString', 'Remove selected variable(s)', ... 'Enable', 'off',... 'Tag','btRemove',... 'Callback', @(h,evt) iRemoveClicked()); lvVariables = xregdatagui.SweepsetList('Parent', Parent,... 'MultiSelect',true,... 'Editable', true); S = lvVariables.getStandardColumnFunctions; lvVariables.setColumnHeaders({S.Min S.Max S.Mean S.Std}, {'Min', 'Max', 'Mean', 'Std. Dev'}, [65 65 65 65]); layout = xreggridbaglayout(Parent,... 'dimension', [3 4],... 'elements', {txRecords btEdit, lvVariables, ... [] btRemove,[],... [] [] [],... txFilename [] []},... 'mergeblock', {[1 1] [1 3]},... 'mergeblock', {[3 3] [1 4]},... 'rowsizes', [40 25 -1],... 'colsizes', [60 60 60 -1],... 'border', [10 0 10 10],... 'gapy', 10,... 'gapx', 5); layoutUD.Listeners = [ event.listener(lvVariables, 'KeyUp', @iListviewDelete);... event.listener(lvVariables, 'SelectionChanged', @iListviewSelectionChanged)]; layoutUD.txRecords = txRecords; layoutUD.txFilename = txFilename; layoutUD.lvVariables = lvVariables; layoutUD.btEdit = btEdit; layoutUD.btRemove = btRemove; layoutUD.mergeAvail = false; set(layout,'UserData',layoutUD); end if nargin > 1 % initialise user data from localData input layoutUD.mergeSweepset = localData.mergeSweepset; layoutUD.filename = localData.filename; layoutUD.mergeAvail = ~isempty(layoutUD.mergeSweepset); layoutUD.lvVariables.Sweepset = localData.newSweepset; set(layout,'UserData',layoutUD); end % initialise layout initialise() function initialise() %initialise layout controls and info ssData = layoutUD.lvVariables.Sweepset; % Set text and variables information set(layoutUD.txRecords, 'String', ['Imported ' num2str(size(ssData,1)) ' records and ' num2str(size(ssData,2)) ... ' variables from files :']); set(layoutUD.txFilename, 'String', get(ssData,'filename')); set(layoutUD.btRemove,'Enable',mbconoff(~isempty(layoutUD.lvVariables.SelectedRows))) set(layoutUD.btEdit,'Enable',mbconoff(isscalar(layoutUD.lvVariables.SelectedRows))) end function iEditClicked(~,~) %iEditClicked click on edit button layoutUD.lvVariables.editVariable; end function iRemoveClicked(SelectedRows) %iRemoveClicked click on remove button if nargin==0 SelectedRows = layoutUD.lvVariables.SelectedRows; end % Which rows are being kept rowsToKeep = setdiff(1:size(layoutUD.lvVariables.Sweepset, 2), SelectedRows); % Update the sweepset - NOTE it's important to make the sweepset empty if % there are no variables since it's the number of records that define an % empty sweepset. if isempty(rowsToKeep) ssData = sweepset; else ssData = layoutUD.lvVariables.Sweepset(:, rowsToKeep); end layoutUD.lvVariables.Sweepset = ssData; initialise(); end function iListviewDelete(~, evt) %iListviewKeyUp delete rows on key event % First check no modifiers were pressed if evt.data.Modifiers == 0 % Which key was pressed switch evt.data.KeyCode case mbcgui.util.KeyCode.DELETE % DELETE_KEY iRemoveClicked(evt.data.Rows); end end end function iListviewSelectionChanged(lvVariables,evt) %iListviewSelectionChanged enable edit and remove buttons based %on list selection state if nargin==2 SelectedRows = evt.data.SelectedRows; else SelectedRows = lvVariables.SelectedRows; end % enable remove if some rows are selected set(layoutUD.btRemove,'Enable',mbconoff(~isempty(SelectedRows))) % enable edit if only one row is selected set(layoutUD.btEdit,'Enable',mbconoff(isscalar(SelectedRows))) end end end methods % public methods %---------------------------------------- function editVariable(obj, index) %EDITVARIABLE Edit a variable definition in the sweepset % % EDITVARIABLE(OBJ, INDEX) % Get the current names and units from the sweepset if nargin<2 index = obj.SelectedRows; end names = get(obj.Sweepset, 'Name'); units = get(obj.Sweepset, 'Units'); % Convert units to cell array for i = 1:length(units) units{i} = char(units{i}); end % Create a dialog to display the name and unit [OK, newName, newUnit] = i_editNameAndUnit(obj.Parent, names{index}, units{index}); % Did the user press OK if OK names{index} = newName; units{index} = newUnit; % And set the names and units obj.Sweepset = set(obj.Sweepset, 'Name', names, 'Units', units); % Tell the world the sweepset has changed notify(obj, 'SweepsetChanged'); end end % editVariable %---------------------------------------- function pDisplaySweepset(obj, ss) %PDISPLAYSWEEPSET Display the given sweepset % % PDISPLAYSWEEPSET(OBJ, SS) % % Implicit assumption is that ss is different from the current ss and all % functions need to be updated. Also that there are the correct number of % rows and columns in the listview for displaying the information. data = double(ss); Names = get(ss, 'Name'); Data= Names(:); if obj.ShowUnits Units = get(ss, 'Units'); Data = [Data Units(:)]; end % Initialise to NaN columns = NaN(size(data, 2), length(obj.ColumnFcns)); % Compute the column data if ~isempty(data) for i = 1:length(obj.ColumnFcns) fcn = obj.ColumnFcns{i}; try %#ok<TRYNC> if isa(fcn,'function_handle') columns(:, i) = feval(fcn, data)'; elseif iscell(fcn) columns(:, i) = feval(fcn{1}, data, fcn{2:end})'; end end end end Data = [Data num2cell(columns)]; selectedRows = obj.Listview.SelectedRows; obj.Listview.setData(Data); if ~isempty(selectedRows) && max(selectedRows)<=size(Data,1) % select existing rows obj.Listview.SelectedRows = selectedRows; else obj.Listview.SelectedRows = 1; end end % pDisplaySweepset %---------------------------------------- function pInitialiseListview(obj) %PINITIALISELISTVIEW Listview initialiser % % PINITIALISELISTVIEW(OBJ) % Make the listview a detail view % Set a whole bunch of properties if obj.MultiSelect set(obj.Listview,'SelectionMode','MultiRow') else set(obj.Listview,'SelectionMode','SingleRow') end set(obj.Listview,'Editable', obj.Editable); if obj.Editable obj.Listview.Peer.setEditableColumns(0:1); end set(obj.Listview,... 'SelectionChangedCallBack',{@i_click,obj},... 'ActionPerformedCallback',{@i_doubleClick,obj},... 'ValueChangedCallback',{@i_afterLabelEdit,obj},... 'KeyTypedCallback',{@i_keyUp,obj}); end % pInitialiseListview %---------------------------------------- function pPostSetEditable(obj, ~,~) %PPOSTSETEDITABLE A short description of the function % % OUT = PPOSTSETEDITABLE(IN) obj.Listview.Editable = obj.Editable; if obj.Editable obj.Listview.Peer.setEditableColumns(0:1); else obj.Listview.Peer.setEditableColumns([]); end end % pPostSetEditable %---------------------------------------- function pPostSetMultiSelect(obj, ~,~) %PPOSTSETMULTISELECT A short description of the function % PPOSTSETMULTISELECT(OBJ, EVENT) if obj.MultiSelect set(obj.Listview,'SelectionMode','MultiRow') else set(obj.Listview,'SelectionMode','SingleRow') end end % pPostSetMultiSelect %---------------------------------------- function [ss] = pSetSweepset(obj, ss) %PSETSWEEPSET Set function to ensure that this property contains a sweepsepset % [SS] = PSETSWEEPSET(OBJ, SS) if ~isa(ss, 'sweepset') error(message('mbc:xregdatagui:sweepsetlist:InvalidPropertyValue')); end % Call the update routine with the old and new sweepsets obj.pSweepsetChanged(obj.Sweepset, ss); end % pSetSweepset %---------------------------------------- function pSweepsetChanged(obj, oldSS, newSS) %PSWEEPSETCHANGED update routine to call if the sweepset changes % PSWEEPSETCHANGED(OBJ, OLDSS, NEWSS) % No point in doing this if we don't yet have a listview if isempty(obj.Listview) || ~ishandle(obj.Listview) return end % Get a handle to the listItems collection % Have the variable names changed oldNames = get(oldSS, 'Name'); newNames = get(newSS, 'Name'); oldUnits = get(oldSS, 'Units'); newUnits = get(newSS, 'Units'); NAMES_CHANGED = ~isequal(oldNames, newNames); UNITS_CHANGED = ~isequal(oldUnits, newUnits); % Has the data changed (treating NaN as equal) if NAMES_CHANGED || UNITS_CHANGED || ~isequaln(double(oldSS), double(newSS)) obj.pDisplaySweepset(newSS); end end % pSweepsetChanged %---------------------------------------- function setColumnHeaders(obj, callbacks, names, widths) %SETCOLUMNHEADERS set the list column headers % SETCOLUMNHEADERS(OBJ, CALLBACKS, NAMES) % Make sure that the callbacks and names are cell arrays if ~iscell(callbacks) callbacks = {callbacks}; end if ~iscell(names) names = {names}; end % Have we got widths - default to width 80 if nargin < 4 widths = 80*ones(size(names)); end % Set the internal bits obj.ColumnFcns = callbacks(:); obj.ColumnHeaders = names(:); ColHeaders = {'Variable Name'}; ColWidths = 150; if obj.ShowUnits ColHeaders = [ColHeaders ; {'Units'}]; ColWidths = [ColWidths 80]; end ColHeaders = [ColHeaders ; obj.ColumnHeaders]; ColWidths = [ColWidths widths]; obj.Listview.Peer.setColumnData(ColHeaders); obj.Listview.Peer.setColumnWidths(ColWidths); if size(obj.Sweepset, 1) > 0 obj.pDisplaySweepset(obj.Sweepset); end end % setColumnHeaders end % public methods methods (Static) % static methods %---------------------------------------- function S = getStandardColumnFunctions %GETSTANDARDCOLUMNFUNCTIONS Provide standard set of column functions. % % S = GETSTANDARDCOLUMNFUNCTIONS creates and returns a structure that % contains function handles suitable for use as column data generators. % These functions are generally preferred over simple built-in maths % functions because they are designed to balance memory usage and % computational speed. % % The structure will contain the following fields: Mean, Std, Min, Max S = struct('Mean', @(d) nanmean(d,1), ... 'Std', @(d) nanstd(d,0,1), ... 'Min', @(d) nanmin(d,[],1), ... 'Max', @(d) nanmax(d,[],1)); end % getStandardColumnFunctions end % static methods end % classdef function [OK, name, unit] = i_editNameAndUnit(parent, name, unit) %i_editNameAndUnit edit variable dialog SC = xregGui.SystemColorsDbl; % Create a figure in which to draw the dialog. dlg = mbcgui.container.Dialog('Name', 'Edit Data Variable',... 'Visible','off',... 'Owner', ancestor(parent,'figure'),... 'Size',[250 120],... 'Buttons','OK_CANCEL',... 'DefaultAction','CANCEL'); f = dlg.Figure; % Center on the parent figure xregcenterfigure(f, [250 120], ancestor(parent,'figure')); nameEdit = uicontrol('Parent', f,... 'Style', 'edit',... 'HorizontalAlignment', 'left', ... 'BackgroundColor', SC.WINDOW_BG,... 'String', name); nameLabel = xregGui.labelcontrol('parent', f,... 'LabelSizeMode', 'Absolute',... 'ControlSizeMode', 'Relative',... 'LabelAlignment', 'left',... 'ControlSize', 1,... 'LabelSize', 45,... 'Control', nameEdit,... 'String', 'Name:'); unitEdit = uicontrol('Parent', f,... 'Style', 'edit',... 'HorizontalAlignment', 'left', ... 'BackgroundColor', SC.WINDOW_BG,... 'String', unit); unitLabel = xregGui.labelcontrol('Parent', f,... 'LabelSizeMode', 'Absolute',... 'ControlSizeMode', 'Relative',... 'LabelAlignment', 'left',... 'ControlSize', 1,... 'LabelSize', 45,... 'Control', unitEdit,... 'String', 'Units:'); f.LayoutManager = xreggridbaglayout(f, ... 'dimension', [2 1],... 'elements', {nameLabel unitLabel},... 'gapy', 5,... 'rowsizes', [20 20],... 'border', [7 7 7 7]); closeAction = dlg.showDialog(); OK = strcmpi(closeAction,'OK'); name = get(nameEdit, 'String'); unit = get(unitEdit, 'String'); delete(dlg); end % i_editNameAndUnit %------------------------------------------------------------------------ function i_click(~, evt,obj) % listview selection action evt = xregEventData(evt.data); notify(obj, 'ButtonDown',evt); notify(obj,'SelectionChanged',evt) end % i_click %------------------------------------------------------------------------ function i_doubleClick(~, evt,obj) % double click listview action notify(obj, 'DoubleClick',xregEventData(evt.data)); % Has the use requested the built-in editable behaviour? selectedRows = evt.data.SelectedRows; if obj.Editable && ~isempty(selectedRows) obj.editVariable(selectedRows(1)); end end % i_doubleClick %------------------------------------------------------------------------ function i_keyUp(~, evt,obj) % convert event data to MCOS event.eventdata evt = xregEventData(evt.data); % Send on the KeyUp notify(obj, 'KeyUp', evt); end % i_keyUp %------------------------------------------------------------------------ function i_afterLabelEdit(~, evt,obj) %i_afterLabelEdit edit listview index = evt.data.Rows; % Only add a sensible name if isscalar(index) && ~isempty(evt.data.NewValue) switch evt.data.Columns case 1 % Get the current names from the sweepset names = get(obj.Sweepset, 'Name'); % Modify the correct name names{index} = evt.data.NewValue; % And set the names obj.Sweepset = set(obj.Sweepset, 'Name', names); case 2 % Get the current units from the sweepset units = get(obj.Sweepset, 'UNITS'); % Modify the correct units units{index} = evt.data.NewValue; % And set the units obj.Sweepset = set(obj.Sweepset, 'UNITS', units); otherwise error('Invalid column'); end % Tell the world the sweepset has changed notify(obj, 'SweepsetChanged'); end end % i_afterLabelEdit