2016-10-12 30 views
0

我正試圖在matlab中創建一個簡單的gui,並且有一些問題。這個簡化程序的主要思想是我有一個滑塊,它決定了正弦波的頻率。兩張圖顯示了結果信號。 44100 Hz的高分辨率,100 Hz的低分辨率。另一個滑塊決定了繪製信號的長度(也以Hz爲單位)。原來的程序有更多的滑塊添加更多的頻率,但由於我不認爲這很重要,我試圖縮小這個問題。由此產生的代碼仍然很大,對此感到遺憾。在GUIDE,Matlab中存儲嵌套函數中的數據

我的問題是它並不總是更新,我收到錯誤消息。我試圖把所有東西都存儲在句柄中,因爲我認爲這就是你應該這樣做的方式。 handles.lowresx包含低分辨率時間比例,handles.highresx包含高分辨率時間比例。然後在函數calcandplot(句柄)中創建一個臨時的低結點和高結點。每次移動時間間隔滑塊時,函數recalcx(hObject,newhz,handles)都將從滑塊移動回調中調用,並計算新的低方向和低方向。然後存儲在guidata(hObject,句柄)(我希望),這些用於計算繪圖的新低邊和高邊。它似乎並沒有被儲存。

我不確定當它是回調函數內部的嵌套函數時,現在如何保存數據。我是否應該在調用堆棧中一直調用guidata(hObject,句柄),這意味着我必須將hObject作爲參數傳遞給每個函數?還是隻在最內在的功能?我已經嘗試過但沒有一個真正的工作。如果我以後不需要它們,或者我是否應該將它們也保存在句柄中,以便使所有的工作都正確,那麼僅僅計算低風險和高風險並繪製它們就足夠了嗎?

是否必須在調用set(handles.intervaltext,'String',num2str(val))之後調用guidata(句柄)還是自己更新?

我有一個關於手柄的問題。我瞭解它的方式是在每次調用函數時創建並傳遞。這是否對您可以保存的大數據結構提高效率提出了某種限制?如果爲每個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)) 

回答

1

的問題是內recalcx,你是通過添加場lowresx修改handles。您(正確地)使用guidata(hObject, handles)將此保存到guidata中。

的問題是,在調用函數(gui_OpeningFcn),然後保存一個不同handles結構不具有這些字段,因爲內recalcx修改到handles結構guidata不會傳播回調用函數。

這是這個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); 
+0

感謝。認爲它會是這樣的。我試着從多個來源讀到這一點,但不能真正讓我的頭腦清楚。 爲什麼僅僅用guidata(hObject,handles)在recalcx函數中更新它並且在gui_OpeningFcn中禁用它就足夠了?假設我沒有在gui_OpeningFcn中做任何更改,它會不會被保存呢?我讀過一個你永遠不應該覆蓋句柄的地方,只能改變它的字段,所以我想這就是爲什麼我害怕將它作爲recalcx函數中的一個值傳遞的原因。 – user1661303

+1

@ user1661303對'recalcx'函數中'handles'結構所做的任何更改都不存在於調用函數的'handles'變量中。由於您在調用recalcx之後將'guidata'保存在調用函數*中,它將覆蓋「good」'handles'結構。 – Suever