Laboratorium MATLA. Elementy programowania obiektowego. Graficzny Interfejs Użytkownika (GUI) Opracowali: - dr inż. Beata Leśniak-Plewińska Zakład Inżynierii Biomedycznej Instytut Metrologii i Inżynierii Biomedycznej Wydział Mechatroniki Politechniki Warszawskiej Warszawa, 2017
Cel ćwiczenia W ramach ćwiczenia studenci zapoznają się z projektowaniem graficznego interfejsu użytkownika w MATLAB'ie. W instrukcji do ćwiczenia zamieszczono opis modułu GUIDE (Graphical User Interface Design Enviroment) narzędzia służącego do interaktywnego tworzenia GUI (ang. Graphical User Interface, GUI). 2/21
Informacje podstawowe Graficzny interfejs użytkownika to ogólne określenie sposobu prezentacji informacji przez komputer polegającego na rysowaniu elementów (widżetów, zwanych często kontrolkami, takich jak: okna, przyciski, pola wyboru, pola radiowe, pola edycyjne, paski menu, ikony, listy, zakładki, okna dialogowe, suwaki, paski narzędzi, etykiety) z dokładnością do piksela, w odróżnieniu od interfejsu tekstowego, gdzie najmniejszą jednostką rysowaną jest znak. GUIDE W MATLAB'ie do interaktywnego projektowania GUI służy narzędzie GUIDE. GUIDE wspomaga rozmieszczanie elementów GUI oraz generuje szkielet programu (m-plik) obsługującego te elementy (obiekty). Aplikację GUIDE możemy wywoływać: wpisując w oknie poleceń komendy >>guide lub >>guide('nazwa_pliku.fig'); wybierając ze wstążki Home: New App GUIDE (Rys. 1). Rysunek 1: Uruchamianie aplikacji GUIDE Quick Start Aplikacje tworzone w GUIDE są zapisywane jako pliki graficzne z rozszerzeniem.fig i w formie m-pliku. Polecenie guide otwiera okno GUIDE Quick Strat (Rys. 2). Użytkownik uzyskuje możliwość wyboru pustego edytora GUI, wyboru spośród kilku typowych wzorców rozmieszczenia elementów interfejsu oraz otworzenia istniejącego GUI w celu jego modyfikacji. W celu stworzenia nowego GUI należy wybrać opcję Blank GUI (Default) i kliknąć OK otwierając okno edytora Layout untitled.fig (Rys. 3). 3/21
Rysunek 2: Okno GUIDE Quick Start Rysunek 3: Okno edytora Layout W centralnej części okna edytora Layout (część zakratkowana liniami siatki) znajduje się obszar wyświetlany po uruchomieniu aplikacji, dla której tworzony jest interfejs graficzny. W tym obszarze wstawiane są elementy/obiekty GUI. Z lewej strony okna GUIDE znajduje się pasek narzędzi z ikonami odpowiadającymi poszczególnym komponentom, z których może zostać 4/21
zbudowane. Aby poznać nazwy poszczególnych komponentów należy albo najechać kursorem myszy na ikonę danego komponentu, albo zmienić ustawienia GUIDE. W tym celu należy z menu okna GUIDE wybrać pozycje File Preferences. W efekcie otrzymamy okno służące do edycji preferencji środowiska MATLAB otarte na zakładce opcji dla aplikacji GUIDE. Następnie należy zaznaczyć pole wyboru dla pozycji Show names in component palette (Rys. 4). Rysunek 4: Aktywowanie wyświetlania nazw komponentów GUI w aplikacji GUIDE Po zaakceptowaniu zmiany okno edytora GUI będzie miało postać przedstawioną na Rys. 5 Rysunek 5: Okno edytora Layout po zmianie ustawień 5/21
Poszczególne narzędzia służą do: Select Push Button - wyboru/wskazania komponentu - utworzenia przycisku, który po naciśnięciu wywołuje akcję zdefiniowaną w funkcji wywołania wstecznego (Callback) Slider - utworzenia suwaka. Radio Button - utworzenia przycisku opcji, służącego do wyboru jednej z opcji, który posiada dwa stany: włączony i wyłączony; jeśli przycisk ten jest w grupie to w momencie aktywacji dezaktywuje on pozostałe przyciski opcji z grupy. Checkbox - utworzenia przycisku wyboru; jeśli przycisk ten jest w grupie, to wybranie jednego z nich nie anuluje wyboru pozostałych Edit Text - utworzenia pola tekstowego umożliwiającego wprowadzanie i edycję tekstu; wywołanie wsteczne jest wykonywane po naciśnięciu klawisza ENTER Static Text - utworzenia etykiety opisującej inne obiekty graficzne w GUI lub pole obliczeniowe; użytkownik nie może interaktywnie wpływać na ten obiekt; nie posiada on wywołania wstecznego Popup Menu - utworzenia menu kontekstowego umożliwiającego wybór jednego z elementów na liście Listbox - utworzenia listy rozwijanej umożliwiającej wybór jednego lub więcej jej elementów Toggle Button - utworzenia przycisku przełącznika bistabilnego wciśnięty pozostaje w tym stanie aż zostanie wyciśnięty; wywołanie wsteczne jest wykonywane po zwolnieniu naciśniętego przycisku myszki wskazującej ten przycisk Table - utworzenia tabeli Axes - utworzenia osi współrzędnych Panel - utworzenia panelu; panel może zawierać grupę dowolnych elementów; zgrupowanie podobnych elementów ułatwia korzystanie z interfejsu; panel ma tytuł, obramowanie oraz może zawierać inne panele, grupę opcji, osie współrzędnych i kontrolki; położenie każdego elementu wewnątrz panelu jest interpretowane jako względne do panelu Button Group - utworzenia grupy przycisków opcji (Radio buttons) lub przycisków przełącznika (Toggle Buttons). Toolbar - utworzenia paska narzędzi ActiveX Control - utworzenia kotrolki ActiveX Właściwe działanie GUI gwarantują wywołania wsteczne (Callbacks). Są to funkcje wykonywane wtedy, gdy wystąpi określona akcja na ekranie, np. klikniecie przycisku. Wybrane rodzaje i własności wywołań wstecznych podaje Tabela 1. Pobranie elementu możliwe jest za pomocą myszy. Każdy obiekt GUI można dopasowywać do aktualnych potrzeb zmieniając jego położenie, rozmiar i inne atrybuty. Korzystając w GUIDE z myszy należy używać obu jej przycisków przy czym: lewy przycisk służy do wyboru obiektu graficznego, zmiany jego wymiarów oraz do jego przesuwania; bardziej precyzyjne pozycjonowanie obiektów, po ich wskazaniu myszką, możliwe jest dzięki klawiszom kierunkowym: ; prawy przycisk myszy otwiera lokalne menu kontekstowe umożliwiające między innymi (Rys. 6): wycięcie elementu (Cut) skopiowanie elementu (Copy) wklejenie wyciętego elementu (dostępna po użyciu opcji Cut) (Paste) wyczyszczenie elementu z okna (Clear) 6/21
duplikowanie elementu (Duplicate) zmianę warstwy: przesuń na wierzch/pod spód (Bring to Front/Send to Back) określenie i modyfikację właściwości obiektu (Property Inspector) przeglądanie zdefiniowanych obiektów (Object Browser) definiowanie wywołań zwrotnych (View Callbacks). Tabela 1 Właściwość wywołania wstecznego Opis ButtonDownFcn Jest wykonywane wtedy, gdy użytkownik naciśnie przycisk myszki, a jej kursor wskazuje dany komponent CreateFcn Inicjalizuje komponent podczas jego tworzenia, ale przed pojawieniem się na ekranie Callback Wykonuje podstawowe zadania w odpowiedzi na akcję użytkownika. DeleteFcn Jest wykonywane przed usuwaniem obiektu, tj. gdy uruchomione zostanie polecenie delete albo close w stosunku do okna aplikacji zawierającego dany element (nie ma zastosowania do obiektu root). KeyPressFcn Jest wykonywane wtedy, gdy użytkownik naciśnie klawisz na klawiaturze a wywołanie wsteczne komponentu jest aktywne. ResizeFcn Jest wykonywane wtedy, gdy użytkownik zmienia rozmiar obiektu Panel lub Button Group. SelectionChangeFcn (Radio Button) lub przełącznika (Toggle Button) Rysunek 6: Okno edytora Layout. Menu kontekstowe otwarte za pomocą prawego przycisku myszy. Programowanie interfejsu graficznego rozpoczyna się od określenia właściwości jego elementów (obiektów graficznych). Właściwości tych elementów są przechowywane w odpowiednich w strukturze o nazwie handles. Struktura ta zawiera uchwyty do wszystkich elementów GUI. Może ona zawierać także dane użytkownika służącą do przekazywania danych między wywołaniami wstecznymi dla różnych elementów GUI. 7/21
W pierwszej kolejności należy zdefiniować wartości właściwości Tag użytego obiektu GUI. Wartość właściwości Tag jest bowiem wykorzystywana do automatycznego tworzenia funkcji związanych z wywołaniami wstecznymi dla danego obiektu (np. wartość_tag_callback) oraz do aktualizacji struktury handles (dodanie elementu/pola struktury dla każdego nowo utworzonego obiektu wg schematu handles.wartość_tag) co pozwala na łatwe pobieranie/modyfikowanie wartości właściwości użytych obiektów za pomocą funkcji get i set. Określanie i modyfikację wartości właściwości obiektów umożliwia inspektor właściwości (Property Inspector) (Rys. 7). Rysunek 7: Okno inspektora właściwości obiektu (Property Inspector) Okno inspektora właściwości dla danego obiektu można otworzyć wykorzystując jedną z poniższych możliwości: kliknąć obiekt dwukrotnie kliknąć przycisk na pasku narzędzi GUIDE Layout Editor (edytora Layuot) z menu View wybrać opcję Property Inspector z lokalnego menu kontekstowego wywołanego prawym przyciskiem myszy wybrać opcję Property Inspector. Uruchomienia wykonanego projektu można dokonać albo wybierając opcję Run z menu Tools, albo naciskając przycisk na pasku narzędzi GUIDE Layout Editor. GUI jest zapisywane w dwóch plikach, pliku.m i pliku.fig. W m-pliku zawarty jest kod GUI (programu), natomiast w fig-pliku zawarta jest struktura GUI. 8/21
1. Postępując zgodnie z poniższymi instrukcjami utwórz graficzny interfejs (1) Uruchom aplikację GUIDE wybierając puste GUI (Blank GUI (Default)). (2) Za pomocą Inspektora Właściwości ustal wielkość otwieranego okna na 10 15 cm. W tym celu najpierw określ nową wartość dla właściwości Units obszaru okna graficznego (z kratką linii siatki) na centymetry - centimeters (Rys. 8). Następnie w zakładce właściwości Position zmodyfikuj wartości pól: width na 15 oraz height na 10. (Zatwierdzenie wartości odbywa się klawiszem ENTER) (Rys. 9). (3) Zamknij okno Inspektora Właściwości. (4) Wstaw osie układu współrzędnych (Axes) i przycisk polecenia (Push button) (Rys. 10). (5) Otwórz okno Inspektora Właściwości dla obiektu Axes. (6) Zmień wartości właściwości: Tag na 'Osie', Units na centymetry wartości właściwości Position: wielkość wykresu na 10x6 (jak w p. b) i pozycje jego lewego dolnego rogu na: x=1, y=3 (w stosunku do lewego dolnego rogu obszaru tworzonego interfejsu) (Rys. 11). (7) Otwórz okno Inspektora Właściwości dla obiektu Push Button (mając otwarte okno inspektora właściwości wskaż kursorem myszy na właściwy element interfejsu). (8) Zmień wartości właściwość: Tag na 'Push_Rysuj', a String na 'Rysuj'. Dzięki temu po włączeniu GUI nasz przycisk będzie miał etykietę 'Rysuj' (Rys. 12). (9) Jeśli to potrzebne, zmień pozycję obiektu Push Button (skorzystaj z inspektora właściwości lub przesuń korzystając z myszy) tak, aby nie kolidował on z obiektem Axes (Rys. 13). (10) Zamknij okno Inspektora Właściwości elementów GU. (11) Uruchom aplikację. MATLAB zada pytanie, czy chcemy zapisać zmiany. Bez zapisania zmian nie uda się uruchomić GUI. (12) Zapisz gui w pliku o pierwsze_gui.fig. M-plik o nazwie o tej samej nazwie co nazwa plik.fig zostanie utworzony automatycznie. Pliki zostaną zapisane w bieżącym katalogu. Wspólnie tworzą one informacje dla MATLAB'a dotyczące wyglądu i funkcjonowanie GUI. M-plik zostanie automatycznie otwarty w Oknie Edytora. Uruchom GUI (albo uruchamiając jego m-plik, albo w oknie edytora Layout narzędzia GUIDE). Przyciśnij przycisk 'Rysuj'. Czy coś się dzieje? Przyciśnięcie przycisku 'Rysuj' nie powoduje żadnej reakcji, ponieważ nie została określona akcja dla jego wywołania wstecznego. (13) Zamknij okno uruchomionego GUI i przejdź do m-pliku w Oknie Edytora. (14) Znajdź funkcję o nazwie Push_Rysuj_Callback (Rys. 15). (15) Ustaw kursor pod linią definicji funkcji i jej komentarzami. (16) Wpisz polecenie: peaks(12). Pamiętaj, że wpisanie polecenia bez średnika spowoduje wyświetlenie zwracanych wartości w Oknie Poleceń MATLAB. (17) Zapisz m-plik. Ponownie uruchom GUI. W tym celu możesz uruchomić jego jego m-plik. Przyciśnij przycisk 'Rysuj'. Czy coś się stało? 9/21
Rysunek 8: Ustalenie wartości właściwości Units na centymetry centimetrs Rysunek 9: Ustalenie rozmiaru okna GUI 10/21
Rysunek 10: Wstawienie osi układu współrzędnych (Axes) i przycisku polecenia (Push Button) Rysunek 11: Zmiana właściwości obiektu Axes 11/21
Rysunek 12: Zmiana właściwości obiektu Push Button Rysunek 13: Zmiana położenia elementu Push Button 12/21
Rysunek 14: Okno uruchomionego interfejsu graficznego Rysunek 15: Funkcja Push_Rysuj_Callback 13/21
18. Zamknij okno GUI i ponownie przejdź do okna edytora Layout narzędzia GUIDE. Dodajmy teraz suwak, który umożliwi ustalenie wartości parametru wejściowego n dla polecenia peaks(n). W tym celu: 19. Wstaw element Slider (Rys. 16). 20. Korzystając z Inspektora Właściwości ustal wielkość suwaka na: height = 0.45 i width = 10 cm (pamiętaj o zmianie jednostek - Units - na centymetry). 21. Ustaw w jednej linii wykres i obiekt Slider. W tym celu z menu Tools wybierz Grid and Rulers (Rys. 17). 22. Następnie, w otwartym oknie zaznacz opcję Show rulers (Rys. 17). 23. Z lewej krawędzi okna edytora Layout wyciągnij linijkę. Dociągnij ją do lewego boku osi układu współrzędnych wykresu, tworząc prowadnice, do której można wyrównywać obiekty (Rys. 18). 24. Dociągnij obiekt Slider do utworzonej (niebieskiej) linii (Rys. 18). 25. Zmień wartość właściwość Tag obiektu Slider na 'Suwak'. 26. Zmień wartości właściwości Min i Max na 2 i 50, odpowiednio. Dzięki temu wartości odpowiadające położeniu suwaka będą się zawierały w podanym zakresie (pomiędzy Min i Max). Domyślnie są to wartości od 0 do 1. 27. Zmień wartość właściwości Value. Jest to wartość, którą przyjmuje suwak po uruchomieniu GUI. Domyślnie jest to 0. Ponieważ zero jest poza aktualnym zakresem wartości naszego suwaka, musimy ja zmienić. Ustaw najmniejszą możliwą wartość, tzn. 2. 28. Zamknij okno Inspektora Właściwości. 29. Zapisz GUI (w oknie edytora Layout). Rysunek 16: Dodanie suwaka 14/21
Rysunek 17: Aktywowanie linijek Rysunek 18: Linijka pionowa (niebieska linia po lewej stronie) 15/21
30. Przejdź w m-pliku, do funkcji Suwak_Callback. Funkcja get(hobject,'value') zwróci aktualną wartość suwaka (w formacie double). Wartość tę należy zapamiętać w strukturze handles, tak aby można ją było wykorzystać w momencie przyciśnięcia przycisku Rysuj jako parametr wejściowy dla polecenia peaks(n). W ciele funkcji Suwak_callback wpisz handles.suwakwrt=get(hobject,'value'). Dzięki temu w strukturze handles w polu o nazwie suwakwrt będzie zapisana wartość odpowiadająca aktualnej pozycji suwaka. Następnie musimy zapisać (odświeżyć) strukturę handles. Odbywa się to za pomocą polecenia guidata(hobject, handles) (Rys. 19) Uwaga: Wszelkie zmienne Wspólne dla kilku funkcji zawartych w m-pliku GUI powinny być przechowywane w strukturze handles, a ich wartości odświeżane za pomocą polecenia guidata(hobject, handles). To umożliwi wykorzystywanie tych zmiennych w obrębie całego m-pliku, a w przyapdku korzystania w wartości właściwości elementów GUI, unikniemy konieczności ciągłego odwoływania się do nich za pomocą funkcji set i get.!!! 31. Przejdź ponownie do funkcji Push_Rysuj_Callback. Przed wywołaniem funkcji peaks przypisz wartość właściwości Value obiektu Suwak zapisaną w strukturze handles (jako pole SuwakWrt) do zmiennej z. Jednocześnie ogranicz wartość zmiennej z do wartości całkowitych korzystając z polecenia floor: z=floor(handles.suwakwrt) Następnie zmodyfikuj wywołanie funkcji peaks tak, aby rysowała peaks(z)zamiast peaks(12)(rys. 20). 32. Zapisz m-plik. Uruchom GUI. Naciśnij przycisk Rysuj. Czy coś się stało? A teraz, przesuń suwak, a następnie naciśnij przycisk 'Rysuj'. Czy teraz udało się uzyskać wykres? Później dowiemy się dlaczego. Na razie zamknij GUI. 33. Przejdź ponownie do okna edytora Layout. Jeśli zachodzi taka potrzeba zmień pozycję suwaka w kierunku pionowym tak, aby nie przysłaniał on opisu osi wykresu. 34. W oknie Layout dodaj pole tekstowe Static Text, które będzie zawierało wartość suwaka. Pole wstaw mniej więcej w połowie długości suwaka pod nim (Rys. 21). 35. Zmień właściwość Tag obiektu Static Text na Wartosc_Suwaka i usuń wartość właściwości String. 36. Zapisz GUI (w oknie edytora Layout). Przy pomocy polecenia set możemy zmieniać wszystkie właściwości dostępne w Inspektorze Właściwości. Wystarczy podać identyfikator obiektu zapisanego w strukturze handles (handles.tag), nazwę właściwości (w pojedynczym cudzysłowie) i wartość końcową dla tej właściwości. 37. Przejdź do m-pliku do funkcji Suwak_Callback. Przed zapisaniem zmian do struktury handles zmień zaokrąglaną wartość właściwości String elementu Wartosc_Suwaka na łańcuch znakowy odpowiadający wartości pola SuwakWrt struktury handles (Rys. 22): set(handles.wartosc_suwaka,'string', num2str(floor(handles.suwakwrt'))) 38. Zapisz m-plik. 16/21
Rysunek 19: Funkcja Suwak_Callback Rysunek 20: Modyfikacja funkcji Push_Rysuj_Callback 17/21
Rysunek 21: Dodanie elementu Static Text Rysunek 22: Kolejna modyfikacja funkcji Push_Rysuj_Callback 18/21
Uruchom zmodyfikowane GUI. Po przesunięciu suwaka, pod suwakiem, powinna się pojawić liczba całkowita, której wartość odpowiada wartość parametru wejściowego funkcji peaks (Rys. 23). Rysunek 23: Zmiana wartości elementu Static Text po przesunięciu suwaka Bezpośrednio po uruchomieniu GUI, zanim suwak zostanie przesunięty, wartość zmiennej handles.suwakwrt jest nieokreślona. Przyciśnięcie przycisku 'Rysuj' powoduje wówczas błąd. Poprawmy to. 39. W oknie Inspektora Właściwości zmień wartość właściwości String obiektu Wartosc_Suwaka na 2. 40. Dodaj w funkcji pierwsze_gui_openingfcn (przed guidata(hobject, handles)) następujące polecenie: handles.suwakwrt=2; (Rys. 24). 41. Dzięki realizacji p. 39 i 40, w momencie uruchomienia programu od samego początku początku będzie zdefiniowana i wyświetlona początkowa wartość suwaka. 42. Zamknij okno Inspektora Właściwości i zapisz GUI. Ponownie uruchom GUI i przetestuj jego działanie. Czy program działa poprawnie? 2. Samodzielnie dodaj nowy element GUI (przycisk przełącznika bistabilnego), który będzie aktywował i dezaktywował możliwość obracania wykresu. Nazwij go 'Rotacja'. Kolejne przyciśnięcia przycisku Rotacja powinny przełączać (włączać/wyłączać) możliwość obracania wykresu. W m-pliku wpisz odpowiedni kod. WSKAZÓWKA: do implementacji rotacji wykresu możesz użyć wbudowanej funkcji MATLAB'a rotate3d. 3. Zapewnij zachowanie bieżącego położenia/orientacji osi układu współrzędnych wykresu po kolejnym naciśnięciu przycisku Rysuj. 19/21
WSKAZÓWKA: w cel ustalenia lub zmiany orientacji układu współrzędnych wykresu można skorzystać np. z właściwości View obiektu Axes. Rysunek 24: Inicjalizacja pola suwakwrt struktury handles 20/21
Sprawozdanie. Elementy programowania obiektowego. Graficzny Interfejs Użytkownika (GUI). L.p. Punkt cw./ L. punktów Imię i nazwisko Grupa Realizacja/wynik Data Uwagi prowadzącego 1/3 2 / 0,5 3/2 21/21