Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab 什么';这是“什么?”;对",;组织GUI代码的方法?_Matlab_User Interface_Matlab Guide_Matlab Deployment - Fatal编程技术网

Matlab 什么';这是“什么?”;对",;组织GUI代码的方法?

Matlab 什么';这是“什么?”;对",;组织GUI代码的方法?,matlab,user-interface,matlab-guide,matlab-deployment,Matlab,User Interface,Matlab Guide,Matlab Deployment,我正在开发一个相当复杂的GUI程序,该程序将与MATLAB编译器一起部署。(有很好的理由使用MATLAB构建这个GUI,这不是问题的重点。我意识到GUI构建并不适合这种语言。) 有很多方法可以在GUI中的函数之间共享数据,甚至在应用程序中的GUI之间传递数据: setappdata/getappdata/____;appdata-将任意数据关联到句柄 guidata-通常与指南一起使用;“存储或检索GUI数据”到句柄结构 对句柄对象的UserData属性应用set/get操作 在主函数中使用嵌

我正在开发一个相当复杂的GUI程序,该程序将与MATLAB编译器一起部署。(有很好的理由使用MATLAB构建这个GUI,这不是问题的重点。我意识到GUI构建并不适合这种语言。)

有很多方法可以在GUI中的函数之间共享数据,甚至在应用程序中的GUI之间传递数据:

  • setappdata/getappdata/____;appdata
    -将任意数据关联到句柄
  • guidata
    -通常与指南一起使用;“存储或检索GUI数据”到句柄结构
  • 对句柄对象的
    UserData
    属性应用
    set/get
    操作
  • 在主函数中使用嵌套函数;基本上模拟“全局”范围变量
  • 在子功能之间来回传递数据
我的代码的结构不是最漂亮的。现在我将引擎与前端分离(很好!),但是GUI代码非常像意大利面条。借用Android speak,这里有一个“活动”的框架:

function myGui

    fig = figure(...); 

    % h is a struct that contains handles to all the ui objects to be instantiated. My convention is to have the first field be the uicontrol type I'm instantiating. See draw_gui nested function

    h = struct([]);


    draw_gui;
    set_callbacks; % Basically a bunch of set(h.(...), 'Callback', @(src, event) callback) calls would occur here

    %% DRAW FUNCTIONS

    function draw_gui
        h.Panel.Panel1 = uipanel(...
            'Parent', fig, ...
            ...);

        h.Panel.Panel2 = uipanel(...
            'Parent', fig, ...
            ...);


        draw_panel1;
        draw_panel2;

        function draw_panel1
             h.Edit.Panel1.thing1 = uicontrol('Parent', h.Panel.Panel1, ...);
        end
        function draw_panel2
             h.Edit.Panel2.thing1 = uicontrol('Parent', h.Panel.Panel2, ...);
        end


    end

    %% CALLBACK FUNCTIONS
    % Setting/getting application data is done by set/getappdata(fig, 'Foo').
end
我以前编写的代码中没有嵌套任何内容,因此我在任何地方来回传递
h
(因为需要重新绘制、更新内容等)和
setappdata(图)
,以存储实际数据。无论如何,我一直在一个文件中保存一个“活动”,我相信这将是未来维护的噩梦。回调同时与应用程序数据和图形句柄对象交互,我认为这是必要的,但这阻止了代码库的两个“一半”的完全分离

因此,我在这里寻找一些组织/GUI设计帮助。即:

  • 是否有我应该用来组织的目录结构?(回调与绘图函数?)
  • 与GUI数据交互并将其与应用程序数据隔离的“正确方式”是什么?(当我提到GUI数据时,我指的是
    set/get
    ting句柄对象的属性)
  • 我如何避免将所有这些绘图功能放在一个包含数千行的巨大文件中,并且仍然高效地来回传递应用程序和GUI数据?可能吗
  • 持续使用
    set/getappdata
    是否会导致性能下降
  • 我的后端代码(3个对象类和一堆助手函数)是否应该采用某种结构,以便从GUI的角度进行维护
我不是一名软件工程师,我只知道这很危险,所以我确信这些对于经验丰富的GUI开发人员来说是相当基本的问题(在任何语言中)。我几乎觉得MATLAB中缺少GUI设计标准(是否存在标准?)严重影响了我完成该项目的能力。这是一个比我所从事的任何项目都要庞大得多的MATLAB项目,而且我以前从未考虑过具有多个图形窗口等的复杂UI。

这是MATLAB对象的一个有用但传统的属性。“AppData”方法套件(即
setappdata
getappdata
rmappdata
isappdata
,等等)提供了一个很好的替代方法,可以替代比较笨拙的
get/set(hFig,'UserData',dataStruct)
方法。事实上,为了管理GUI数据,《指南》使用了该功能,它只是
setappdata
/
getappdata
函数的包装

AppData方法相对于
'UserData'
属性的几个优点如下:

  • 多个异构属性的更自然界面

    用户数据
    仅限于一个变量
    ,要求您设计另一层数据组织(即结构)。假设您要存储一个字符串
    str='foo'
    和一个数字数组
    v=[12]
    。对于
    UserData
    ,您需要采用结构方案,例如
    s=struct('str','foo','v',[12])
    set/get
    只要你想要任何一个属性(例如
    s.str='bar';set(h,'UserData',s);
    )。使用
    setappdata
    ,过程更直接(也更高效):
    setappdata(h,'str','bar')

  • 底层存储空间的受保护接口

    虽然
    'UserData'
    只是一个常规句柄图形属性,但包含应用程序数据的属性不可见,尽管可以通过名称('ApplicationData',但不要这样做!)访问它。您必须使用
    setappdata
    来更改任何现有的AppData属性,这可以防止您在尝试更新单个字段时意外地删除
    'UserData'
    的全部内容。此外,在设置或获取AppData属性之前,您可以使用
    isappdata
    验证命名属性的存在,这有助于异常处理(例如,在设置输入值之前运行进程回调)和管理GUI的状态或它所管理的任务(例如,通过某些属性的存在来推断进程的状态,并适当地更新GUI)

'UserData'
'ApplicationData'
属性之间的一个重要区别是
'UserData'
默认为
[]
(一个空数组),而
'ApplicationData'
本质上是一个结构。这一差异,加上
setappdata
getappdata
没有M文件实现(它们是内置的),表明使用
setappdata
设置命名属性不需要重写数据结构的全部内容(想象一个执行结构字段就地修改的MEX函数-MATLAB能够通过将结构维护为
hFig = ancestor(hObj,'Figure')
function pushbutton17_callback(hObject,evt, handles)
    some_text = someOtherFunction();
    set(handles.text45, 'String', some_text);
end
 handles.panel17 = uipanel(...);
 createTable(handles.panel17); % creates a table in the specified panel
classdef Model < handle
    %MODEL  represents a signal composed of two components + white noise
    % with sampling frequency FS defined over t=[0,1] as:
    %   y(t) = a * sin(2pi * f*t) + sin(2pi * 2*f*t) + white_noise

    % observable properties, listeners are notified on change
    properties (SetObservable = true)
        f       % frequency components in Hz
        a       % amplitude
    end

    % read-only properties
    properties (SetAccess = private)
        fs      % sampling frequency (Hz)
        t       % time vector (seconds)
        noise   % noise component
    end

    % computable dependent property
    properties (Dependent = true, SetAccess = private)
        data    % signal values
    end

    methods
        function obj = Model(fs, f, a)
            % constructor
            if nargin < 3, a = 1.2; end
            if nargin < 2, f = 5; end
            if nargin < 1, fs = 100; end
            obj.fs = fs;
            obj.f = f;
            obj.a = a;

            % 1 time unit with 'fs' samples
            obj.t = 0 : 1/obj.fs : 1-(1/obj.fs);
            obj.noise = 0.2 * obj.a * rand(size(obj.t));
        end

        function y = get.data(obj)
            % signal data
            y = obj.a * sin(2*pi * obj.f*obj.t) + ...
                sin(2*pi * 2*obj.f*obj.t) + obj.noise;
        end
    end

    % business logic
    methods
        function [mx,freq] = computePowerSpectrum(obj)
            num = numel(obj.t);
            nfft = 2^(nextpow2(num));

            % frequencies vector (symmetric one-sided)
            numUniquePts = ceil((nfft+1)/2);
            freq = (0:numUniquePts-1)*obj.fs/nfft;

            % compute FFT
            fftx = fft(obj.data, nfft);

            % calculate magnitude
            mx = abs(fftx(1:numUniquePts)).^2 / num;
            if rem(nfft, 2)
                mx(2:end) = mx(2:end)*2;
            else
                mx(2:end -1) = mx(2:end -1)*2;
            end
        end
    end
end
function handles = View_TimeDomain(m)
    %VIEW  a GUI representation of the signal model

    % build the GUI
    handles = initGUI();
    onChangedF(handles, m);    % populate with initial values

    % observe on model changes and update view accordingly
    % (tie listener to model object lifecycle)
    addlistener(m, 'f', 'PostSet', ...
        @(o,e) onChangedF(handles,e.AffectedObject));
end

function handles = initGUI()
    % initialize GUI controls
    hFig = figure('Menubar','none');
    hAx = axes('Parent',hFig, 'XLim',[0 1], 'YLim',[-2.5 2.5]);
    hSlid = uicontrol('Parent',hFig, 'Style','slider', ...
        'Min',1, 'Max',10, 'Value',5, 'Position',[20 20 200 20]);
    hLine = line('XData',NaN, 'YData',NaN, 'Parent',hAx, ...
        'Color','r', 'LineWidth',2);

    % define a color property specific to the view
    hMenu = uicontextmenu;
    hMenuItem = zeros(3,1);
    hMenuItem(1) = uimenu(hMenu, 'Label','r', 'Checked','on');
    hMenuItem(2) = uimenu(hMenu, 'Label','g');
    hMenuItem(3) = uimenu(hMenu, 'Label','b');
    set(hLine, 'uicontextmenu',hMenu);

    % customize
    xlabel(hAx, 'Time (sec)')
    ylabel(hAx, 'Amplitude')
    title(hAx, 'Signal in time-domain')

    % return a structure of GUI handles
    handles = struct('fig',hFig, 'ax',hAx, 'line',hLine, ...
        'slider',hSlid, 'menu',hMenuItem);
end

function onChangedF(handles,model)
    % respond to model changes by updating view
    if ~ishghandle(handles.fig), return, end
    set(handles.line, 'XData',model.t, 'YData',model.data)
    set(handles.slider, 'Value',model.f);
end
function handles = View_FrequencyDomain(m)    
    handles = initGUI();
    onChangedF(handles, m);

    hl = event.proplistener(m, findprop(m,'f'), 'PostSet', ...
        @(o,e) onChangedF(handles,e.AffectedObject));
    setappdata(handles.fig, 'proplistener',hl);
end

function handles = initGUI()
    % load FIG file (its really a MAT-file)
    hFig = hgload('ViewGUIDE.fig');
    %S = load('ViewGUIDE.fig', '-mat');

    % extract handles to GUI components
    hAx = findobj(hFig, 'tag','axes1');
    hSlid = findobj(hFig, 'tag','slider1');
    hTxt = findobj(hFig, 'tag','fLabel');
    hMenu = findobj(hFig, 'tag','cmenu1');
    hMenuItem = findobj(hFig, 'type','uimenu');

    % initialize line and hook up context menu
    hLine = line('XData',NaN, 'YData',NaN, 'Parent',hAx, ...
        'Color','r', 'LineWidth',2);
    set(hLine, 'uicontextmenu',hMenu);

    % customize
    xlabel(hAx, 'Frequency (Hz)')
    ylabel(hAx, 'Power')
    title(hAx, 'Power spectrum in frequency-domain')

    % return a structure of GUI handles
    handles = struct('fig',hFig, 'ax',hAx, 'line',hLine, ...
        'slider',hSlid, 'menu',hMenuItem, 'txt',hTxt);
end

function onChangedF(handles,model)
    [mx,freq] = model.computePowerSpectrum();
    set(handles.line, 'XData',freq, 'YData',mx)
    set(handles.slider, 'Value',model.f)
    set(handles.txt, 'String',sprintf('%.1f Hz',model.f))
end
function [m,v1,v2] = Controller
    %CONTROLLER  main program

    % controller knows about model and view
    m = Model(100);           % model is independent
    v1 = View_TimeDomain(m);  % view has a reference of model

    % we can have multiple simultaneous views of the same data
    v2 = View_FrequencyDomain(m);

    % hook up and respond to views events
    set(v1.slider, 'Callback',{@onSlide,m})
    set(v2.slider, 'Callback',{@onSlide,m})
    set(v1.menu, 'Callback',{@onChangeColor,v1})
    set(v2.menu, 'Callback',{@onChangeColor,v2})

    % simulate some change
    pause(3)
    m.f = 10;
end

function onSlide(o,~,model)
    % update model (which in turn trigger event that updates view)
    model.f = get(o,'Value');
end

function onChangeColor(o,~,handles)
    % update view
    clr = get(o,'Label');
    set(handles.line, 'Color',clr)
    set(handles.menu, 'Checked','off')
    set(o, 'Checked','on')
end