【问题标题】:Storing data in nested functions in GUIDE, Matlab在 GUIDE、Matlab 中将数据存储在嵌套函数中
【发布时间】:2017-02-21 06:48:51
【问题描述】:

我正在尝试在 matlab 中创建一个简单的 gui,但遇到了一些问题。这个简化程序的主要思想是我有一个滑块,它决定了正弦波的频率。两个图显示了结果信号。高分辨率为 44100 Hz,低分辨率为 100 Hz。另一个滑块确定正在绘制的信号的长度(也是以 Hz 为单位测量的)。原始程序有更多的滑块来添加更多频率,但由于我认为这并不重要,所以我尝试将其缩小以解决这个问题。结果代码仍然很大,很抱歉。

我的问题是它并不总是更新,并且我收到错误消息。我尝试将所有内容存储在句柄中,因为我认为这是您应该这样做的方式。 handle.lowresx 包含低分辨率时间刻度,handles.highresx 包含高分辨率时间刻度。然后在函数 calcandplot(handles) 中创建一个临时的 lowresy 和 highresy。每次移动时间间隔滑块时,都会从滑块移动回调中调用函数 recalcx(hObject, newhz, handles) 并计算新的 lowresx 和 lowresy。然后将其存储在 guidata(hObject,handles) 中(我希望如此),这些用于计算新的 lowresy 和 highresy 以进行绘图。但它似乎没有被存储。

当数据是回调函数中的嵌套函数时,我现在不确定如何保存数据。我是否应该在调用堆栈中一直调用 guidata(hObject, handles) ,这意味着我必须将 hObject 作为参数传递给每个函数?还是只在最内部的功能?我都试过了,都没有真正奏效。如果以后不需要它们,仅计算 lowresy 和 highresy 并绘制它们是否足够,或者我也应该将它们保存在句柄中,以使一切正常?

我必须在调用 set(handles.intervaltext, 'String', num2str(val)) 之后调用 guidata(handles) 还是它会自行更新?

我有一个关于句柄的问题。我理解它的方式是在每次调用函数时创建并传递一个副本。这是否对您可以在那里保存多少大数据结构以使其高效产生某种限制?如果在调用某种事件(鼠标悬停、按键等)时为每个 gui 组件创建一个副本,我当然可以看到事情会变得缓慢。有关如何处理此问题的任何提示?

错误信息:

Reference to non-existent field 'lowresx'.

Error in gui>calcandplot (line 85)
lowresy = wave(handles.lowresx, handles.freq1);

Error in gui>intervalslider_Callback (line 106)
calcandplot(handles);

代码:

function varargout = gui(varargin)
% GUI MATLAB code for gui.fig
%      GUI, by itself, creates a new GUI or raises the existing
%      singleton*.
%
%      H = GUI returns the handle to a new GUI or the handle to
%      the existing singleton*.
%
%      GUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in GUI.M with the given input arguments.
%
%      GUI('Property','Value',...) creates a new GUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before gui_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to gui_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help gui

% Last Modified by GUIDE v2.5 12-Oct-2016 14:18:38

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @gui_OpeningFcn, ...
                   'gui_OutputFcn',  @gui_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before gui is made visible.
function gui_OpeningFcn(hObject, eventdata, handles, varargin)
handles.freq1 = 0;
handles.lowsr = 1000;
handles.sr = 44100;
handles.lenhz = 220;
recalcx(hObject, handles.lenhz, handles);
'recalculated'

% Choose default command line output for gui
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes gui wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = gui_OutputFcn(hObject, eventdata, handles) 
varargout{1} = handles.output;

% --- Executes on slider movement.
function slider1_Callback(hObject, eventdata, handles)
val = get(hObject,'Value');
handles.freq1 = val;
guidata(hObject, handles);
set(handles.text1, 'String', num2str(val));
calcandplot(handles);

% --- Executes during object creation, after setting all properties.
function slider1_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

function calcandplot(handles)
lowresy = wave(handles.lowresx, handles.freq1);
highresy = wave(handles.highresx, handles.freq1);
axes(handles.axes1);
plot(handles.lowresx,lowresy, 'o');
axes(handles.axes2);
plot(handles.highresx,highresy, 'o');

function y = wave(x, freq1)
% x in sec
y = sin(x*freq1);

% --- Executes on slider movement.
function intervalslider_Callback(hObject, eventdata, handles)
val = get(hObject,'Value');
recalcx(hObject, val, handles);

strcat('val is now ', num2str(val))
strcat('handles.lenhz is now', num2str(handles.lenhz))
guidata(hObject, handles);
set(handles.intervaltext, 'String', num2str(val));
handles
calcandplot(handles);

% --- Executes during object creation, after setting all properties.
function intervalslider_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

function recalcx(hObject, newhz, handles)
handles.lenhz = newhz;
handles.lowresx = (0:1/handles.lowsr:(2*pi)/handles.lenhz)';
handles.highresx = (0:1/handles.sr:(2*pi)/handles.lenhz)';
strcat('inside handles is', num2str(handles.lenhz))
guidata(hObject, handles);
strcat('inside handles again is', num2str(handles.lenhz))

【问题讨论】:

    标签: matlab user-interface matlab-figure


    【解决方案1】:

    问题是在recalcx 中,您通过添加字段lowresx 来修改handles。您(正确地)使用 guidata(hObject, handles) 将其保存到 guidata。

    问题在于,在调用函数 (gui_OpeningFcn) 中,您随后将 不同 handles 结构保存到 guidata 中,因为对 @987654327 进行了修改recalcx 中的 @ 结构不会传播回调用函数。

    正是这个 handles 结构没有这些字段,然后在您的 GUI 中传递并导致您看到的错误。

    解决此问题的一种方法是让 recalcx 返回修改后的 handles 结构

    function handles = recalcx(hObject, newhz, handles)
        handles.lenhz = newhz;
        handles.lowresx = (0:1/handles.lowsr:(2*pi)/handles.lenhz)';
        handles.highresx = (0:1/handles.sr:(2*pi)/handles.lenhz)';
        strcat('inside handles is', num2str(handles.lenhz))
        guidata(hObject, handles);
        strcat('inside handles again is', num2str(handles.lenhz))
    end
    

    然后调用函数可以有一个更新的版本

    function gui_OpeningFcn(hObject, eventdata, handles, varargin)
        handles.freq1 = 0;
        handles.lowsr = 1000;
        handles.sr = 44100;
        handles.lenhz = 220;
        handles = recalcx(hObject, handles.lenhz, handles);
    
        % Choose default command line output for gui
        handles.output = hObject;
    
        % Update handles structure
        guidata(hObject, handles);
    

    【讨论】:

    • 谢谢。以为会是这样。我已经尝试从多个来源阅读此内容,但无法真正理解它。为什么仅在 recalcx 函数中使用 guidata(hObject,handles) 更新它并在 gui_OpeningFcn 中禁用它还不够?假设我不在 gui_OpeningFcn 中对其进行任何更改,那它不会被保存吗?我在某处读到你不应该覆盖句柄,只更改其中的字段,所以我想这就是为什么我害怕将它作为值传递给 recalcx 函数。
    • @user1661303 对recalcx 函数中的handles 结构所做的任何更改都不存在于调用函数的handles 变量中。由于您将guidata 保存在调用函数之后 调用recalcx 它会覆盖“好”handles 结构。
    猜你喜欢
    • 1970-01-01
    • 2017-05-15
    • 1970-01-01
    • 2017-12-03
    • 1970-01-01
    • 2015-08-12
    • 1970-01-01
    • 1970-01-01
    • 2014-12-02
    相关资源
    最近更新 更多