Grafische Benutzeroberflächen mit Objektorientierter Programmierung

In diesem Beitrag möchte ich Ihnen gerne zeigen, wie Sie die von MATLAB und GUIDE vorgegebenen Struktur zur Erzeugung von grafischen Benutzeroberflächen (GUI = Graphical User Interface) umgehen können und stattdessen eine Klasse zur Steuerung Ihrer Benutzeroberfläche nutzen können. Diese Vorgehensweise bietet aus meiner Sicht große Vorteile bei der Umsetzung größerer Projekte mit grafischen Benutzeroberflächen, da sie später die Möglichkeit haben die Nutzeroberfläche mit sehr geringem Aufwand zu ersetzen.

Zur Demonstration soll ein einfaches Beispiel mit einem Popupmenu und einem statischen Textfeld dienen.

„Klassische“ Implementierung mit GUIDE

Zuerst erzeugen wir über „New“ -> „Graphical User Interface“ -> „Blank GUI“ eine leere Benutzeroberfläche. In diese fügen wir ein Objekt vom Typ Pop-Up Menu und ein Objekt vom Typ Stacic Text ein:

Bildschirmfoto 2016-02-04 um 20.25.02

Da es mir besser gefällt, setzen wir die Eigenschaft „HorizontalAlignment“ des statischen Texts noch auf „left“ (über Doppelklick auf das Textfeld). Nach Speichern der Nutzeroberfläche unter dem Namen hansIsstWurst.fig wird automatisch die MATLAB-Datei hansIsstWurst.m erzeugt. Diese Datei können wir schon starten, aber es wird nicht viel passieren:

Bildschirmfoto 2016-02-04 um 20.33.08

Wir füllen nun die Benutzeroberfläche mit Leben. Nach Doppelklick auf das Pop-Up Menu in GUIDE klicken wir auf den angedeuteten Text neben der Eigenschaft „String“:

Bildschirmfoto 2016-02-04 um 20.37.11

In das daraufhin erscheinende Textfeld tragen wir folgendes ein:

Bildschirmfoto 2016-02-04 um 20.40.14

Die Eigenschaft „String“ des Textfeldes ändern wir auf die gleiche Weise in einen leeren String.

Jetzt müssen wir dem Pop-Up Menu noch ein Verhalten bei Änderung zuweisen. Wir klicken dafür mit der rechten Maustaste auf das Pop-Up Menu und dann auf „View Callbacks“ -> „Callback“:

Bildschirmfoto 2016-02-04 um 20.45.27

Wir gelangen dadurch in den Editor auf die Funktion „popupmenu1_Callback“. In diese Funktion fügen wir nun folgenden Text ein:

function popupmenu1_Callback(hObject, eventdata, handles)
% hObject    handle to popupmenu1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
 
% Hints: contents = cellstr(get(hObject,'String')) returns popupmenu1 contents as cell array
%        contents{get(hObject,'Value')} returns selected item from popupmenu1
contents = cellstr(get(hObject,'String'));
switch contents{get(hObject,'Value')}
    case 'Hans'    
        set(handles.text1,'string','Hans isst Wurst.')
    case 'Wurst'
        set(handles.text1,'string','Wurst ist lecker.')
end

Jetzt gaukeln wir MATLAB noch vor, dass das Pop-Up Menu am Beginn der Ausführung einmal gedrückt wird, indem wir folgenden Code in die Funktion „hansIsstWurst_OpeningFcn“ ein:

function hansIsstWurst_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to hansIsstWurst (see VARARGIN)

% Choose default command line output for hansIsstWurst
handles.output = hObject;

% Wir gaukeln MATLAB vor, dass das Pop-Up Menu gedrückt wurde
popupmenu1_Callback(handles.popupmenu1, eventdata, handles)

% Update handles structure
guidata(hObject, handles);

Das Programm ist nun bereit zur Ausführung. Im folgenden möchte ich Ihnen die Alternative zeigen, die für dieses kleine Projekt sicher etwas überdimensioniert ist, sich meines Erachtens aber bei größeren Projekten lohnt.

Umsetzung mit Objektorientierter Programmierung

Wir erzeugen uns zunächst wie im obigen Beispiel eine Benutzeroberfläche mit einem Pop-Up Menu und einem statischen Textfeld. Die Eigenschaft „String“ der beiden Objekte lassen wir dieses mal aber unverändert. Das soll später unsere MATLAB-Klasse erledigen.

Ziel dieser Übung ist, dass wir die von GUIDE erzeugte MATLAB-Funktion so wenig wie möglich benutzen. Deshalb entfernen wir als erstes die Callback-Funktion des Pop-Up Menus. Dafür müssen wir zunächst die Eigenschaft „Callback“ des Pop-Up Menus auf einen leeren String setzen:

Bildschirmfoto 2016-02-04 um 21.22.31

Anschließend können wir die alte Callback-Funktion löschen. Sie wird nicht weiter gebraucht.

Die Callback-Funktion soll nun in der MATLAB-Klasse implementiert werden. Wir erzeugen nun eine MATLAB-Klasse mit dem Namen „UIController.m“. In diese geben wir folgenden Inhalt ein:

classdef UIController < handle
    
    properties
        handlePopUpMenu
        handleStaticText
    end
    
    properties (Dependent)
        textPopUpMenu
    end
    
    methods
        function obj = UIController(...
                handlePopUpMenu,stringPopUpMenu,...
                handleStaticText,defaultText)
            obj.handlePopUpMenu = handlePopUpMenu;
            set(handlePopUpMenu,'string',stringPopUpMenu);
            set(handlePopUpMenu,'callback',...
                @obj.popUpMenuCallback);
            obj.handleStaticText = handleStaticText;
            set(handleStaticText,'string',defaultText);
            obj.popUpMenuCallback([],[]);
        end
        
        function wert = get.textPopUpMenu(obj)
            string = get(obj.handlePopUpMenu,'string');
            wert = string{get(obj.handlePopUpMenu,'value')};
        end
    end
    
    methods (Access = protected)
        
        function popUpMenuCallback(obj,source,event)
            switch obj.textPopUpMenu
                case 'Hans'
                    set(obj.handleStaticText,'string',...
                        'Hans isst keine Wurst.');
                case 'Wurst'
                    set(obj.handleStaticText,'string',...
                        'Wurst ist nicht lecker.');
            end
        end
    end
    
end

Jetzt müssen wir nur noch unsere Benutzeroberfläche mit der MATLAB-Klasse verbinden. Dazu fügen wir folgende Zeile in die Funktion „hansIsstKeineWurst_OpeningFcn“ ein:

function hansIsstKeineWurst_OpeningFcn(hObject, eventdata, handles, varargin)

% Choose default command line output for hansIsstKeineWurst
handles.output = hObject;

% hier übergebe ich an die Klasse UIController
handles.uiController = UIController(handles.popupmenu1,{'Hans','Wurst'},...
    handles.text1,'');

% Update handles structure
guidata(hObject, handles);

Außerdem müssen wir dafür sorgen, dass das Objekt beim Beenden des Programms wieder gelöscht wird. Dafür gehen wir über einen Rechtsklick auf eine freie Fläche der Benutzeroberfläche in GUIDE und anschließend auf „View Callbacks“ -> „DeleteFcn“. In die daraufhin erscheinende Funktion „figure1_DeleteFcn“ geben wir folgende Zeile ein:

function figure1_DeleteFcn(hObject, eventdata, handles)
delete(handles.uiController)

Hier das Ergebnis unserer Mühen:

Bildschirmfoto 2016-02-04 um 22.10.07

Das Programm macht noch immer (fast) dasselbe wie die erste Version. Wenn Sie anfangen, größere Projekte zu implementieren, werden Sie aber den Vorteil zu schätzen lernen.

Vorteile der objektorientierten Implementierung

Ich sehe bei der objektorientierten Implementierung folgende Vorteile:

  • Die Überführung des Codes in eine andere Benutzeroberfläche problemlos möglich.
  • Die Verwendung der Klasse ist auch ohne die Benutzeroberfläche möglich.
  • Wenn Sie das Objekt vom Typ UIController als MATLAB-Variable speichern, können Sie so den aktuellen Stand Ihrer Benutzeroberfläche „einfrieren“. Sie machen dann bei der nächsten Sitzung genau da weiter, wo Sie aufgehört haben.

Mehr über grafische Benutzeroberflächen und objektorientierte Programmierung in MATLAB

Wenn Sie mehr über grafische Benutzeroberflächen, objektorientierte Programmierung, die Umsetzung größerer Projekte in MATLAB sowie viele weitere Themen lernen wollen, empfehle ich Ihnen den MATLAB-Kurs in 20 Lektionen. Registrieren Sie sich noch heute und werden Sie zum MATLAB-Aufsteiger!