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

Delphi Hoofdstuk 2: Tien sommen

Op deze pagina gaan we een programma maken, waarmee er tien keer een sommetje verschijnt.
Het antwoord moet worden ingetypt, en de computer zegt dan of het goed of fout is.
Na afloop wordt er vermeld hoeveel antwoorden er goed waren.

Het scherm moet er na het eerste sommetje zó uit zien:

  2.1 Labels enz. namen geven. Textlabels naast elkaar.

Als je met dit programma wilt beginnen dan klik je op Bestand, en dan op New Project.

Een programma wordt hier een Project genoemd, dat meestal uit een aantal bestanden bestaat (als je het maakt), want elk formulier wordt in een apart bestand bewaard.
Bij de eerste programma's zullen we steeds maar één formulier gebruiken, maar als je verder komt dan zul je merken dat er voor een groot programma een heleboel verschillende formulieren nodig zijn.

Maak eerst het bovenste label, en zorg dat het opschrift (=Caption) "Vul in, druk dan op enter" wordt, en de achtergrondkleur geel.

Dan zie je in het midden een veld waar een optelsom in komt.
Ik heb daar niet één tekstveld van gemaakt, maar vijf verschillende, die tegen elkaar aan liggen, zodat het net lijkt alsof het er één is.

Maak eerst het linker tekstveld.
Zorg er voor dat er nog geen tekst in staat.
Zorg dat "enabled" op "false" staat, want het is niet de bedoeling dat er in dit tekstveld getypt kan worden.

De computer geeft aan dit tekstveld automatisch als naam "Edit1", maar die kun je veranderen.
We willen dit tekstveld eigenlijk wel de naam "Getal1" geven, maar het is de gewoonte om de naam van een tekstveld altijd met de letters txt te laten beginnen, zodat je later nog aan de naam kunt zien dat het een tekstveld is.
Daarom maken we er txtGetal1 van.

Dat doe je als volgt: klik in het propertiesvenster op Name, en typ er achter: txtGetal1

Maak nu een tekstveldje naast het eerste, er vlak tegen aan.
Zorg er voor dat er een " + " in staat, en dat "enabled" op "false" staat.

Dan maken we nog een tekstveld er naast.
Zorg er voor dat er geen tekst in staat en dat "enabled" op "false" staat. Zorg er voor dat dit tekstvenster als naam "txtGetal2" krijgt.

Maak dan nog een tekstveldje naast het vorige, er weer vlak tegen aan. Zorg er voor dat er een " = " in staat, en dat "enabled" op "false" staat.

En dan maken we nog een vijfde tekstveld er naast.
Zorg er voor dat er geen tekst in staat. Nu moet "enabled" op "true" staan, want het is de bedoeling dat in dit venstertje de uitkomst van de som wordt ingetypt.
Zorg er voor dat dit tekstvenster als naam "txtUitkomst" krijgt.

Maak onder deze tekstvensters een label, en zorg dat het opschrift "Goed zo !" wordt, en de achtergrondkleur rood.
Zorg er voor dat je de naam van dit label verandert in lblGoedzo; zoals je ziet zorgen we er voor dat de beginletters lbl worden !

Vervolgens moet er nog een "Button" worden getekend, naast het "Goedzo"-label.
En het opschrift daarvan moet "verder !" zijn.
Zorg er voor dat de naam van deze knop (of button) "cmdVerder" wordt.
(we zetten de letters cmd van CommandButton voor het woord Verder)

Het is de bedoeling dat, als er op deze knop wordt geklikt, de volgende som verschijnt.

  2.2. Objecten onzichtbaar maken.

Als je het programma start moet er eigenlijk direkt een sommetje staan.
En er moet nog niet "Goed zo !" onder staan, dat mag pas als het sommetje goed is gemaakt.
En er mag ook nog geen "Verder !" onder staan, dat moet ook pas gebeuren als het sommetje is gemaakt.

Klik eerst maar eens op een lege plek in het formulier. En ga dan naar het properties-venster.
Dan kun je aangeven hoe het totale formulier er uit moet zien.

Je kunt bijv. een andere achtergrondkleur nemen.
Je kunt ook het opschrift veranderen: klik op Caption, en vul als opschrift in: SOMMEN
Je ziet direkt in de titelbalk van het formulier ook "SOMMEN" verschijnen.

Dubbelklik nu op een lege plek in het formulier.
Dan krijg je een venster, waarin je programmaregels kunt intypen die slaan op het formulier.
De kop is: procedure TForm1.FormCreate(Sender: TObject);
(misschien is het bij jouw Form2, dat hangt ervan af of je het project in een nieuwe map hebt opgeslagen of niet)
Dan kun je aangeven wat er moet gebeuren als het formulier geladen wordt, en dat is direkt als het programma start.


Zorg er voor dat er het volgende staat:

procedure TForm1.FormCreate(Sender: TObject);

begin
lblGoedzo.visible := false;
cmdVerder.visible := false;

end;

Dat heeft tot gevolg dat het label met "Goed zo !" onzichtbaar is in het begin en dat de knop met "Verder !" onzichtbaar is in het begin.

  2.3. Random-getallen.

Als het programma start moet er direkt een sommetje op het scherm verschijnen.
De opdrachten daarvoor moeten dus ook in de procedure TForm1.FormCreate worden gezet. En wel onder de opdrachten lblGoedzo.visible := false; en cmdVerder.visible := false;

Door de opdracht g1 := RANDOM(100); wordt g1 een willekeurig geheel getal kleiner dan 100. Het kan dan dus 0, 1, 2, ... , 99 zijn.
g1 := RANDOM(90) + 10; levert een getal tussen 10 en 100 op.

Om er voor te zorgen dat dat getal in de eerste tekstbox wordt gezet moet je de volgende opdracht geven:
txtGetal1.Text := IntToStr(g1); (want we hadden aan het eerste tekstveld de naam "txtGetal1" gegeven.)

De variabele g1 moet ook worden "gedeclareerd", en de opdracht daarvoor is:
var g1:integer;
En die opdracht moet bovenaan in de procedure staan.
Ook in het derde tekstveld moet een willekeurig getal komen, dat geven we aan met g2.
Verder geven we het aantal sommetjes, dat geweest is, met "aantal" aan.
Maar die variabele declareren we niet in deze procedure. Waarom niet, daarover straks.

In totaal ziet de procedure, die direkt bij het starten moet worden uitgevoerd, er als volgt uit:

procedure TForm1.FormCreate(Sender: TObject); 
var g1, g2 : integer;

begin
   lblGoedzo.visible := false;
   cmdVerder.visible := false;
   Randomize;
   g1 := RANDOM(90) + 10;
   txtGetal1.Text := IntToStr(g1); 
   g2 := RANDOM(90) + 10;
   txtGetal2.Text := IntToStr(g2);
   aantal := 1;
end;

  2.4 Het antwoord controleren.

Wat moet er gebeuren als het antwoord is ingetypt ?
Dan moet er o.a. gecontroleerd worden of het antwoord goed is.
Daar moet programma-code voor worden ingevoerd, op de volgende manier:

Dubbelklik op het tekstvenster, waarin het antwoord getypt moet worden.
(klik eerst op het tabblad Design, rechtsonder in het codevenster, dan komt het ontwerpvenster weer in beeld).
Dan verschijnt er een programmavenster voor de edit-box voor het antwoord, die heet txtAntwoord.
Op de eerste regel staat procedure TForm1.txtUitkomstChange(Sender: TObject);

Deze procedure moeten we echter niet hebben, we moeten een procedure hebben die op Keypress reageert.
Klik op de edit-box voor het antwoord, en ga naar de Object Inspector met de properties. Klik (bovenaan) op het tabblad Events, dan kun je uit verschillende events kiezen. Klik op OnKeyPress, en klik op het pijltje er achter. Daar staat nog niets. Vul daar in: txtAntwoordKeyPress (je mag eventueel ook een andere naam voor de procedure bedenken, maar het is wel verstandig een logische naam te gebruiken), en druk op enter.



Dan springt de cursor naar het programmavenster, en daar staat de kop van een nieuwe procedure:
procedure TForm1.txtAntwoordKeypress(Sender: TObject; var Key: Char);
Deze procedure wordt uitgevoerd zodra er op een toets wordt gedrukt in het antwoord-tekstvenster.
Onder de declaratieregels typ je het volgende: If (Key = chr(13)) Then begin
en onder de laatste regel typ je: End;
In plaats van If (Key = chr(13)) Then begin mag je ook typen: If (Key = #13) Then begin

Dan kun je intypen wat er moet gebeuren als er in dat venster op een bepaalde toets is gedrukt.

We gaan er van uit dat, nadat het antwoord is ingetypt, er op de entertoets wordt gedrukt, en die heeft ASC-code 13.
In die procedure moet dan het volgende staan :

procedure TForm1.txtUitkomstKeyPress(Sender: TObject; var Key: Char);
var g1, g2, u: Integer;

begin  
If (Key = chr(13)) Then
begin
   g1 := StrToInt(txtGetal1.Text);
   g2 := StrToInt(txtGetal2.Text);
   u := StrToInt(txtUitkomst.Text);
   lblGoedzo.Visible := True;
   cmdVerder.Visible := True;
   txtUitkomst.Enabled := False;
   If (u = g1 + g2) Then
   begin
     aantalgoed := aantalgoed + 1;
     lblGoedzo.Caption := 'Goed zo !';
   end
   Else
   begin
      lblGoedzo.Caption:='Nee, het juiste'+Chr(13)+'antwoord is '+IntToStr(g1+g2);
   end;
end;
end;

Wat betekent dit allemaal ?

Er wordt gekeken welk getal in de tekstbox txtGetal1 staat, en dat getal wordt aan de variabele g1 toegekend.
Het getal in textbox txtGetal2 wordt aan de variabele g2 toegekend, en het getal in textbox txtUitkomst wordt aan de variabele u toegekend.

Deze variabelen moeten eerst weer worden gedeclareerd.
Elke procedure wordt eigenlijk als een apart programma opgevat, en de variabelen moeten in elke procedure opnieuw worden gedeclareerd.
Behalve bij "globale variabelen", daarover straks meer.

Het tweede label (met "goed zo!") mag nu verschijnen, maar er mag natuurlijk alleen "goed zo!" op staan als het ingetypte antwoord goed was, en als het anwoord verkeerd was moet het opschrift worden: "Nee, het juiste antwoord is ...

Dus als u (dat is het ingetypte antwoord) gelijk is aan g1+g2 (dat is het antwoord dat de computer berekent, en dat is natuurlijk goed), dan moet de variabele waarin het aantal goede antwoorden bewaard wordt met één verhoogd worden.
De opdracht daarvoor is (aantalgoed := aantalgoed + 1;),
En het opschrift van het lblGoedzo-label moet worden "Goed zo!";
De opdracht daarvoor is: lblGoedzo.Caption:='Goed zo!';

Dat opschrift kun je dus ook in het programma vastleggen, en zo kun je er voor zorgen dat dat opschrift zo nu en dan verandert.

Als het antwoord verkeerd was, dan staat er als opdracht voor het opschrift van het label:
lblGoedzo.Caption:= 'Nee, het juiste' + Chr(13) + 'antwoord is ' + IntToStr(g1 + g2);

De code van de entertoets is 13, dus Chr(13) stelt eigenlijk het indrukken van de entertoets voor.
Als je dat tussen twee zinnetjes zet met plussen er tussen dan heeft dat tot gevolg dat het tweede zinnetje een regel lager komt dan het eerste zinnetje.

Zinnen of woorden aan elkaar plakken doe je met behulp van de + ("abc" + "defg" levert "abcdefg" op)

  2.5. Globale variabelen declareren.

In de procedure van de vorige paragraaf komt de variabele aantalgoed voor.
Die is niet aan het begin van die procedure gedeclareerd.
Daar is een reden voor.
Zodra een procedure is uitgevoerd worden de geheugenplaatsen, die in die procedure zijn gedeclareerd, opgeruimd.
Ze zijn gewoon weg.

Daarom moet de variabele aantalgoed ergens anders worden gedeclareerd.
En er wordt ook nog gebruik gemaakt van de variabele aantal, die wordt gebruikt voor het aantal sommetjes dat al geweest is.
De variabelen aantal en aantalgoed zijn zogenaamde "globale" variabelen, die in elke procedure gebruikt kunnen worden, zonder dat ze daar weer apart gedeclareerd hoeven te worden. Ze houden hun waarde vast.

Klik op het tabblad Code onderaan het ontwerpvenster. Dan verschijnt het codevenster
Ga dan helemaal naar boven. Daar staan een aantal programmaregels, die automatisch zijn aangemaakt.
Op de tweede regel staat interface. De eerste programmaregels hebben namelijk betrekking op de interface.
Op regel 26 en 27 staat:
var Form1: TForm1; En onder die regel, waar het formulier wordt gedeclareerd, moeten we de globale variabelen declareren. Onder die regel tik je in:
aantal, aantalgoed: Integer
Dan ziet de kop van het programma er dus als volgt uit:


  2.6. Wat moet er gebeuren als er op de knop cmdVerder geklikt wordt.

Als er op de knop cmdVerder wordt geklikt moet er een nieuw sommetje komen, tenminste als het aantal sommetjes dat geweest is, minder dan tien is.
Daarom begint het met: If (aantal < 10) Then
De regels die daarna komen kun je wel kopiëren uit de procedure TForm1.FormCreate(Sender: TObject);
Er komt dan:

procedure TForm1.cmdVerderClick(Sender: TObject);
var g1, g2 : integer;

begin
   If (aantal < 10) Then
   begin
     lblGoedzo.visible := false;
     cmdVerder.visible := false;
     Randomize;
     g1 := RANDOM(90) + 10;
     txtGetal1.Text := IntToStr(g1); 
     g2 := RANDOM(90) + 10;
     txtGetal2.Text := IntToStr(g2);
     aantal := aantal + 1;
     txtUitkomst.Text := '';
     txtUitkomst.Enabled := True;
   end
   else
   begin
    lblGoedzo.Caption := 'Je had er '+IntToStr(aantalgoed) + ' goed.' + 
                        Chr(13) + 'Tot de volgende keer !';
    cmdVerder.Visible := False;
  end;
end;

Als het aantal sommetjes al 10 was, dan is het afgelopen.
Dan krijgt het lblGoedzo-label een ander opschrift: er wordt getoond hoeveel er goed waren.
En de verder-knop wordt onzichtbaar gemaakt, zodat daar niet meer op geklikt kan worden.
Dus dan is het echt afgelopen.

  2.7. Een plaatje toevoegen.

We willen er voor zorgen dat onder de labels enz. nog een foto van de school staat.
Daarvoor moet je vier of vijf dingen doen.
  1. Je moet het plaatje declareren als TBitmap, en wel als globale variabele.
    Denk er om, je kunt op de manier die hier wordt beschreven alleen bmp-plaatjesbestanden laten zien!
    Het tonen van jpg- en gif- en png-bestanden gaat op een andere manier.
    Dus boven de regel met implementation zet je: foto: TBitmap;



  2. Er moet ruimte voor het plaatje in het geheugen worden gereserveerd, bij het openen van de Form.
    Dat gaat m.b.v. de opdracht: foto := TBitmap.Create;
    Deze opdracht moet worden geplaatst in de procedure TForm1.FormCreate(Sender: TObject);
  3. De foto moet worden ingelezen van de harde schijf, en in het geheugen worden geplaatst.
    Dat gaat m.b.v. de opdracht: foto.LoadFromFile('school.bmp');
    (Het bestand moet dan in dezelfde map als het programma staan, anders moet het pad er bij)
    Ook deze opdracht moet worden geplaatst in de procedure TForm1.FormCreate(Sender: TObject);
  4. Dan moet je een Imagebox op het formulier zetten, op de plaats waar het plaatje moet komen.
    Klik dus in de toolbox op TImage, en zet dan een imagebox op het formulier. Ga naar het properties-venster van de imagebox, en klik dan op Stretch. Zet dat op true, dan zal het plaatje dat in de picturebox wordt geplaatst automatisch passend worden gemaakt.
    Je hoeft niet beslist een imagebox te gebruiken, je kunt het plaatje ook rechtstreeks op het formulier plaatsen (als achtergrondplaatje). Zie daarvoor bij punt 6.
  5. Dan moet je er nog voor zorgen dat het plaatje in de imagebox verschijnt..
    Dat gaat m.b.v. de opdracht: Image1.Canvas.Draw(0,0,foto);
    Dan wordt het plaatje in de imagebox getekend met de linker bovenhoek op punt (0,0), dat is linksboven.
    Deze opdracht moet in de de procedure TForm1.FormCreate(Sender: TObject); worden gezet.
  6. Je kunt er ook voor zorgen dat het plaatje rechtstreeks op het formulier wordt getekend, dus zonder een imagebox te gebruiken.
    Dat gaat m.b.v. de opdracht: Canvas.Draw(0,150,foto);
    Die opdracht moet in een speciale procedure, namelijk in de procedure TForm1.FormPaint(Sender: TObject);

    De kop van die procedure maak je op de volgende manier: dubbelklik op een leeg gedeelte van het formulier. Dan komen de properties van het formulier in de Object Inspector.
    Klik (bovenaan) op het tabblad Events, dan kun je uit verschillende events kiezen. Klik op OnPaint, en klik op het pijltje er achter. Daar staat nog niets. Vul daar in: FormPaint (je mag eventueel ook een andere naam voor de procedure bedenken, maar het is wel verstandig een logische naam te gebruiken), en druk op enter.



    Dan springt de cursor naar het programmavenster, en daar staat de kop van een nieuwe procedure:
    procedure TForm1.FormPaint(Sender: TObject);
    Tik tussen begin en end de volgende opdracht: Canvas.Draw(0,150,foto);
    Dan wordt de foto getoond op het formulier met de linker bovenhoek op punt (0,150), dat is 150 pixels onder de bovenrand en dan zit de foto mooi onder de som en de labels en de knoppen.

  2.8. Afspraken over naamgeving.

De naam van een editbox laten we beginnen met de letters txt En daarna komt de "echte" naam met een hoofdletter.
Zo worden voor alle besturingselementen bepaalde beginletters (prefix genoemd) gebruikt. Welke dat zijn zie je in onderstaande tabel.
(Je hoeft je daar niet beslist aan te houden, maar het is wel handig)

besturingselementprefix
label lbl
(command)button cmd
editboxtxt
timer tmr
option button opt
listbox lst
checkbox chk

  2.9. Opgaven

Opgaven.
Maak nu opgave 2 van de oefenopgaven van delphi