2013-06-05 45 views
3

想知道如何實現標題中的問題。我有一些從按鈕按下運行的回調。這些回調,如果被數字關閉中斷,將導致錯誤,因爲函數似乎運行,然後被關閉函數關閉數字而中斷,然後在數字關閉後回調似乎恢復。如何防止回撥被圖形的關閉功能中斷?

如果我將按鈕的'Interruptible'屬性設置爲'on',它可以防止其他回調中斷它,但似乎不適用於圖形的關閉功能。我的另一個想法是在圖的'CloseRequestFcn'回調中指定'closefunction',然後在刪除圖之前調用drawnow來刷新事件隊列,但這不起作用。

對我來說,最後一招是在運行回調時將圖形的'CloseRequestFcn'設置爲'',但這看起來很乏味。有沒有一個標準的解決方案來完成這個?

編輯:

從MATLAB的文件:

注意如果中斷回調是DeleteFcn或CreateFcn 回調或人物的CloseRequest或ResizeFcn回調,它 不管中斷值的執行回調該對象的可中斷屬性爲 。中斷回調在下一個drawnow,figure,getframe,pause或waitfor 語句中啓動 執行。圖形的WindowButtonDownFcn回調例程或對象的ButtonDownFcn或回調例程按照上述規則進行處理。

因此,看來是interruptible屬性不影響關閉功能的情況。

編輯2:

好的,所以我覺得我發現了一個問題。這真是奇怪。其實我從MATLAB文檔是回調只是中斷髮現,如果他們有interruptible屬性設置爲on AND:

If there is a drawnow, figure, getframe, waitfor, or pause command in the running callback, then MATLAB executes the interrupting callbacks which are already in the queue and returns to finish execution of the current callback.

我不使用任何的明確這些功能,所以事實證明我的大部分回調不能被closereqfcn中斷。但是,事實證明有些是,而爲什麼看起來很奇怪。如果有回調:

`大的計算 - > imshow - > imshow

large computation -> set -> set -> set -> set

其中set命令設置軸visible屬性爲off,然後沒有中斷似乎發生,如果我退出回調

現在時,如果我有:

large computation -> imshow -> set -> imshow -> set

如果我在第二個set命令的回調期間退出,matlab會發出錯誤。另外,如果我有:

large computation -> imshow -> imshow -> set

MATLAB發出一個錯誤,如果第一set命令的回調過程中我退出。如果我在回調過程中取消

large computation -> imshow -> imshow -> imshow

還發行了第三imshow錯誤。

由於某種原因,似乎連續撥打兩個imshow致使我的回調中斷。是否有可能matlab隱式調用drawnow或做一些奇怪的事情,如果你使用多個imshow?順便說一句,我的matlab版本是R2009a。

+1

一個解決方法可以在'CloseRequestFcn'可以啓動計時器,並在計時器回調試圖關閉這個數字如果沒有通過檢查**標誌中斷任何重要的回調**('close_allowed'),你當數字不應該被關閉時(例如在重要進程中)設置爲false。 – pm89

+1

在我看來,導致錯誤的實際問題是回調中使用的數據會被刪除。在圖形之外創建所需的數據副本可能是一個想法(無論如何,這是一個很好的做法)。也許用'copyfig'到一個隱藏的窗口,或者只是在回調開始時手動存儲你所需要的。完成後請務必清理乾淨。 – bdecaf

+0

@bdecaf不僅僅如此。有時我必須更新可見的數字軸。如果該回調被圖形關閉中斷,則它會嘗試更新不存在的軸手柄。看起來很奇怪的matlab會這樣做。這似乎使任何回調都可以被數字關閉中斷。如何讓這種行爲更安全? – Justin

回答

2

我從來沒有真正相信Interruptible標誌(或類似的機制)......我立即承認我從來沒有使用過很多,但那是因爲當我第一次嘗試它時,我注意到'Interruptible',   'off'(和朋友)似乎有更多的例外規則比它的維修 - 頭痛材料警報!

所以,我養成了通過簡單的使用標誌來解決這類問題的習慣,並且在鎖定/釋放函數中包裝了所有必須不可中斷的回調。

事情是這樣的:

% Define a button 
uicontrol(... 
    'style', 'pushbutton',... 
    'interruptible', 'off',... % Nice, but doesn't catch DeleteFcn, CreateFcn, ... 
           % CloseRequestFcn or ResizeFcn 
    % ... 
    % further definition of button 
    % ... 

    % Put callback in a wrapper: 
    'callback', @(src,evt) uninterruptibleCallback(@buttonCallback, src,evt)... 
); 

其中uninterruptibleCallback()看起來是這樣的:

function varargout = uninterruptibleCallback(callback, varargin) 

    % only execute callback when 'idle' 
    % (you can omit this if you don't want such strict ordering of callbacks) 
    while ~strcmp(get(mainFigure, 'userData'), 'idle') 
     pause(0.01); 
     % ...or some other action you desire 
    end 

    % LOCK 
    set(mainFigure, 'userData', 'busy'); 

    try 
     % call the "real" callback 
     [varargout{:}] = callback(varargin{:}); 

     % UNLOCK 
     set(mainFigure, 'userData', 'idle'); 

    catch ME 
     % UNLOCK 
     set(mainFigure, 'userData', 'idle'); 

     throw(ME); 
    end 

end 

,它允許您使用此closeReqFcn()你的身材:

function closeReqFcn(~,~) 

    % only when the currently running locked callback (if any) has finished 
    while ~strcmp(get(mainFigure, 'userData'), 'idle') 
     pause(0.01); 
     % ...or some other action you desire 
    end 

    % ... 
    % further clean-up tasks 
    % ... 

    % deletion 
    delete(mainFigure); 

end 

理論上,當你把全部這種模式的回調,它基本上等同於管理你自己的事件隊列。

這當然有一些優點,但有很多很多缺點 - 您可能需要考慮一下。整個機制對於您的用例來說可能會慢得令人無法接受,或者您可能需要定義更多具有更具體行爲的鎖定函數。

無論如何,我懷疑這是一個開始的好地方。

+0

關閉請求函數在返回中斷的回調之前是否運行完成?在這種情況下,似乎'userData'將始終保持不「空閒」狀態。 – Justin

+0

@jucestain:你的意思是關閉請求函數也應該鎖定GUI? –

+0

我正在解釋'closeReqFcn'中的'while'循環,作爲暫停執行的方式,直到中斷的回調完成運行。我的理解是,closeReqFcn在返回到被中斷的回調之前完成,並因此處於死鎖狀態,因爲它正在等待中斷的回調完成。它是否正確? – Justin

0

@Rody Oldenhuis的解決方案的替代方法是在CloseRequestFcn內部啓動一個計時器,以便在沒有不間斷代碼正在進行時關閉該數字(可以用一個標記來表示該數字(Closing_Allowed)。

function mainFig_CloseRequestFcn(hObject, eventdata, handles) 

    Time = 3; % Wait time before force killing (in sec) 
    Kill.tmr = timer('executionMode', 'fixedRate',... 
     'Period', 1/10,... 
     'TimerFcn', {@KillingTimer_Callback, handles}); 
    Kill.counts = ceil(Time/Kill.tmr.Period); 

    setappdata(handles.mainFig,'Kill',Kill); 

    start(Kill.tmr); 

function KillingTimer_Callback(hObject, eventdata, handles) 

    Kill = getappdata(handles.mainFig,'Kill'); 
    Kill.counts = Kill.counts - 1; % Count down 
    setappdata(handles.mainFig,'Kill',Kill); 

    if Kill.counts == 0 || getappdata(handles.mainFig, 'Closing_Allowed') 
     stop(Kill.tmr); 
     delete(handles.mainFig); 
    end 

if Kill.counts == 0意味着超時,並關閉即使不間斷工作正在進行中,然後將導致你現在有時同樣的錯誤的數字,但如果你知道的最長時間你需要完成不可中斷的工作,那麼你可以正確設置上面的Time

最後通過設置Closing_Allowed標誌來包裝不間斷代碼。

function pushbutton_Callback(hObject, eventdata, handles) 

    setappdata(handles.mainFig, 'Closing_Allowed', 0); % Closing is not allowed 
    pause(2); 
    setappdata(handles.mainFig, 'Closing_Allowed', 1); % Closing is allowed