如何在Matlab GUI中实现MVC设计思想

3

我是一名学生,正在开发一个使用MVC设计在Matlab中分析数据的可视化工具项目。但我遇到的问题是我对编程和Matlab都很陌生。虽然我已经完成了代码,但我担心它们不符合MVC设计模式,所以我需要进行更改。

非常感谢您提供尽可能多的建议,以帮助我寻找有用的材料。我无法找到任何关于Matlab中MVC的资料或者示例代码,可以帮助我了解如何完成我的项目。目前,我的数据是一个结构体,包含.Name和.Data字段。函数/方法datcorrCoef和datCorrSum是我创建的,它们接受我的数据对象作为参数。


function dataAnalysisGUI(data)

fdataAnalysisGUI = figure('Name','Data Analysis ',...
    'tag','dataAnalysisGUI',...
    'menu','none',...
    'units','normalized',...
    'NumberTitle', 'off')



%%% intialise the gui with data set to work with
vtDaUD.opD = data;



Rsq = datcorrCoef(vtDaUD.opD);
opit = datWrappa(Rsq);
vtDaUD.wd = opit;
vtDaUD.feel = datCorrSum(data);
%%%------------------- menus ------------------------------------------%%%
smh = uimenu('Label', 'Sort', 'Tag', 'daSortMenu');
cmh = uimenu(smh, 'Label', 'Sum of CorrCoeff ',...
    'Tag', 'correlation');
    uimenu(cmh, 'Label', 'Increasing ',...
    'Tag', 'cIncreasing',...
    'callback','vtDaCallbacks(''cIncreasing_callback'')');
    uimenu(cmh, 'Label', 'Decreasing ',...
    'Tag', 'cDecreasing',...
    'callback','vtDaCallbacks(''cDecreasing_callback'')');
mmh = uimenu(smh, 'Label', 'Max Lag ',...
    'Tag', 'maxLag');
    uimenu(mmh, 'Label', 'Increasing ',...
    'Tag', 'mIncreasing',...
    'callback','vtDaCallbacks(''mIncreasing_callback'')');
    uimenu(mmh, 'Label', 'Decreasing ',...
    'Tag', 'mDecreasing',...
    'callback','vtDaCallbacks(''mDecreasing_callback'')');



dmh = uimenu('Label', 'Display', 'Tag', 'daDisplayMenu');
            uimenu(dmh, 'Label', 'Scatter Plots ',...
                  'Tag', 'dScatter',...
                  'Callback','vtDaCallbacks(''dScatter_callback'')');
              uimenu(dmh, 'Label', 'Cross Correlation ',...
                  'Tag', 'dCrosscorr',...
                  'callback','vtDaCallbacks(''dCrosscorr_callback'')');
              uimenu(dmh, 'Label', 'Time Series ',...
                  'Tag', 'dTimeseries',...
                  'callback','vtDaCallbacks(''dTimeseries_callback'')');


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%------------------------ panels ------------------------------------%%%
 vtDaPanel1 = uipanel(fdataAnalysisGUI,...
       'Units','normalized',...
       'Position', [.025 .035 .84 .95],...
       'FontSize',10,...
       'tag','vtDaPanel1',...
       'backgroundcolor',[0.8, 0.8,0.8],...
       'title', 'Table of Cross Correlations between Data');
    vtDaPanel2 = uipanel(fdataAnalysisGUI,...
       'Units','normalized',...
       'Position', [.87 .566 .12 .396],...
       'tag','vtDaPanel2',...
       'backgroundcolor',[0.8, 0.8,0.8],...
       'title', 'Analysis');

   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   %%%------------------------- objects -------------------------------%%%
        uitable('parent', vtDaPanel1,...
            'tag','vtDaTable',...
            'RearrangeableColumn', 'on',...
            'clipping','off',...
            'Units','normalized',...
            'Position',[.01 .2 .98 .8],...
            'data',opit.Data,...
            'rowname',opit.Name,...
            'columnname',opit.Name,...
            'CellSelectionCallback',{@daTable_callback,vtDaUD.opD});

        uitable('parent', vtDaPanel1,...
            'tag','vtDaTable2',...
            'RearrangeableColumn', 'on',...
            'Units','normalized',...
            'Position',[.01 .01 .98 .15],...
            'data',vtDaUD.feel.Data,...
            'rowname','Sum of Corr. Coeff',...
            'columnname',vtDaUD.feel.Name,...
            'TooltipString','select column header to drill down',...
            'CellSelectionCallback',{@daTable2_callback,vtDaUD.opD});


        uicontrol(vtDaPanel2, 'Style', 'popupmenu',...
            'tag','taskpopMenu',...
            'Units','normalized',...
            'Position', [.10 .75 .8 .1],...
            'String', {'Correlation Coeff';'Max lags'},...
            'Callback', 'vtDaCallbacks(''taskpopMenu_callback'')');

        uicontrol(vtDaPanel2, 'Style', 'text',...
            'tag','staticTxt2',...
            'Units','normalized',...
            'Position', [.10 .86 .8 .05],...
            'String', {'Task'});

        uicontrol(vtDaPanel2, 'Style', 'text',...
            'tag','staticTxt3',...
            'Units','normalized',...
            'Position', [.10 .61 .8 .05],...
            'String', {'Mini Display'});

        uicontrol(vtDaPanel2, 'Style', 'pushbutton',...
            'tag','pushTimeseries',...
            'Units','normalized',...
            'Position', [.10 .5 .8 .1],...%[450 350 100 50]
            'String', {'TimeSeries'},...
            'Callback', 'vtDaCallbacks(''pushTimeseries_callback'')');

        uicontrol(vtDaPanel2, 'Style', 'pushbutton',...
            'tag','pushScatter',...
            'Units','normalized',...
            'Position', [.10 .35 .8 .1],...
            'String', {'Scatter'},...
            'Callback', 'vtDaCallbacks(''pushScatter_callback'')');

        uicontrol(vtDaPanel2, 'Style', 'pushbutton',...
            'tag','pushMaxlag',...
            'Units','normalized',...
            'Position', [.10 .2 .8 .1],...
            'String', {'Max Lag'},...
            'Callback', 'vtDaCallbacks(''pushMaxlag_callback'')');


name = genvarname(['daGUI' data.Name{2}]);%name = datname('daGUI',lenght(data.Name));
vtDaUD.varName = name;
eval([name '= data.Data']);
assignin('base',name,data.Data);


set(fdataAnalysisGUI,'UserData',vtDaUD)

我已经按照以下方式完成了回调/控制;
function vtDaCallbacks(action)
handles = guihandles(gcf);
vtDaUD = get(handles.dataAnalysisGUI,'UserData');
%tabdata=get(handles.vtDaTable,'data');
tab2Data.Data = get(handles.vtDaTable2,'data');
tab2Data.Name = get(handles.vtDaTable2,'columnname');


switch action
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%%-----------------------Data AnalysisGUI menu callbacks-----------%%%
    case 'cIncreasing_callback'
        [newTabData,index] = sortaColumn(tab2Data,'ascend',1);
        vtDaUD.wd = dataselect(vtDaUD.opD,index);
        set(handles.vtDaTable2, 'data', newTabData.Data)
        set(handles.vtDaTable2, 'columnname', newTabData.Name)
        set(handles.vtDaTable2,'CellSelectionCallback',{@daTable2_callback,vtDaUD.wd});


    case 'cDecreasing_callback'
        [newTabData,index] = sortaColumn(tab2Data,'descend',1);
        vtDaUD.wd = dataselect(vtDaUD.opD,index);
        %[vtDaUD.wd,newTabData,newcolumnname] = sortta2(vtDaUD.opD,'descend',tab2Data,1);
        set(handles.vtDaTable2, 'data', newTabData.Data)
        set(handles.vtDaTable2, 'columnname', newTabData.Name)
        set(handles.vtDaTable2,'CellSelectionCallback',{@daTable2_callback,vtDaUD.wd});

    case 'dScatter_callback'
        dataDispGUI('dScatta','calnumpage2',vtDaUD.opD, 'Scatter Plots')

    case 'dTimeseries_callback'
        dataDispGUI('dTimeSeries2','calnumpage2',vtDaUD.opD, 'Time Series Plots')

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%%-------------------Data AnalysisGUI uiobject callbacks-----------%%%

    case 'dataTable_callback'
        [indices,data1,data2] = daTable_callback(vtDa.opD);
        vtDaUD.data1=data1;
        vtDaUD.data2=data2;
        dsingTseries(y1,y2)

    case 'taskpopMenu_callback'
        val = get (handles.taskpopMenu,'value');
        switch val
            case 1
                Rsq = datcorrCoef(vtDaUD.opD);
                tab1data = datWrappa(Rsq);%vtDaUD.wd
                set(handles.vtDaPanel1,...
                    'title', 'Table of Cross Correlations between Data');
            case 2
                [maxT,lags,coeff]= datCrossCorr(vtDaUD.opD,30);
                tab1data = datWrappa(maxT);%vtDaUD.wd
                set(handles.vtDaPanel1,...
                    'title', 'Table of Max Lag between Data');
        end
        set(handles.vtDaTable, 'data', tab1data.Data)%vtDaUD.wd.Data
        set(handles.vtDaTable2,'data', vtDaUD.feel.Data)
        set(handles.vtDaTable2,'columnname', vtDaUD.feel.Name)
        set(handles.vtDaTable2,'CellSelectionCallback',{@daTable2_callback,vtDaUD.opD});



    case 'pushTimeseries_callback'
        dsingTseries(vtDaUD.opD,vtDaUD.varName,vtDaUD.indices)

    case 'pushScatter_callback'
        dsingScatta(vtDaUD.opD,vtDaUD.varName,vtDaUD.indices)

    case 'pushMaxlag_callback'
        dsingMlags(vtDaUD.opD,vtDaUD.varName,vtDaUD.indices)


end
set(handles.dataAnalysisGUI,'UserData',vtDaUD)

在这里,我又有其他与我的数据对象一起操作的函数;整件事情让我非常沮丧!!如果我对问题的描述不够清晰,请告诉我,以便您可以帮助解决。谢谢


当您完成项目后,请告诉我们您的教练在MATLAB中指的是哪些MVC编程模式/技术! - Mikhail Poda
3个回答

6

使用MVC需要正确的面向对象编程技术。在MATLAB中,新版本提供了面向对象编程(OO)功能,您可以像在Java中实现MVC一样使用它。但在MATLAB中这样做并不“合适”(因此我认为您的导师并不是这个意思),因为在大多数简单情况下,这将是过度的,而对于复杂/大型UI,则会出现性能问题。MATLAB在某些情况下速度太慢且存在性能问题。

否则,您可以使用嵌套函数(CS中的闭包)。使用闭包可以“模拟”一些OO功能。唯一的问题是所有代码都必须保存在一个m文件中。

  • 模型:嵌套作用域变量(此处命名为“this”)
  • 视图:uicontrols(和其他UI元素)
  • 控制器:回调

这是一个非常基本的示例,只需填充您的模型数据和视图UI即可:

    function mvc_test()

    //% THIS is nested scope variable
    this.model = getModel(); 
    this.view = getView();

    //% create model
    function model = getModel()
        model.data1 = 1;
    end

    //% create view
    function view = getView()
        view.hfig = figure();
        view.hbtn = uicontrol( 'style', 'push', 'string', 'click me', 'callback', @btn1_cb );
    end

    //% controller
    function btn1_cb(varargin)
        this.model.data1 = this.model.data1 + 1;
        set( this.view.hbtn, 'string', num2str(this.model.data1) );
    end
    end

4
你正在尝试做一件不那么简单的事情。MATLAB的UI系统GUIDE并不是非常灵活。我不想对此持消极态度。我欣赏你尝试按照模式开发UI,但我会建议你简单地使用GUIDE并保留自动生成的代码段。
使用Java或C#作为UI,然后使用MATLAB Builder NEMATLAB Builder Java将MATLAB引入进行处理是更好的选择。我不确定学生版本是否带有它,但这确实是你想要的。
任何程序员学到的最重要的一课是每种语言都有其优点和缺点。试图将一种语言强行用于其设计之外的范例是一场艰苦的战斗,通常会以哭泣而不是欢呼告终。

3
我刚刚研究了一下在Matlab中如何实现MVC,我想我已经找到了一种可行的模式,能够克服Matlab的限制。主要问题是GUI文件是图形对象句柄,而不是类。但是,如果您将GUI包装在视图类中,就可以订阅模型类中的可观察属性。您必须放弃使用GUI中的句柄结构来存储所有用户数据......这与设计模式不符。好消息是,Matlab类非常支持事件和监听器,包括我提到的可观察属性。
我的解决方案演示可以在Matlab Central File Exchange上找到:http://www.mathworks.com/matlabcentral/fileexchange/40294-model-view-control-pattern-using-guide。 有关实现的更详细说明,请参见http://myunscriptedblog.blogspot.com/2013/02/mvc-in-matlab.html博客文章。

优秀的博客文章。为了SO的目的,您可能希望将其放入您的答案中(以避免链接失效)。 - Dang Khoa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接