Grafiske grensesnitt består av en rekke GUI elementer som kalles widgets.

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 std::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 std::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 std::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:

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()
: TDT4102::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);
}
Hvert GUI element som kan brukes i TDT4102::AnimationWindow er definert i sin egen klasse som arver fra TDT4102::Widget. GUI elementer som finnes i AnimationWindow står i tabellen nedenfor med en liten forklaring.
| Widget | Forklaring |
TDT4102::Button | Knapp som kan trykkes på |
TDT4102::TextBox | Tekstfelt som ikke kan endres av bruker |
TDT4102::TextInput | Tekstfelt som bruker kan endre |
TDT4102::DropdownList | Liste over ulike alternativer |
TDT4102::Checkbox | Checkbox for å velge et alternativ blant flere |
TDT4102::RadioButton | Radiobutton for å velge et alternativ fra en gruppe |
TDT4102::Slider | Slider for å velge en verdi i et intervall |
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.
En knapp er et GUI element som gjør noe når du klikker på den:

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 std::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 å gjøre den 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. De andre widgetsene har tilsvarende funksjoner unntatt DropdownList.
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.
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).

#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:

#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;
}
TextBox er veldig lik TextInput, den eneste forskjellen er at innholdet ikke kan endres av bruker.
#include "AnimationWindow.h"
#include "widgets/TextBox.h"
TDT4102::TextBox tbox({100, 100}, 300, 30, "Hello there!");
int main() {
TDT4102::AnimationWindow window;
window.add(tbox);
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, bruk funksjonen TDT4102::DropdownList::setOptions(std::vector<std::string> &updatedOptionsList) med en vector som inneholder de nye elementene.

#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;
}
En slider lar brukeren velge en verdi innenfor et intervall. Du ser dem bli brukt til å endre volum eller lysstyrke.
Her lager vi en slider i punktet (100,100) med bredde lik 200 piksler, høyde lik 30. De neste verdiene bestemmer hvordan slideren oppfører seg;
minsteverdien og maksverdien blir satt til hhv. 0 og 50. Neste verdien er initialveriden til slideren og den siste er hvor mye verdien endrer på seg når bruker interagerer med slideren.

#include "AnimationWindow.h"
#include "widgets/Slider.h"
TDT4102::Slider sl{{100,100},200, 30, 0, 50, 0, 2};
void callbackFunction() {
std::cout << "Current value is: " << sl.getValue() << std::endl;
}
int main() {
TDT4102::AnimationWindow window;
window.add(sl);
sl.setCallback(callbackFunction);
window.wait_for_close();
return 0;
}
Checkbox'en lar brukeren velge én eller flere uavhengige alternativer. Den brukes ofte i skjemaer, innstillinger og applikasjoner der brukeren gjør valg som ikke utelukker hverandre.

#include "AnimationWindow.h"
#include "widgets/CheckBox.h"
int main() {
TDT4102::CheckBox cb{{200, 200}, 200, 50, ""};
cb.setLabelColor(TDT4102::Color::dark_violet);
cb.setLabel("This is a checkbox");
TDT4102::AnimationWindow window;
window.add(cb);
window.wait_for_close();
return 0;
}
Radiobuttons tillater brukeren til å velge ett alternativ fra en gruppe med forhåndsdefinerte valg. I motsetning til checkboxes, hvor flere valg kan være aktive samtidig, tillater radioknapper kun ett aktivt valg om gangen innenfor samme gruppe (NB! dette må du sjekke for selv).

#include "AnimationWindow.h"
#include "widgets/RadioButton.h"
int main() {
TDT4102::RadioButton rb{{200, 200}, 200, 30, "Easy"};
TDT4102::RadioButton rb2{{200, 235}, 200, 50, "Hard"};
rb.setLabelColor(TDT4102::Color::black);
rb2.setLabelColor(TDT4102::Color::black);
TDT4102::AnimationWindow window;
window.add(rb);
window.add(rb2);
window.wait_for_close();
return 0;
}