2008-11-07 51 views
5

Có thể viết GUI từ bên trong một hàm không?Làm thế nào để tạo một GUI bên trong một hàm trong MATLAB?

Vấn đề là việc gọi lại tất cả các chức năng GUI được đánh giá trong không gian làm việc chung. Nhưng các hàm có không gian làm việc riêng và không thể truy cập các biến trong không gian làm việc chung. Có thể làm cho GUI-chức năng sử dụng không gian làm việc của hàm không? Ví dụ:

function myvar = myfunc() 
    myvar = true; 
    h_fig = figure; 

    % create a useless button 
    uicontrol(h_fig, 'style', 'pushbutton', ... 
         'string', 'clickme', ... 
         'callback', 'myvar = false'); 

    % wait for the button to be pressed 
    while myvar 
     pause(0.2); 
    end 

    close(h_fig); 

    disp('this will never be displayed'); 
end 

Vòng lặp sự kiện này sẽ chạy vô hạn, vì cuộc gọi lại sẽ không sửa đổi myvar trong hàm. Thay vào đó, nó sẽ tạo một myvar mới trong không gian làm việc toàn cầu.

Trả lời

5

Có một số cách để build a GUI, chẳng hạn như sử dụng App Designer, GUIDE hoặc tạo nó theo chương trình (Tôi sẽ minh họa tùy chọn này bên dưới). Điều quan trọng cần lưu ý là different ways to define callback functions cho các thành phần GUI của bạn và options available for sharing data between components.

Cách tiếp cận mà tôi đang sử dụng là sử dụng nested functions làm gọi lại. Dưới đây là một giao diện đơn giản như một ví dụ:

function make_useless_button() 

    % Initialize variables and graphics: 
    iCounter = 0; 
    hFigure = figure; 
    hButton = uicontrol('Style', 'pushbutton', 'Parent', hFigure, ... 
         'String', 'Blah', 'Callback', @increment); 

    % Nested callback function: 
    function increment(~, ~) 
    iCounter = iCounter+1; 
    disp(iCounter); 
    end 

end 

Khi bạn chạy mã này, bộ đếm hiển thị nên tăng bởi một mỗi khi bạn nhấn nút, bởi vì hàm lồng nhau increment có quyền truy cập vào các không gian làm việc của make_useless_button và do đó có thể sửa đổi iCounter. Lưu ý rằng nút gọi lại được đặt thành function handle đến increment và chức năng này phải chấp nhận hai đối số theo mặc định: một xử lý đồ họa cho thành phần giao diện người dùng đã kích hoạt gọi lại và cấu trúc dữ liệu sự kiện được liên kết. Chúng tôi ignore them with the ~ trong trường hợp này vì chúng tôi không sử dụng chúng.

Mở rộng phương pháp trên để vấn đề cụ thể của bạn, bạn có thể thêm vòng lặp của bạn và thay đổi callback để nó đặt biến lá cờ của bạn false:

function make_stop_button() 

    % Initialize variables and graphics: 
    keepLooping = true; 
    hFigure = figure; 
    hButton = uicontrol('Style', 'pushbutton', 'Parent', hFigure, ... 
         'String', 'Stop', 'Callback', @stop_fcn); 

    % Keep looping until the button is pressed: 
    while keepLooping, 
    drawnow; 
    end 

    % Delete the figure: 
    delete(hFigure); 

    % Nested callback function: 
    function stop_fcn(~, ~) 
    keepLooping = false; 
    end 

end 

Các drawnow là cần thiết vào đây để cung cấp cho các nút gọi lại một cơ hội để làm gián đoạn luồng chương trình trong vòng lặp và sửa đổi giá trị của keepLooping.

1

Bạn có thể khai báo biến toàn cục trong hàm của bạn và toàn cục trong mã GUI, chắc chắn nếu hàm gọi lại nằm trong một hàm riêng biệt thay vì nội tuyến. Tôi đã thực hiện điều này trong một giao diện bộ xương nhỏ mà tôi sử dụng để tạo hệ thống menu nhanh.

Trong mã của bạn ở trên, bạn có thể thêm từ khóa toàn cầu để khai ban đầu của bạn và cũng để inline bạn gọi lại ví dụ: 'myvar toàn cầu = false'

+0

OP sẽ cần thay đổi biến đầu ra thành biến khác và tạo "myvar chung" trong vùng làm việc cơ sở để làm việc này. – Azim

+0

Đây có phải là cách duy nhất không? Nó có vẻ là loại cùn để sử dụng variales toàn cầu cho công việc. – bastibe

+0

Đó là cách tốt nhất mà tôi đã đưa ra - Tôi đồng ý rằng nó hơi xấu xí, tôi không nghĩ rằng mô hình GUI Matlab là rất tốt. Bạn có thể muốn kiểm tra mã trong phần đóng góp uitable (?) Trên Mathworks. Trang web giảm xuống vào phút. –

1

Tôi tìm thấy một giải pháp cho vấn đề. Hàm gọi lại phải sửa đổi cấu trúc xử lý của GUI. Cấu trúc này có thể được truy cập cả từ bên trong gọi lại và từ chức năng mà không giới thiệu các biến mới cho không gian làm việc toàn cầu:

function myfunc() 
    h_fig = figure; 

    % add continue_loop to the GUI-handles structure 
    fig_handles = guihandles(h_fig); 
    fig_handles.continue_loop = true; 
    guidata(h_fig, fig_handles); 

    % create a useless button 
    uicontrol(h_fig, 'style', 'pushbutton', ... 
         'string', 'clickme', ... 
         'callback', @gui_callback); 

    % wait for the button to be pressed 
    while fig_handles.continue_loop 
     fig_handles = guidata(h_fig); % update handles 
     pause(0.2); 
    end 

    close(h_fig); 
    disp('callback ran successfully'); 
end 

% The arguments are the Matlab-defaults for GUI-callbacks. 
function gui_callback(hObject, eventdata, handles) 
    % modify and save handles-Structure 
    handles.continue_loop = false; 
    guidata(hObject, handles); 
end 

lưu ý rằng kể từ khi vòng lặp while sẽ chỉ cập nhật fig_handles khi nó được chạy, bạn sẽ luôn có ít nhất 0.2 giây cho đến khi vòng lặp bắt sự sửa đổi của fig_handles.continue_loop

+0

Câu trả lời bạn đưa ra ở đây chắc chắn có vẻ chính xác và đây là cách mà nhiều người có thể xử lý loại vấn đề này. Đó là tất cả về sở thích cá nhân: một số người thích sử dụng GUIDE, trong khi tôi luôn luôn cảm thấy tôi có thể làm cho mọi thứ trông sạch hơn với các chức năng lồng nhau (mặc dù nó hoạt động nhiều hơn một chút). – gnovice

+0

Tôi thứ hai. Trong thực tế, tôi đã phải chịu đựng rất nhiều từ mã do GUIDE tạo ra, mà tôi đã viết fig2cmd - để trích xuất từ ​​một tệp .fig các lệnh cần thiết để tái tạo nó trong một tệp m. –

Các vấn đề liên quan