MATLAB GUI - tutorial dla początkujących część 1
Matlab to rozbudowane środowisko przeznaczone do obliczeń inżynierskich, tworzenia symulacji. Cechuje go duża liczba funkcjonalnych bibliotek oraz toolboxów, możliwości znacząco poszerzane są za pomocą funkcji pisanych przez użytkownika. Język programowania pakietu Matlab jest pełnoprawnym językiem programowania wysokiego poziomu, o składni wzorowanej na języku C. Pozwala on na używanie funkcji i struktur, oraz umożliwia pisanie programów zorientowanych obiektowo. umożliwia rysowanie dwu i trójwymiarowych wykresów funkcji oraz wizualizację wyników obliczeń w postaci rysunków statycznych i animacji. Program pozwala na wyświetlanie wykresów dwu i trójwymiarowych, oraz wizualizację wyników obliczeń w postaci rysunków statycznych i animacji. Często jednak plik skryptowy nie jest najlepszym sposobem prezentacji danych. Wymaga to od użytkownika końcowego wpisywanie poleceń bezpośrednio w środowisku. Takie coś może być niezwykle trudne i frustrujące gdy się pomylimy. Jak ułatwić sobie i innym korzystanie z środowiska MATLAB? Należy w takim przypadku wykorzystać GUI – Graphical User Interface, czyli graficzny interfejs użytkownika. W tym tutorialu, stworzymy prosty kalkulator, potrafiący wykonać podstawowe działania arytmetyczne, wyświetlać będzie je w wyznaczonym miejscu.
Pracę zaczynamy od wpisania w linii poleceń >>guide.
W następnym kroku mamy do wyboru cztery opcje, my wybierzemy Blank GUI(Default). Otworzy nam się pusty projekt. Okno edytora wygląda jak poniżej. Dla naszych potrzeb dodałem najczęściej używane elementy.
Okno edytora GUIDE(Graphical User Interface Design Editor)
Pokrótce przedstawię elementy jakie możemy użyć do stworzenia naszego graficznego środowiska.
1. Push Button – standardowy przycisk, wciśnięcie może wywoływać określoną akcje. 2. Slider – możemy go ustawić w dwóch płaszczyznach, minimalne przesunięcie suwaka określone jest domyślnie na 0.01x maksymalny zakres. 3. Listbox – przydatny element gdy potrzebujemy korzystać z danych wsadowych, bądź różnych funkcji rozwiązujących nasz problem. 4. Axes – przeznaczeniem tego jest wyświetlanie danych, oprócz wykresów, służy do pokazywania animacji oraz statycznych obrazów. 5. Checkbox – używany gdy wymagany jest wielokrotny wybór, najczęściej w połączeniu z panel, dla większej przejrzystości interfejsu. 6. Toggle button – funkcja identyczna jak przy check box. 7. Pop‑up menu – rozwijane menu kontekstowe, możliwość wyboru tylko jednego elementu z listy. 8. Radio button – zgrupowanie ich pozwala uzyskać funkcje jak w ankietach, tylko jedna funkcja może zostać wybrana. 9. Button group – pozwala grupować przyciski. 10. Edit text – okno wprowadzania danych. 11. Static text – wyświetlanie danych.
Gdy dwukrotnie klikniemy na dowolny element w edytorze, otrzymamy property inspektor. Najważniejsze elementy oznaczono kolorowymi prostokątami.
1. Edycja czcionki • FontAngle – pochylenie • FontName – krój • Font Size – rozmiar w punktach
2. Uchwyt i wyświetlana nazwa • String – wyświetlany ciąg znaków, możliwy do zmiany z poziomu m‑pliku • Edit – możliwość wyboru innego typu • Tag – to co najważniejsze za pomocą wpisanej tu nazwy będziemy odwoływać się do tego elementu
3. Ustawienie wartości maksymalnej oraz minimalnej, przydatne dla na przykład suwaka.
4. TooltipString – podpowiedź dla użytkownika gdy kursor najedzie na element GUI.
5. Value – pozwala nam ustawić wartość początkową.
Do zbudowania naszego kalkulatora będziemy potrzebowali: • 19 x push button • 1 x static text • 1 x panel
Przyciski oznaczymy sobie jako p0 do p9, działania arytmetyczne w polu TAG kolejno mają wpisane: dodawanie, odejmowanie, mnożenie, dzielenie. Dodatkowo przewidziałem, chęć zastosowania separatora dziesiętnego oznaczonego jako kropka, przycisk +/- został oznaczony w kodzie tagiem znak. Wszystkie tagi wraz z podświetleniem elementu wraz z wyświetlaną nazwą możemy podejrzeć wybierając Object Browser.
Gdy mamy już oznaczone wszystkie przyciski możemy przystąpić do pracy nad kalkulatorem. Początek m‑pliku wygląda zawsze mniej więcej tak, w ten kod nie należy ingerować. Tu zapisane są zagnieżdżone pliki naszego GUI z rozszerzeniem *.fig.
[color=#0000FF]function varargout = kalkulator(varargin) gui_Singleton = 1; gui_State = struct([color=#BF00BF]'gui_Name', mfilename, ... [color=#BF00BF] 'gui_Singleton', [color=#BF00BF] gui_Singleton, ... [color=#BF00BF] 'gui_OpeningFcn', @kalkulator_OpeningFcn, ... [color=#BF00BF] 'gui_OutputFcn', @kalkulator_OutputFcn, ... [color=#BF00BF]'gui_LayoutFcn', [] , ... [color=#BF00BF]'gui_Callback', []); [color=#0000FF]if nargin && ischar(varargin{1}) gui_State.gui_Callback = str2func(varargin{1}); end [color=#0000FF]if nargout [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); [color=#0000FF]else gui_mainfcn(gui_State, varargin{:}); [color=#0000FF]end [color=#00BF00]% End initialization code - DO NOT EDIT [color=#00BF00]% --- Executes just before kalkulator is made visible. [color=#00BF00]function kalkulator_OpeningFcn(hObject, eventdata, handles, varargin) handles.output = hObject; [color=#00BF00]% UIWAIT makes kalkulator wait for user response (see UIRESUME) % uiwait(handles.figure1); [color=#0000FF]global zmienna_pomocnicza set(handles.text1,[color=#BF00FF]'String','0.'); zmienna_pomocnicza=0; [color=#00BF00]% Update handles structure guidata(hObject, handles);
To co dla nas jest istotne to: [code] [color=#00BF00]% Update handles structure guidata(hObject, handles);[/code]
Wyrażenie to, odpowiada za uaktualnianie zmiennych pomiędzy funkcjami. Każda funkcja powinna kończyć się tą frazą.
Po handles.output = hObject; dopisałem wartości początkowe, tak by kalkulator nie startował z pustym polem static text
Klawisze oznaczone cyframi opiszemy w następujący sposób:
[color=#00BF00]% --- Executes on button press in p1. [color=#0000FF]function p1_Callback(hObject, eventdata, handles) [color=#0000FF]global zmienna_pomocnicza [color=#00BF00]% get(handles.text1,[color=#BF00FF]'String') odpowiada za pobranie wartości z pola text1, [color=#00BF00]% dane przechowywane w zmiennej handles.text1 są typu <i>string</i> textString = get(handles.text1,[color=#BF00FF]'String'); [color=#00BF00]% warunek logiczny odpowiadający za sprawdzenie czy pojawiająca się liczba jest pierwsza if(strcmp(textString,[color=#BF00FF]'0.')==1)&(zmienna_pomocnicza ==0) [color=#00BF00]% tu nalezy zmienić '1' w kolejnych krokach na liczby w zakresie od 0 do 9 set(handles.text1,[color=#BF00FF]'String','1') ; [color=#0000FF]else [color=#00BF00]% tu nalezy zmienić '1' w kolejnych krokach na liczby w zakresie od 0 do 9 textString =strcat(textString,[color=#BF00FF]'1'); [color=#00BF00]% przykład strcat({ [color=#BF00BF]'209'[color=#00BF00]},{ [color=#BF00BF]'105'[color=#00BF00]}) [color=#00BF00]% da w wyniku [color=#BF00FF]'209105' set(handles.text1,[color=#BF00FF]'String',textString) [color=#0000FF]end zmienna_pomocnicza =0; guidata(hObject, handles);
Liczby mamy zrobione, należy teraz opisać działania.
[color=#00BF00]% --- Executes on button press in odejmowanie. [color=#0000FF]function odejmowanie_Callback(hObject, eventdata, handles) textString = get(handles.text1,[color=#BF00BF]'String'); [color=#00BF00]% w kolejnych funkcjach odpowiedzialnych za działania zmieniamy [color=#BF00FF]'-' [color=#00BF00]na[color=#BF00FF] '+', '/', '*' textString =strcat(textString,[color=#BF00BF]'-'); set(handles.text1,[color=#BF00BF]'String',textString) guidata(hObject, handles);
Na koniec zostało nam zaprogramować backspace, kasowanie pola static text, zmianę znaku na przeciwny, separator dziesiętny oraz wynik działania.
[color=#00BF00]% --- Executes on button press in backspace. [color=#0000FF]function backspace_Callback(hObject, eventdata, handles) [color=#0000FF]global zmienna_pomocnicza textString = get(handles.text1,[color=#0000FF]'String'); [color=#0000FF]if(strcmp(textString,[color=#BF00BF]'0.')==1)&(zmienna_pomocnicza==0) set(handles.text1,[color=#BF00BF]'String','0.') ; [color=#0000FF]else xx=char(textString); l=length(textString); textString=xx(1:l-1); set(handles.text1,'String',textString) [color=#0000FF]end zmienna_pomocnicza=0;
[color=#008000]% --- Executes on button press in kasuj. [color=#0000FF]function kasuj_Callback(hObject, eventdata, handles) set(handles.text1,'String','0.') guidata(hObject, handles); [color=#008000]% --- Executes on button press in kropka. [color=#0000FF]function kropka_Callback(hObject, eventdata, handles) [color=#0000FF]global zmienna_pomocnicza textString = get(handles.text1,[color=#BF00BF]'String'); [color=#0000FF]if(strcmp(textString,[color=#BF00BF]'0.')==1) set(handles.text1,[color=#BF00BF]'String','0.') ; zmienna_pomocnicza=1; [color=#0000FF]else textString =strcat(textString,'.'); set(handles.text1,[color=#BF00BF]'String',textString) [color=#0000FF]end guidata(hObject, handles); [color=#008000]% --- Executes on button press in znak. [color=#0000FF]function znak_Callback(hObject, eventdata, handles) textString = get(handles.text1,[color=#BF00BF]'String'); [color=#0000FF]if(strcmp(textString,[color=#BF00BF]'0.')==1) set(handles.text1,[color=#BF00BF]'String','0.') ; [color=#0000FF]else a = strread(textString, [color=#BF00BF]'%f'); a=0-a; set(handles.text1,[color=#BF00BF]'String',a) end guidata(hObject, handles);
By ułatwić sobie życie, wynik otrzymamy używając eval.Funkcję należy interpretować następująco: EVAL(s), gdzie s jest ciągiem znaków, który MATLAB traktuje jako działanie arytmetyczne na liczbach.
[color=#008000]% --- Executes on button press in wynik. [color=#0000FF]function wynik_Callback(hObject, eventdata, handles) textString = get(handles.text1,[color=#BF00BF]'String'); ans =eval(textString); set(handles.text1,[color=#BF00BF]'String',ans) guidata(hObject, handles);
[image=img2] Gotowy kalkulator
Przedyskutujmy najważniejsze elementy kodu oraz ich działanie.
textString = get(handles.text1,'String');
TextString to zmienna, służy do przechowywania ciągu znaków. Uchwyt handles.text1 pobiera wartość z pola static text Zmienna jest typu string. Co oznacza, iż jeśli chcielibyśmy wykonać działania, należało by zmodyfikować typ danych. Załóżmy iż chcemy dodać dwie liczby a i b wpisywane do programu.
a = get(handles.input1,'String'); b = get(handles.input2,'String');
Pobraliśmy dane, by je dodać do siebie musimy zastosować str2num(string to number).
total= (str2num(a) + str2num(b));
Gdyby zaszła potrzeba wyświetlenia wyniku w GUI, dane typu liczba należało by ponownie zamienić na typ ciąg znaków
c = num2str(total); set(handles.output,'String',c);
By stworzyć ciąg znaków z kolejno wciskanych przycisków wykorzystałem funkcje strcat
textString =strcat(textString,'1');
Działa to w sposób nastepujący. T = STRCAT(S1,S2,S3,...) poziomo łączy odpowiednie wiersze wektorów S1 S2 S3. Wszystkie tablice wejściowe muszą mieć taką samą liczbę wierszy(może to być jeden ciąg znaków). Jeśli na wejściu daliśmy wektor znaków, na wyjściu dostaniemy również wektor znaków.
By pobrać kalkulator kliknij tutaj, zostaniesz przekierowany na serwis hostingowy. W kolejnym odcinku przedstawię sposó na przesyłanie danych między dwoma figurami GUI oraz wyświetlanie danych.