Skip to content

Grafiske Brukergrensesnitt (GUI)

Konstruksjon av grafiske grensesnitt

Grafiske grensesnitt består av en rekke GUI elementer som kalles widgets. Dette kan være knapper, tekstfelt eller dropdown-lister.

Bilde som viser ulike widgets; knapper, tekstfelt og dropdown-liste

Callback

Et «callback» er en funksjon som kalles etter at en spesifikk hendelse har inntruffet. Disse brukes ofte med brukergrensesnitt, for eksempel for å spesifisere hva som skal skje etter brukeren har trykket på en knapp. Hvert GUI-element lar deg definere én slik funksjon som blir kjørt etter hver interaksjon. Nøyaktig hvilken interaksjon er avhengig av GUI-elementet.

For å vise hvordan man definerer og bruker en callback funksjon, fortsetter vi med samme eksempelet som før:

#include "AnimationWindow.h"
#include "widgets/Button.h"

int main() {
    const TDT4102::Point buttonPosition {100, 100};
    const unsigned int buttonWidth = 100;
    const unsigned int buttonHeight = 40;
    const string buttonLabel = "Click me!";
    TDT4102::Button button {buttonPosition, buttonWidth, buttonHeight, buttonLabel};

    TDT4102::AnimationWindow window;
    window.add(button);
    window.wait_for_close();

    return 0;
}

Vi kan nå definere callback funksjonen. Den skal ha ingen parametere, og returnere void. Det er mulig å definere flere callback funksjoner i en enkelt fil, og navnet på funksjonene er ikke viktig. Flere GUI elementer kan ha samme callback funksjonen.

#include "AnimationWindow.h"
#include "widgets/Button.h"

void callbackFunction() {
    std::cout << "This is printed when this function is executed." << std::endl;
}

int main() {
    const TDT4102::Point buttonPosition {100, 100};
    const unsigned int buttonWidth = 100;
    const unsigned int buttonHeight = 40;
    const string buttonLabel = "Click me!";
    TDT4102::Button button {buttonPosition, buttonWidth, buttonHeight, buttonLabel};

    TDT4102::AnimationWindow window;
    window.add(button);
    window.wait_for_close();

    return 0;
}

Den siste steget er å bruke callbackFunction() funksjonen som callback av knappen vi laget tidligere. Vi gjør dette ved å bruke setCallback() funksjonen, med navn på funksjonen som vi ønsker å bruke som parameter:

#include "AnimationWindow.h"
#include "widgets/Button.h"

void callbackFunction() {
    std::cout << "This is printed when this function is executed." << std::endl;
}

int main() {
    const TDT4102::Point buttonPosition {100, 100};
    const unsigned int buttonWidth = 100;
    const unsigned int buttonHeight = 40;
    const string buttonLabel = "Click me!";
    TDT4102::Button button {buttonPosition, buttonWidth, buttonHeight, buttonLabel};

    TDT4102::AnimationWindow window;
    button.setCallback(callbackFunction);
    window.add(button);
    window.wait_for_close();

    return 0;
}

Når vi kjører dette programmet og klikker på knappen ser vi at callback funksjonen skriver ut tekst på skjermen:

Bilde som viser tekst i terminalen fra callback-funksjonen

Objekt-orienterte callback funksjoner

Dersom man ønsker å sette callback-funksjonen til en klassemetode må man bruke std::bind for å gjøre funksjonen kompatibel.

class SuperManWindow : public TDT4102::AnimationWindow {
   public: 
    SuperManWindow();
    void superCallbackFunction();
    void fly();
   private:
    TDT4102::Button flyButton;
};

void SuperManWindow::superCallbackFunction() {
    std::cout << "Thanks for clicking, im going to fly\n";
    this->fly();
    // Do something else
}

SuperManWindow::SuperManWindow()
    : AnimationWindow(50, 50, 500, 500, "Super man window"),
    flyButton{{100, 100}, 50, 50, "fly"} {
    // Here we convert the class method to a void function
    // by binding this instance of the class to the function
    flyButton.setCallback(std::bind(&SuperManWindow::superCallbackFunction, this));
    add(flyButton);
}

GUI Elementer

Hvert GUI element som kan brukes i TDT4102::AnimationWindow er definert i sin egen klasse som arver fra TDT4102::Widget. GUI elementer som støttes er TDT4102::Button , TDT4102::TextInput og TDT4102::DropdownList. Hvis du for eksempel ønsker å vise en knapp i vinduet, lager du en instans av TDT4102::Button klassen og legger den til i vinduet ved å bruke medlemsfunksjonen:

void TDT4102::AnimationWindow::add(TDT4102::Widget &widgetToAdd);

Hvis du ikke ønsker å vise knappen med en gang, kan du kalle på funksjonen setVisible(bool isVisible) med false på knapp-variabelen for å skjule elementet. Bruk true for å vise elementet.

Knapp

En knapp er et GUI element som gjør noe når du klikker på den:

Bilde som viser en knapp

Her er et eksempel som vises hvordan den brukes:

#include "AnimationWindow.h"
#include "widgets/Button.h"

void buttonClicked() {
    std::cout << "Someone clicked on me!" << std::endl;
}

int main() {
    const TDT4102::Point buttonPosition {100, 100};
    const unsigned int buttonWidth = 100;
    const unsigned int buttonHeight = 40;
    const string buttonLabel = "Click me!";
    TDT4102::Button button {buttonPosition, buttonWidth, buttonHeight, buttonLabel};

    TDT4102::AnimationWindow window;
    window.add(button);
    button.setCallback(buttonClicked);
    button.setButtonColor(TDT4102::Color::silver);
    window.wait_for_close();
    return 0;
}

Merk at vi må først inkludere headeren til TDT4102::Button klassen ved å skrive #include "widgets/Button.h" øverst i filen.

Deretter lager vi en knapp ved å instansiere TDT4102::Button klassen, som har følgende konstruktør:

TDT4102::Button(TDT4102::Point location, unsigned int width, unsigned int height, std::string label);

Her definerer TDT4102::Point location hvor knappen skal plasseres på skjermen, width og height størrelsen, og label teksten som skal vises på knappen. Vi bruker add() og setCallback() funksjonene for å sørge at knappen blir synlig i vinduet, og at det skjer noe når vi klikker på den.

Callback funksjonen blir kalt hver gang brukeren klikker på knappen.

Buttonklassen har diverse funksjoner for å endre på utseende.

void setLabel(std::string newLabel);
void setLabelColor(TDT4102::Color newColor);
void setButtonColor(TDT4102::Color newColor);
void setButtonColorHover(TDT4102::Color newColor);
void setButtonColorActive(TDT4102::Color newColor);

Du kan endre tekst og tekstfarge med setLabel og setLabelColor. Du kan endre fargen for knappen med setButtonColor, fargen når du har musepekeren over med setButtonColorHover og fargen på knappen når den er trykket ned med setButtonColorActive.

Tekstfelt

Et tekstfelt er et GUI element hvor man kan skrive inn tekst. Det er også mulig å hente ut teksten som er i tekstfelet med funksjonen TDT4102::TextInput::getText(). For å skrive til et tekstfelt bruker vi funksjonen TDT4102::TextInput::setText(std::string text).

bilde som viser textinput

#include "AnimationWindow.h"
#include "widgets/TextInput.h"

TDT4102::TextInput textField {{100, 100}, 300, 30, "This text field is small!"};

void textFieldChanged() {
    std::cout << "The text field now contains: " << textField.getText() << std::endl;
}

int main() {
    TDT4102::AnimationWindow window;
    window.add(textField);
    textField.setCallback(textFieldChanged);
    window.wait_for_close();
    return 0;
}

Tekstfeltene kan også være over flere linjer:

bilde som viser textinput over flere linjer

#include "AnimationWindow.h"
#include "widgets/TextInput.h"

TDT4102::TextInput textField {{100, 100}, 300, 150, "This text field\ncontains more than\none line of text!"};

void textFieldChanged() {
    std::cout << "The text field now contains: " << textField.getText() << std::endl;
}

int main() {
    TDT4102::AnimationWindow window;
    window.add(textField);
    textField.setCallback(textFieldChanged);
    window.wait_for_close();
    return 0;
}

Dropdown-liste har en liste med elementer som man kan velge mellom. Det valgte elementet henter vi ut med funksjonen TDT4102::DropdownList::getSelectedValue(). For å endre på elementene i lista, kall på funksjonen TDT4102::DropdownList::setOptions(std::vector<std::string> &updatedOptionsList) med en vector som inneholder de nye elementene.

bilde som viser dropdownliste

#include "AnimationWindow.h"
#include "widgets/DropdownList.h"

std::vector<std::string> options {"Hello", "There", "General", "You", "Are", "A", "Bold", "One"};
TDT4102::DropdownList list({100, 100}, 300, 30, options);

void handle() {
    std::cout << "Selected: " << list.getSelectedValue() << std::endl;
}

int main()
{
    TDT4102::AnimationWindow window;
    window.add(list);
    list.setCallback(handle);
    window.wait_for_close();
    return 0;
}