Skip to content

Grafiske Brukergrensesnitt (GUI)

Grafiske brukergrensesnitt

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 en kurve tegnet med draw_arc funksjonen og endret farge

Callback

Et «callback» er en funksjon som kalles etter 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 "std_lib_facilities.h"
#include "AnimationWindow.h"
#include "widgets/Button.h"

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

    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 "std_lib_facilities.h"
#include "AnimationWindow.h"
#include "widgets/Button.h"

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

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

    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 "std_lib_facilities.h"
#include "AnimationWindow.h"
#include "widgets/Button.h"

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

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

    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 en kurve tegnet med draw_arc funksjonen og endret farge

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 AnimationWindow {
   public: 
    SuperManWindow();
    void superCallbackFunction();
    void fly();
   private:
    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 en AnimationWindow er definert i sin egen klasse. Det vil si at når du for eksempel ønsker å vise en knapp i vinduet, lager du en instans av TDT4102::Button klassen. I tillegg er det nødvendig å legge til knappen i vinduet ved å bruke medlemsfunksjonen:

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

Alle GUI elementer arver fra typen Widget. Widget har en funksjon for å gjemme eller vise GUI elementene:

void Widget::setVisible(bool isVisible);
Denne funksjonen blir kalt med true for å vise elementet og med false for å skjule elementet.

Knapp

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

Bilde som viser en kurve tegnet med draw_arc funksjonen og endret farge

Her er et eksempel som vises hvordan den brukes:

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

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

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

    AnimationWindow window;
    window.add(button);
    button.setCallback(buttonClicked);
    button.setButtonColor(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øren:

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 å sørge for 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(Color newColor);
void setButtonColor(Color newColor);
void setButtonColorHover(Color newColor);
void setButtonColorActive(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 musen over med setButtonColorHover og fargen på knappen når den er trykket ned med setButtonColorActive.

Tekst felt

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

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()
{
    AnimationWindow window;
    window.add(textField);
    textField.setCallback(textFieldChanged);
    window.wait_for_close();
    return 0;
}
#include "std_lib_facilities.h"
#include "AnimationWindow.h"
#include "widgets/TextInput.h"

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()
{
    AnimationWindow window;
    window.add(textField);
    textField.setCallback(textFieldChanged);
    window.wait_for_close();
    return 0;
}
#include "std_lib_facilities.h"
#include "AnimationWindow.h"
#include "widgets/DropdownList.h"

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

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

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