Informaticasite van het Sondervick College te Veldhoven                 © L.J.M van Haperen (bron : R.J. van der Beek)
 

Delphi Hoofdstuk 3. Listbox, inputbox, messagebox.

  3.1. Het formulier klaarmaken.

We willen een programma maken waarvan de interface er uitziet zoals in het venster hier onder.



  • Links heb je een zogenaamde listbox
    Daarin staan een aantal landen en er kan een land worden uitgekozen door er op te klikken.
    Kies in Delphi voor een nieuw project.
    Klik in de toolbox op de Listbox listbox, en plaats die op het formulier.
    Geef die listbox de naam lstLanden
  • Verder zijn er zes buttons, met als opschrift Geef de hoofdstad, Voeg toe, Verwijder, Maak leeg, Omhoog, Omlaag
    Plaats die zes buttons op het formulier. Zorg er voor dat ze het juiste opschrift krijgen, en geef ze de namen cmdGeefhoofdstad, cmdVoegtoe, cmdVerwijder, cmdMaakleeg , cmdOmhoog en cmdOmlaag
  • Dan zijn er nog twee labels, achter de button Voeg toe, met de opschriften land: en hoofdstad:
    Plaats die twee labels op het formulier. Zorg er voor dat ze het juiste opschrift krijgen.
  • Verder zijn er nog drie tekstvensters, achter de button Geef de hoofdstad, en achter de labels land: en hoofdstad:
    Plaats die drie tekstvensters op het formulier. Geef ze de namen txtGeefhoofdstad, txtLand en txtHoofdstad
  • Tenslotte is er nog een listbox, onder de button Voeg toe.
    Plaats die listbox op het formulier. Geef hem de naam lstHoofdsteden, en zorg er voor dat hij onzichtbaar is.
Zo, nu is de "interface" klaar.
Maar als we ergens op klikken gebeurt er nog niets. Dat moeten we nog programmeren.

  3.2. Items toevoegen aan de Listbox.

Een ListBox is een venster waarin je uit een lijstje van dingen iets kunt kiezen door het aan te klikken.
De naam van de eerste ListBox is standaard List1, en een woord ....... aan de lijst toevoegen gaat dan m.b.v. de opdracht List1.Items.Add ('.......... ');
In dat geval wordt het woord .......... onder aan de lijst toegevoegd.
Je kunt ook de volgende opdracht gebruiken: List1.Items.Insert(3,'.......... ');
In dat geval wordt het woord .......... tussengevoegd op plaats nummer 4 (de eerste krijgt nummer 0, dus nummer 3 is het vierde item).

We willen dat er, direkt als het programma start, al een aantal landen in de lijst staan.
Daar kunnen we op twee manieren voor zorgen.
  1. We kunnen bij de Properties van de listbox een aantal items invoeren. Dat doe je achter Items
    Klik op de listbox lstLanden, en klik in het properties-venster achter Items
    Klik dan op de drie puntjes, dan verschijnt er een invulvenstertje.
    Tik in: Nederland
    Druk dan op enter, en tik in: België, druk dan op enter en tik dan nog in: Frankrijk
    Klik dan op OK.
    Die drie landen verschijnen dan in de lijst op het formulier.

    Zorg er op dezelfde manier voor dat de listbox lstHoofdsteden de volgende hoofdsteden bevat: Amsterdam, Brussel en Parijs

  2. Je kunt er ook d.m.v. programmaregels voor zorgen dat er bij de start items aan de listbox worden toegevoegd.
    Dan moeten die opdrachten staan bij de procedure TForm1.FormCreate(Sender: TObject);

    Dubbelklik daarom op een lege plek in het formulier.
    Dan verschijnt het programmavenster voor procedure TForm1.FormCreate(Sender: TObject);
    (bij mij is het Form1 omdat ik Form1 en Form2 van hoofdstuk 1 en 2 in dezelfde map heb staan, misschien is het bij jou wel Form1)
    Dan kun je aangeven wat er moet gebeuren als het formulier (en dus het programma) wordt geladen, dus direkt in het begin.

    Tik het volgende in:

    lstLanden.Items.Add ('Spanje');
    lstLanden.Items.Add ('Denemarken');
    lstLanden.Selected(0) := true;
    lstHoofdsteden.Items.Add ('Madrid');
    lstHoofdsteden.Items.Add ('Kopenhagen');

    De opdracht lstLanden.Selected(0) := true; heeft tot gevolg dat het eerste woord in de lijst van de listbox wordt geselecteerd (dat is dus blauw gekleurd).
    Ze beginnen in zo'n lijst altijd te tellen bij nul, dus als je bijv. als opdracht geeft : lstLanden.Selected(2) = true dan wordt het derde woord geselecteerd !

  3.3. Items toevoegen als het programma loopt, commentaar

Het is de bedoeling dat, als je op de button Voeg toe klikt, het land dat in het bijbehorende tekstvenster staat wordt toegevoegd aan de lijst van landen, en de hoofdstad die in het bijbehorende tekstvenster staat wordt toegevoegd aan de lijst van hoofdsteden.
Hier onder zie de programmacode daarvoor, maar er zijn zogenaamde commentaarregels toegevoegd.

Als je een programma gemaakt hebt, en je bekijkt het een hele tijd later weer dan snap je soms zelf niet meer waarom je bepaalde dingen gedaan hebt.
En als iemand anders het bekijkt snapt die er meestal helemaal niets van.
Daarom is het verstandig zogenaamde commentaarregels toe te voegen aan je programma.
Dat kun je op verschillende manieren doen.
De Pascal-manier: Als je één of meer regels tussen accolades zet dan beschouwt Delphi die regels als commentaar.
De Java-manier: Als je een regel met // laat beginnen dan beschouwt Delphi die regel als commentaar.

De eventhandler (de code voor wat er moet gebeuren als er op de voegtoe-knop wordt geklikt) is als volgt:

procedure TForm1.cmdVoegtoeClick(Sender: TObject);

// als er niets is ingevuld kan er niets worden toegevoegd
If ((txtLand.text = '') Or (txtHoofdstad.text = '')) Then
      showmessage('Je moet wel een land en een hoofdstad invoeren')
Else
begin
  // voeg het land toe aan de landenlijst
  lstLanden.Items.Add (txtLand.text);
  // voeg de hoofdstad toe aan de hoofdstedenlijst
  lstHoofdsteden.Items.Add (txtHoofdstad.text);
  // maak de edit-vensters leeg
  txtLand.text := '';
  txtHoofdstad.text := '';
End;

End;

Kijk goed naar de commentaarregels, daarin staat wat er gebeurt.

  3.4. Een item uitkiezen en afdrukken in een tekstvenster.

Het is de bedoeling dat, als je op de knop Geef de hoofdstad klikt (nadat je eerst een land hebt uitgekozen in de landenlijst), de hoofdstad van het gekozen land in het bijbehorende tekstvenster verschijnt.



Daarbij moet je de volgende opdrachten gebruiken:
  • n := lstLanden.ItemIndex;
    Dat levert het nummer op van het land waarop geklikt is.
    Als er bijvoorbeeld op de bovenste geklikt is krijgt n de waarde 0, want Delphi begint bij 0 te tellen.
    En als er bijvoorbeeld op de derde geklikt wordt krijgt n de waarde 2
    Als er nergens op geklikt is krijgt n de waarde -1
  • h = lstHoofdsteden.Items[n]
    Dat levert het woord op dat op de n-de plaats staat van de hoofdstedenlijst.
    Als er bijvoorbeeld op het bovenste land geklikt is krijgt n de waarde 0, en dan bevat h de eerste hoofdstad.
    Als er bijvoorbeeld op het derde land geklikt is krijgt n de waarde 2, en dan bevat h de derde hoofdstad.
    De landen en de bijbehorende hoofdsteden moeten dus wel in dezelfde volgorde staan, anders gaat het verkeerd.
De eventhandler voor het klikken op de knop Geef de hoofdstad wordt als volgt:

procedure TForm1.cmdGeefhoofdstadClick(Sender: TObject);
var n: integer;
        h: string;

begin
// n krijgt de waarde van het nummer van het land, dat is geselecteerd
n := lstLanden.ItemIndex;
If (n > -1) Then
begin
// aan h wordt het woord toegekend dat op de n-de plaats staat van de lijst
      h := lstHoofdsteden.Items[n];
      // het land h wordt in de edit-box geplaatst
      txtGeefhoofdstad.text := h;
end
Else
begin
      // als er niets was geselecteerd heeft n de waarde -1
      // en dan wordt het volgende afgedrukt
      ShowMessage ('Je moet eerst een land selecteren!')
end;

end;

Uitleg:
n krijgt de waarde van het nummer van de landenlijst, waarop geklikt is.
Als n groter of gelijk aan 0 is dan is ergens op geklikt, en dan levert lstHoofdsteden.Items[n] de bijbehorende hoofdstad.
Die moet dan in het tekstvenster voor de hoofdstad worden geplaatst.
Als n niet groter of gelijk aan 0 is, dan is er niet op een land geklikt, dan gebeurt er wat na else staat.
Dan verschijnt er dus een messagebox met de tekst 'Je moet eerst een land selecteren!'
Denk er om: voor else nooit een puntkomma!

  3.5. Een item verwijderen.

Het is de bedoeling dat, als je op de knop Verwijder klikt (nadat je eerst een land hebt uitgekozen in de landenlijst), dat land wordt verwijderd uit de landenlijst, en ook de bijbehorende hoofdstad moet worden verwijderd.

Daarbij moet je de volgende opdrachten gebruiken:
  • n := lstLanden.ItemIndex;
    Dat levert het nummer op van het land waarop geklikt is (zie de vorige paragraaf).
  • lstLanden.Items.Delete(n);
    Die opdracht zorgt er voor dat het land met nummer n wordt verwijderd uit de landenlijst.
De eventhandler voor het klikken op de knop Verwijder wordt als volgt:

procedure TForm1.cmdVerwijderClick(Sender: TObject);
var n: integer;

begin
// n krijgt de waarde van het nummer van het land, dat is geselecteerd
n := lstLanden.ItemIndex;
If (n >-1) Then
begin
      // het land met nummer n wordt verwijderd
      lstLanden.Items.Delete (n);
      // de hoofdstad met nummer n wordt verwijderd
      lstHoofdsteden.Items.Delete (n);
end
Else
begin
      // als er niets was geselecteerd heeft n de waarde -1
      // en dan wordt het volgende afgedrukt
      ShowMessage ('Je moet eerst een land selecteren!');
end;

end;

  3.6. Een lijst leeg maken

Het is de bedoeling dat, als je op de knop Maak leeg klikt, alle landen worden verwijderd uit de landenlijst, en ook alle hoofdsteden worden verwijderd uit de hoofdstedenlijst.
Voordat dat echt gebeurt wordt er nog gevraagd of je er zeker van bent dat je alles wilt verwijderen.
Daarvoor kun je handig een speciale messagebox gebruiken.

Je moet de volgende opdrachten gebruiken:
  • lstLanden.Clear;
    Die opdracht zorgt er voor dat alle landen worden verwijderd uit de landenlijst.
  • a := MessageDlg('Ben je er zeker van dat je alles wilt verwijderen?',mtCustom, [mbYes,mbNo], 0);
    Die opdracht zorgt er voor dat er een messagebox verschijnt met een knop met Yes en een knop met No er op.
    En de mededeling in de messagebox is "Ben je er zeker van dat je alles wilt verwijderen?"
    MtCustom heeft tot gevolg dat er geen extra tekens in de messagebox staan (en dat de naam van het project in de titelbalk staat), en de laatste 0 is niet belangrijk.



    Als je dan op de knop met Yes klikt dan krijgt a de waarde 6, en als je op de knop met No klikt dan krijgt a de waarde 7.
    Meer informatie over messageboxen in de volgende paragraaf, lees dat voor verdere uitleg.
De eventhandler voor het klikken op de knop Maak leeg wordt als volgt:

procedure TForm1.cmdMaakleegClick(Sender: TObject);
var a: integer;

begin
a := MessageDlg('Ben je er zeker van dat je alles wilt verwijderen?',mtCustom, [mbYes,mbNo], 0);
// als er op Yes geklikt is heeft a de waarde 6
If (a = 6) Then
begin
      lstLanden.Clear;
      lstHoofdsteden.Clear;
end;
end;

Uitleg:
De opdracht a := MessageDlg('Ben je er zeker van dat je alles wilt verwijderen?',mtCustom, [mbYes,mbNo], 0); heeft tot gevolg dat er een messagebox verschijnt met een knop met Yes en een knop met No er op.
Als je dan op de knop met Yes klikt dan krijgt a de waarde 6, en als je op de knop met No klikt dan krijgt a de waarde 7.

De volgende opdrachten:
If (a = 6) Then
begin
          lstLanden.Clear;
          lstHoofdsteden.Clear;
end;

hebben tot gevolg dat, als er op de knop met Yes geklikt is (want dan heeft a de waarde 6) de twee lijsten geleegd worden.
En als er op de knop met No geklikt is (dan heeft a de waarde 7) gebeurt er niets, want dan is a niet gelijk aan 6

  3.7. De Messagebox en de Inputbox.

De meest eenvoudige messagebox-opdracht is bijvoorbeeld: ShowMessage("Je moet wel een land en een hoofdstad invoeren")
dan verschijnt er een berichtvenster met daarin "Je moet wel een land en een hoofdstad invoeren" en een OK-knop er onder (en de naam van het project in de titelbalk), en dan kan de gebruiker niet eerder verder dan wanneer hij of zij op OK heeft geklikt. Daarna verdwijnt het berichtvenster en kan de gebruiker weer verder. Maar zolang er niet op geklikt is kan de gebruiker niets anders, alle vensters zijn "bevroren" totdat er op het berichtvenster is gereageerd.
Hoe groot de messagebox is en waar hij verschijnt bepaalt Delphi, daar kun je zelf niets aan veranderen.
Maar er is een andere versie, waarmee je wel de plaats op het scherm kunt bepalen: ShowMessagePos

Er is ook een uitgebreidere vorm van die opdracht mogelijk, in het algemeen is de syntax van de MessageDlg-functie als volgt:
resultaat := MessageDlg (Boodschap, Style, Buttons, help-id);
Zoals je ziet zijn er vier dingen (attributen) die tussen de haakjes ingevuld moeten worden. Dat zijn:
  1. De boodschap mag uit maximaal 1024 tekens bestaan, en je kunt er voor zorgen dat er een aantal regels onder elkaar komen door + chr(13) + tussen de regels te zetten.
  2. Style : Het tweede attribuut geeft aan of er een extra teken in het venstertje verschijnt.
    Je kunt daarbij kiezen uit:
    • mtWarning (er verschijnt een uitroepteken),
    • mtConfirmation (er verschijnt een vraagteken),
    • mtError (er verschijnt een rode X),
    • mtInformation (er verschijnt een i) of
    • mtCustom ((er verschijnt geen extra teken).
  3. Met het derde attribuut wordt bepaald welke buttons in het venstertje verschijnen. De codes voor die buttons noteer je achter elkaar, met komma's er tussen, en het geheel tussen vierkante haken.
    De codes voor de verschillende buttons zijn:
    • mbYes (Yes-button),
    • mbNo (No-button),
    • mbOK (OK-button),
    • mbCancel (Cancel-button),
    • mbAbort (Abort-button),
    • mbRetry (Retry-button),
    • mbIgnore (Ignore-button),
    • mbAll (All-button),
    • mbNoToAll (No to all-button),
    • mbYesToAll (Yes to all-button),
    • mbHelp (Help-button)
    Voor een aantal combinaties kun je een speciale code gebruiken, de meest gebruikte zijn:
    mbYesNoCancel = [mbYes,mbNO,mbCancel] en mbOKCancel =[mbOK,mbCancel]
  4. Het vierde attribuut is een integer, en dat wordt alleen gebruikt bij de Help-button. Dat laten we buiten beschouwing. Meestal wordt daar een 0 neergezet, maar als er geen Help-button is maakt het eigenlijk niets uit welk getal er staat.
Voorbeeld 1:
b := MessageDlg('Dit is de boodschap',mtError, [mbYes,mbNO,mbCancel], 0);
Je mag deze opdracht ook als volgt schrijven:
b := MessageDlg('Dit is de boodschap',mtError, mbYesNoCancel, 0);
Dus mbYesNoCancel is een 'afkorting' voor [mbYes,mbNO,mbCancel]



Voorbeeld 2:
b := MessageDlg('Nu geen extra teken',mtCustom, [mbOK,mbCancel], 0);

De waarde van de variabele, die aangeeft op welke knop is geklikt (hierboven a of resultaat genoemd), is als volgt:
(En je kunt ook constanten gebruiken, die de betreffende waarde hebben. De staan onder de getallen)

OKCancelAbortRetryIgnoreYesNoAllNoToAllYesToAll
  1     2   3   4   5   6   7   8   9   10
mrOK mrCancel mrAbort mrRetry mrIgnore mrYes mrNo mrAll mrNoToAll mrYesToAll

Het drukken op de escape-toets heeft hetzelfde effect als het klikken op de cancel-knop.

Een InputBbox is net zoiets als een messagebox, met het verschil dat er in een inputbox nog tekst kan worden ingevoerd.
Als je bijv. de opdracht x := InputBox('Geef je naam', 'Dit staat in de titelbalk','xxx'); geeft dan verschijnt er een berichtvenster met daarin "Geef je naam" en daaronder een tekstvenster waarin die naam kan worden ingevoerd, en een OK-knop er onder.
Het tweede attribuut staat in de titelbalk, het derde attribuut staat alvast in het invoervenstertje.
De variabele x bevat het woord dat is ingevoerd.

  3.8. Omhoog, omlaag.

Het is de bedoeling dat, als je op de knop Omhoog klikt (nadat je eerst een land hebt uitgekozen in de landenlijst), dat land een plaats hoger komt in de landenlijst, en ook de bijbehorende hoofdstad komt een plaats hoger.
Daarmee kun je dus de volgorde van de landen (en de bijbehorende hoofdsteden) veranderen.

Het is de bedoeling dat, als je op de knop Omhoog klikt (nadat je eerst een land hebt uitgekozen in de landenlijst), dat land een plaats hoger komt in de landenlijst, en ook de bijbehorende hoofdstad komt een plaats hoger.
Daarmee kun je dus de volgorde van de landen (en de bijbehorende hoofdsteden) veranderen.

We doen het op de volgende manier:
  • Als bijvoorbeeld item nummer drie één omhoog moet, dus naar plaats twee, dan verwijderen we eerst item nummer twee (en we zorgen er voor dat we dat item wel onthouden).
    Dan staat item nummer drie automatisch op de tweede plaats.
  • En daarna voegen we op de derde plaats het oude item nummer twee in. En dan zijn we klaar.
  • Natuurlijk moeten we eerst controleren of er wel op een land is geklikt.
  • En we moeten er ook om denken dat, als het eerste land is geselecteerd, het niet omhooggeschoven kan worden.
  • Het zou ook anders kunnen: we zouden ook item nummer twee kunnen vervangen door item nummer drie (wel item nummer twee onthouden), en item nummer drie vervangen door item nummer twee.
    Dan moet je gebruik maken van ListBox1.Items[n] := 'Dit item wordt nu vervangen';, dat is de opdracht om een item in een lijst te wijzigen.
De eventhandler voor het klikken op de knop Omhoog wordt als volgt:

procedure TForm1.cmdOmhoogClick(Sender: TObject);

var n: Integer;
land, stad: String;
begin

// n krijgt de waarde van het nummer van het land, dat is geselecteerd
n := lstLanden.ItemIndex;
If (n =0) Then
begin
      ShowMessage ('Dit land kan niet omhoog!');
      // sla in dit geval de rest van de opdrachten over
      exit;
end;

If (n >-1) Then
begin
      // het land met nummer n-1 wordt in de variabele land vastgelegd
      land := lstLanden.Items[n - 1];
      // het land met nummer n-1 wordt verwijderd
      lstLanden.Items.Delete (n - 1);
      // op plaats n wordt de vorige ingevoegd
      lstLanden.Items.Insert(n, land);
      // de hoofdstad met nummer n-1 wordt in de variabele stad vastgelegd
      stad := lstHoofdsteden.Items[n - 1];
      // de hoofdstad met nummer n-1 wordt verwijderd
      lstHoofdsteden.Items.Delete (n - 1);
      // op plaats n wordt de vorige ingevoegd
      lstHoofdsteden.Items.Insert(n, stad);
end
Else
begin
      // als er niets was geselecteerd heeft n de waarde -1
      // en dan wordt het volgende afgedrukt
      ShowMessage ('Je moet eerst een land selecteren!');
End;

End;

Uitleg:
Het meeste zal wel duidelijk zijn, lees de commentaarregels goed.
Eén opdracht moet nog worden verduidelijkt:
De opdracht exit; als laatste van de regels
If (n = 0) Then
begin
        ShowMessage ('Dit land kan niet omhoog!');
        exit;
end;


Als die opdrachtregel er niet tussen stond dan zouden daarna de volgende opdrachten ook worden uitgevoerd als n gelijk is aan 0, maar dat is niet de bedoeling.
De opdracht Exit; heeft tot gevolg dat de volgende opdrachten niet worden uitgevoerd, maar dat er uit de procedure wordt gesprongen (er wordt eigenlijk naar de laatste End; gesprongen).

Het is de bedoeling dat, als je op de knop Omlaag klikt (nadat je eerst een land hebt uitgekozen in de landenlijst), dat land een plaats lager komt in de landenlijst, en ook de bijbehorende hoofdstad komt een plaats lager.

De methode die we gebruiken is vergelijkbaar met het omhoogschuiven:
  • Als bijvoorbeeld item nummer drie één omlaag moet, dus naar plaats vier, dan verwijderen we eerst item nummer vier (en we zorgen er voor dat we dat item wel onthouden).
  • En daarna voegen we op de derde plaats het oude item nummer vier in. En dan zijn we klaar.
  • Natuurlijk moeten we eerst controleren of er wel op een land is geklikt.
  • En we moeten er ook om denken dat, als het laatste land is geselecteerd, het niet omlaaggeschoven kan worden.
De eventhandler voor het klikken op de knop Omlaag wordt als volgt:

procedure TForm1.cmdOmlaagClick(Sender: TObject);

var n: Integer;
land, stad: String;
begin

// n krijgt de waarde van het nummer van het land, dat is geselecteerd
n := lstLanden.ItemIndex;
If (n = lstLanden.Items.Count -1) Then
begin
      ShowMessage ('Dit land kan niet omlaag!');
      // sla in dit geval de rest van de opdrachten over
      exit;
end;

If (n >-1) Then
begin
      // het land met nummer n-1 wordt in de variabele land vastgelegd
      land := lstLanden.Items[n + 1];
      // het land met nummer n-1 wordt verwijderd
      lstLanden.Items.Delete (n + 1);
      // op plaats n wordt de vorige ingevoegd
      lstLanden.Items.Insert(n, land);
      // de hoofdstad met nummer n-1 wordt in de variabele stad vastgelegd
      stad := lstHoofdsteden.Items[n + 1];
      // de hoofdstad met nummer n-1 wordt verwijderd
      lstHoofdsteden.Items.Delete (n + 1);
      // op plaats n wordt de vorige ingevoegd
      lstHoofdsteden.Items.Insert(n, stad);
end
Else
begin
      // als er niets was geselecteerd heeft n de waarde -1
      // en dan wordt het volgende afgedrukt
      ShowMessage ('Je moet eerst een land selecteren!');
End;

End;

Uitleg:
Er is maar één belangrijk verschil met het omhoogschuiven, namelijk de controle of er misschien op het laatste land geklikt is.
De methode lstLanden.Items.Count geeft het aantal landen in de lijst.
Maar je moet er wel om denken dat, als er bijvoorbeeld 6 landen zijn, dan heeft het laatste land nummer 5. Want er wordt begonnen te tellen bij 0.
Daarom is de index van het laatste land lstLanden.Items.Count - 1

  3.9. Opdrachten.

Opgaven.
Maak nu opgave 3 van de oefenopgaven van Delphi