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

Delphi Hoofdstuk 7: Menu's

  7.1. Het menu van het overhoor-programma

We gaan het programma uit hoofdstuk 6 van Delphi (het woordjes-overhoor programma) zo aanpassen dat er een echt Windows-menu wordt gebruikt.
Dat moet er als volgt uitzien:



Op de menubalk staan de woorden Bestand, Bewerken en Help
Als je op Bestand klikt verschijnt er een pulldown-menu onder met de woorden Nieuw, Open, Opslaan en Afsluiten
Als je op Bewerken klikt verschijnt er een pulldown-menu onder met de woorden Overhoor, Wijzig en Voeg toe aan bestand
Die woorden zijn in het begin grijsgekleurd, ze zijn dan niet geactiveerd want je moet eerst een bestand openen voordat er overhoord kan worden, enz.
En als je op Help klikt verschijnt er het woord Info onder.

Als je op Bestand → Open klikt dan kun je een woordjes-bestand uitkiezen, en dat wordt dan ingelezen.
Als je daarna op Bewerken → Overhoor klikt (dat is dan niet meer grijsgekleurd, het is dan wel geactiveerd), dan start het overhoorgedeelte.
Als je een bestand hebt geopend dan kun je ook kiezen voor Bewerken → Wijzigen , dan worden de woordjes met de vertaling getoond in een listbox.
Als je op een woord met de bijbehorende vertaling klikt, dan verschijnt dat woord en de vertaling in het bijbehorende tekstvenster.
Dat kun je dan wijzigen.
Je moet ook op Bestand → Nieuw kunnen klikken.
Dan kun je woorden met de vertaling invoeren. En als je dan op Bestand → Opslaan klikt dan kun je een map voor het nieuwe woordjes-bestand uitkiezen, en een naam, en dan wordt het in die map en onder die naam opgeslagen.

Als je op op Bewerken → Voeg toe aan bestand dan kun je eerst een bestand openen, en dan kun je daar woorden aan toevoegen.

Verder moet je nog voor Bestand → Afsluiten kunnen kiezen, dan wordt het programma afgesloten.

Tenslotte moet je nog op Help → Info kunnen klikken, en dan verschijnt er een informatietekst.

  7.2. Het menu maken

We beginnen met het eerste formulier. Als naam van het formulier voer je in: frmMenu, en als opschrift (Caption): Overhoorprogramma met menubalk
  1. Als je een windowsmenu wilt maken dan klik je in de toolbox op TMainmenu



    Dat menuobject plaats je op het formulier. Dat zie je alleen op het ontwerpvenster, als het programma loopt ziet het er anders uit.
  2. In het propertiesvenster voor het menu-object vul je bij Name in: mnuOverhoorprogramma
  3. Dubbelklik op het menu-object op het ontwerpformulier.
    Dan verschijnt het menu-editor venster.



  4. In het propertiesvenster voor het eerste menu-onderdeel vul je bij Caption in: &Bestand
    en bij Name vul je in: mnuBestand, zodat het venster er als volgt uitziet:



    Dit heeft tot gevolg dat het woord Bestand in de menubalk zal verschijnen.
    De & voor het woord Bestand heeft tot gevolg dat de B van Bestand in het menu onderstreept wordt, en dat je dat menuonderdeel, behalve met de muis, ook kunt activeren door op Alt/B te drukken.

  5. Dan klik je in het menu-editorvenster op het lege balkje onder Bestand, dan kun je de menuonderdelen, die bij Bestand horen, invoeren.
  6. Voer eerst als opschrift Nieuw en bij naam mnuNieuw in, en kies bij Shortcut Ctrl/N uit (klik eerst op het pijltje).



  7. Klik in het menu-editorvenster op het lege balkje onder Nieuw, voer dan als opschrift Open en bij naam mnuOpen in, en kies bij Shortcut Ctrl/O uit.
  8. Klik in het menu-editorvenster op het lege balkje onder Open, voer dan als opschrift Opslaan en bij naam mnuOpslaan in, en kies bij Shortcut Ctrl/S uit.

    Voor het laatste menuonderdeel, Afsluiten, willen we een scheidingslijntje.
    Dat kun je ook invoeren in de menu-editor, je voert bij Caption dan gewoon een streepje ( - ) in, en je moet bij naam ook iets invoeren (welke naam je daar invoert doet er niet toe, als er maar iets staat)
  9. Klik in het menu-editorvenster op het lege balkje onder Opslaan, voer als opschrift - en bij naam mnuScheidingslijn in.
    Je hebt dan het volgende gekregen:



  10. Klik tenslotte in het menu-editorvenster op het lege balkje onder de scheidingslijn, voer als opschrift Afsluiten en bij naam mnuAfsluiten in, en kies bij Shortcut Ctrl/Q uit.

    We gaan nu verder met het menu-onderdeel Bewerken.
  11. Klik in het menu-editorvenster op het lege balkje naast Bestand, voer als opschrift Be&werken en bij naam mnuBewerken in.
    De & voor de w het woord Bewerken heeft tot gevolg dat de w van Bewerken in het menu onderstreept wordt, en dat je dat menuonderdeel, behalve met de muis, ook kunt activeren door op Alt/w te drukken.

  12. Klik in het menu-editorvenster op het lege balkje onder Bewerken, dan kun je de menuonderdelen, die bij Bewerken horen, invoeren.
    Voer als opschrift Overhoor en bij naam mnuOverhoor in.
  13. Klik in het menu-editorvenster op het lege balkje onder Overhoor, voer dan als opschrift Wijzig bestand en bij naam mnuWijzig in.
  14. Klik in het menu-editorvenster op het lege balkje onder Wijzig bestand, voer dan als opschrift Voeg toe aan bestand en bij naam mnuVoegtoe in.

    Tenslotte gaan we het menu-onderdeel Help nog invoeren.
  15. Klik in het menu-editorvenster op het lege balkje naast Bewerken, voer als opschrift &Help en bij naam mnuHelp in.
    De & voor de H het woord Help heeft tot gevolg dat de H van Help in het menu onderstreept wordt, en dat je dat menuonderdeel, behalve met de muis, ook kunt activeren door op Alt/H te drukken.

  16. Klik in het menu-editorvenster op het lege balkje onder Help, dan kun je de menuonderdelen, die bij Help horen, invoeren.
    Voer als opschrift Info en bij naam mnuInfo in.

    Dan zijn we klaar met de menuonderdelen
  17. Klik op het sluitvenster van de menu-editor.
Je kunt direkt uitproberen of het nu werkt. Laat het programma lopen, klik op Bestand (of druk op Alt/B), dan verschijnen de menu-onderdelen Nieuw, Open, Opslaan en Afsluiten er onder. Maar als je op één van die menuonderdelen klikt gebeurt er nog niets, want dat moet je nog programmeren.

  7.3. De programmacode bij een menuonderdeel

We gaan nu alvast de programmacode voor het menu-onderdeel Afsluiten invoeren.
Dat doe je op de volgende manier:
  • Dubbelklik in het ontwerpvenster op het menu-object. Dan verschijnt het menu-editorvenster
  • Dubbelklik in het menu-editorvenster op Afsluiten, dan verschijnt het venster voor de programmacode voor dat menu-item.
    De code om een programma te beëindigen is heel eenvoudig, voer alleen het volgende in tussen begin en end: Application.Terminate;. En rest van de regels staan er al, het wordt dus:

    procedure TfrmMenu.mnuAfsluitenClick(Sender: TObject);
    begin
          Application.Terminate;
    end;
Probeer het direkt maar uit. Laat het programma lopen, klik op Bestand en daarna op Afsluiten.
Als het goed gaat wordt het programma beëindigd, en heb je het ontwerpscherm weer in beeld.

  7.4. De interface

We zetten verder de benodigde labels, tekstboxen en buttons alvast op het formulier.
Die maken we in het begin allemaal onzichtbaar, zodat je met een leeg formulier begint waar alleen de menubalk op staat.
Maar als je dan een menukeuze hebt gemaakt dan is de interface alvast klaar.
Zorg er voor dat het er uitziet zoals hier onder.



Er zijn twee labels. Ze hebben als opschrift Nederlans woord en Vertaling, en als naam lblWoord en lblVertaling.
Achter elk van die labels staat een tekstvenster. Die hebben als naam txtWoord en txtVertaling.

Daar onder twee buttons. Ze hebben als opschrift Volgende en Stop, en als naam cmdVolgende en cmdStop.

Daar onder een label met als opschrift Goedzo, en als naam lblGoedzo.
En daar weer onder een listbox met als naam lstWoorden.

Verder nog drie icoontjes. Een icoontje voor het maken van een menu, een icoontje voor een TOpenDialog-venster , en een icoontje voor een TSaveDialog-venster. Die icoontjes zie je niet als het programma loopt. Maar de eerste hebben we al gebruikt om het menu te maken, de tweede is om een woordjesbestand uit te kiezen en in te lezen, en de derde is om een woordjesbestand op te slaan (zie de volgende paragraaf).

  7.5. TOpenDialog en TSaveDialog

Er is erg handige manier om bestanden, mappen en drives op je scherm te tonen, en wel zo dat je een bestand kunt uitkiezen om in te lezen.
Dat is met behulp van een TOpenDialog-venster.
Als je zo'n TOpenDialog-object op je formulier hebt gezet, dan wordt er niet automatisch een venster met dat object op je formulier getoond.
Als je dus de opdracht openDialog := TOpenDialog.Create(self); geeft dan wordt er een venster getoond waarin je een map uit kunt kiezen. En dan worden de bestanden uit die map getoond. Je kunt ook nog aangeven welke bestanden getoond worden.
Als je bijvoorbeeld de opdracht openDialog.Filter := 'Afbeeldingen|*.BMP';
geeft dan worden alleen de BMP-bestanden getoond, en daaronder wordt vermeld dat het om Afbeeldingen gaat.

Je kunt ook bepalen welke map als eerste wordt getoond, bijvoorbeeld als je de de volgende opdracht geeft dan wordt de actieve map als eerste getoond:
openDialog.InitialDir := GetCurrentDir;

Je wilt natuurlijk ook weten welk bestand er is uitgekozen, daarvoor kun je de volgende opdracht gebruiken:
bestand := := openDialog.FileName; zorgt er voor dat de volledige bestandsnaam + het pad in de variabele "bestand" wordt opgeslagen.

Als het TOpendialog-venster verschijnt dan moet je maar afwachten waar het verschijnt, je kunt de plaats waar het verschijnt niet aangeven.

Je hoeft je niet over foutmeldingen te bekommeren, dat wordt allemaal automatisch geregeld als je een TOpendialog-venster gebruikt.
Als bijvoorbeeld een map wordt uitgekozen waarin niet geschreven kan worden dan zorgt het programma zelf voor een foutmelding, en dan kun je een andere map uitkiezen.
Het enige waar je om moet denken is dat het TOpendialog-venster gesloten kan worden zonder dat er een bestand is uitgekozen.
Dat kan gebeuren doordat er op Cancel is geklikt, of op de sluitknop.

In het properties-venster van het commondialog-object kun je ook verschillende dingen aangeven.
Ook wat het "filter" is, daar kun je bijvoorbeeld *.BMP invoeren.

  7.6. Globale variabelen en een eigen procedure: Initialisatie.

Bij het programmeren gaan we eerst de globale variabelen declareren.
De woorden, die worden ingelezen en die worden overhoord, moeten tijdens het hele programma worden onthouden.
We gaan er van uit dat er niet meer dan 100 woorden in een bestand staan, dus we declareren:
var woord Array[1..100] of String;
Ook de vertaling van die woorden moeten tijdens het hele programma worden onthouden, dus we declareren ook nog:
var vertaling Array[1..100] of String;
.
Verder moet worden onthouden welke woorden wel, en welke woorden nog niet geweest zijn. We declareren daarom:
var geweest: Array[1..100] of Boolean;
Als bijv. geldt dat geweest(7)=false dan betekent dat dat het zevende woord nog niet overhoord is.

Verder moet ook het aantal woorden in het bestand worden onthouden, het aantal dat goed vertaald is, het woord dat aan de beurt is om te overhoren, en de menuoptie worden onthouden.

Dus boven de regel met implementation, waar ook het formulier wordt gedeclareerd, zet je de volgende regels (de eerste staat er al):

var
      frmMenu: TfrmMenu;
      // globale rij-variabelen voor de woorden, vertalingen enz.
      woord, vertaling: Array[1..100] of String;
      geweest: Array[1..100] of Boolean;
      aantalgoed, aantalgeweest, woordnr, aantalwoorden, menuoptie: integer;
      // declaratie van de file
      f:textFile;

Een eigen procedure.
We maken een eigen procedure (dus niet de event-handler van een object) en die noemen we initialisatie.
Initialisatie is iets, dat in het begin moet gebeuren.
In het begin, en elke keer als er gestopt wordt met een menuonderdeel, moeten alle objecten op het formulier onzichtbaar worden.
En de menuonderdelen Overhoor, Wijzig en Voeg toe aan bestand moeten in het begin grijsgekleurd zijn (ze zijn dan niet geactiveerd als er geen bestand geopenend is).
De opdracht om er voor te zorgen dat de optie Overhoor inactief is, is mnuOverhoor.Enabled := False;
En de opdracht om er voor te zorgen dat de optie wel actief is, is dan natuurlijk mnuOverhoor.Enabled := True;

Tik helemaal onderaan het programma, voor de afsluitende end. het volgende (eigenlijk maakt het niet uit waar de procedure staat, het mag ook wel hoger in de code, na een afsluitende end; van een procedure):

procedure TfrmMenu.initialisatie;
begin
      lblWoord.Visible := False;
      lblVertaling.Visible := False;
      lblGoedzo.Visible := False;
      txtWoord.Visible := False;
      txtVertaling.Visible := False;
      cmdVolgende.Visible := False;
      cmdStop.Visible := False;
      lstWoorden.Visible := False;
      lstWoorden.Clear;
      mnuOverhoor.Enabled := False;
      mnuWijzig.Enabled := False;
      mnuVoegtoe.Enabled := False;
      menuoptie := 0;
end;

Verder moet je nog boven de plaats waar de globale variabelen worden gedeclareerd, bij de sectie private het volgende zetten:

private
      { Private declarations }
      procedure initialisatie;

Dat heeft tot gevolg dat je overal in het programma het opdrachtwoord initialisatie; kunt gebruiken.
En als je die opdracht geeft dan worden alle opdrachten van die procedure uitgevoerd.

Elke keer als er een nieuwe keuze in het Bewerken-menu is gemaakt moeten alle objecten op het formulier zichtbaar worden.
Daar maken we ook een procedure van, met de naam maakzichtbaar, zodat je dat woord ook als opdrachtwoord kunt gebruiken.

Tik dus onder de vorige procedure het volgende in:

procedure TfrmMenu.maakzichtbaar;
begin
      lblWoord.Visible := True;
      lblVertaling.Visible := True;
      lblGoedzo.Visible := True;
      txtWoord.Visible := True;
      txtVertaling.Visible := True;
      cmdVolgende.Visible := True;
      cmdStop.Visible := True;
      lstWoorden.Visible := True;
end;

Verder moet je deze procedure ook nog declareren, dus bij de sectie private zet je het volgende (de eerste regels staan er al):

private
      { Private declarations }
      procedure initialisatie;
      procedure maakzichtbaar;

Dat heeft tot gevolg dat je overal in het programma die procedures kunt gebruiken.

De opdrachten van de procedure initialisatie moeten o.a. direkt bij de start worden uitgevoerd.

Dubbelklik dus in het ontwerpvenster ergens op een lege plek van het formulier.
Dan kun je de procedure TfrmMenu.FormCreate(Sender: TObject); invoeren.
Daar hoef je alleen maar de opdracht initialisatie; in te typen.
Dan heb je dus de volgende code:

procedure TfrmMenu.FormCreate(Sender: TObject);
begin
            initialisatie;
end;

  7.7. Nieuw bestand aanmaken met woordjes.

Als je op Bestand → Nieuw klikt dan moeten de tekstvenstertjes, waarin je de nieuwe woorden kunt invoeren, zichtbaar worden. En de labels en knoppen.
De opdracht daarvoor is: maakzichtbaar;
Het goedzo-label hoeft echter niet zichtbaar te zijn, vandaar dat we de opdracht lblGoedzo.Visible := False; toevoegen.
En we zorgen er voor dat de variabele menuoptie de waarde 1 krijgt. Daar maken we gebruik van als er op de volgende-knop wordt geklikt. Want wat er dan moet gebeuren hangt er van af waar je mee bezig bent, dus welke menuoptie je hebt gekozen.

De event-handler voor de menu-opdracht Nieuw wordt dus als volgt:
(Dubbelklik in het ontwerpvenster op het menu-object. Dan verschijnt het menu-editorvenster
Dubbelklik in het menu-editorvenster op Nieuw, dan verschijnt het venster voor de programmacode voor dat menu-item)

procedure TfrmMenu.mnuNieuwClick(Sender: TObject);
      maakzichtbaar;
      lblGoedzo.Visible := False;
      menuoptie := 1;
end;

Als je dan een woord hebt ingevuld, en de vertaling ervan, en je klikt op de Volgende-knop dan moeten de volgende programmaregels worden uitgevoerd: (dubbelklik dus in het ontwerpvenster op de Volgende-knop, dan verschijnt het programmavenster)

procedure TfrmMenu.cmdVolgendeClick(Sender: TObject);
begin
If (menuoptie = 1) Then
begin
      aantalwoorden := aantalwoorden + 1;
      If (aantalwoorden <= 100) Then
      begin
            woord[aantalwoorden] := txtWoord.Text;
            vertaling[aantalwoorden] := txtVertaling.Text;
      end;

      lstWoorden.Items.Add(txtWoord.Text + ' = ' + txtVertaling.text);
      txtWoord.Text := '';
      txtVertaling.text := '';
end;
end;

Uitleg:
  • Het aantalwoorden wordt met één vermeerderd.
  • Als het aantal woorden bijv. 7 is, dan wordt de opdracht op de zevende regel: woord[7] := txtWoord.Text;.
    Dat heeft tot gevolg dat in de variabele woord[7] het woord wordt vastgelegd dat in het eerste tekstvenster is ingevuld.
  • De volgende opdracht heeft dan tot gevolg dat in de variabele vertaling[7] het woord wordt vastgelegd dat in het tweede tekstvenster is ingevuld.
  • Maar dit gebeurt alleen als het aantal woorden kleiner dan 100 is, omdat er maar ruimte voor 100 woorden is gedeclareerd.
  • De opdracht lstWoorden.Items.Add(txtWoord.Text + ' = ' + txtVertaling.text); heeft tot gevolg dat het woord met de vertaling aan de lijst in de listbox wordt toegevoegd (het woord met de vertaling en een = ertussen worden eerst aan elkaar vastgeplakt).
  • Tenslotte worden de tekstvenstertjes leeggemaakt.

  7.8. Het bestand opslaan.

Als je op Bestand → Opslaan klikt dan verschijnt het volgende venster:



  1. Je hoeft maar één opdracht te geven om er voor te zorgen dat er zo'n venster verschijnt. Die opdracht is: saveDialog := TSaveDialog.Create(self);
    (je moet dat savedialog-venster wel eerst declareren m.b.v. de opdracht var saveDialog : TSaveDialog;)
  2. En de opdracht saveDialog.Filter := 'text files|*.txt'; heeft tot gevolg dat alleen de bestanden met de extensie txt worden getoond, en dat bij Bestandstypen staat: text files
  3. De opdracht bestandsnaam := saveDialog.FileName; zorgt er voor dat de variabele bestandsnaam de naam bevat die als bestandsnaam is ingevoerd in het venster.
  4. Door de opdracht bestandsnaam = bestandsnaam + '.txt'; wordt er automatisch de extensie .txt aan de naam vastgeplakt. Dat hoeft de gebruiker er zelf dus niet achter te typen.
  5. Het kan natuurlijk gebeuren dat de gebruiker niet in de gaten heeft dat hij de extensie er zelf niet achter hoeft te typen.
    Als hij dat wel intypt dan heeft de vorige opdracht tot gevolg dat de extensie er twee keer achter staat, omdat die er ook nog eens achter geplakt wordt. Dat moeten we voorkomen.
    Dat gebeurt met de volgende opdrachten:
    a := Pos('.',bestandsnaam);
    If (a > 0) Then bestandsnaam := copy(bestandsnaam, 1, a - 1);

    Eerst wordt gekeken of er een punt in de bestandsnaam voorkomt, en a geeft dan de plaats a waar die punt staat.
    (Als er geen punt in zit krijgt a de waarde 0)
    En bestandsnaam := copy(bestandsnaam, 1, a - 1); heeft tot gevolg dat de punt, en wat daar achter staat, wordt verwijderd uit de naam. Want de nieuwe bestandsnaam wordt het gedeelte van de naam vanaf letter 1 tot en met letter a-1, dat is de letter voor de punt.
  6. De opdracht assignFile(f,bestandsnaam); heeft tot gevolg dat het bestand gemaakt wordt.
    Maar bij het opslaan kan er van alles misgaan, daarom moeten de opdrachten die te maken hebben met het opslaan worden voorafgegaan door try. En na de opdrachten die te maken hebben met het opslaan komt nog except en daarna de opdrachten die moeten worden uitgevoerd als er iets mis gaat met het opslaan.
    Misschien komt er nog wel een foutmelding als je het programma start vanuit de IDE, maar als je het gecompileerde programma (buiten Delphi om) menubalk.exe start dan verschijnt er een venstertje met 'Het lukt niet om het bestand weg te schrijven', en daarna kun je gewoon verder met het programma.
  7. Als er geen fout optreedt dan worden de woorden met de vertaling opgeslagen in een bestand.
    De volgende opdrachten zorgen daarvoor:
    assignFile(f,bestandsnaam);
    rewrite(f);
    For i := 1 To aantalwoorden do
    begin
            writeln(f, woord[i]);
            writeln(f, vertaling[i]);
    end;
    Closefile(f);
  8. Tenslotte zorgt de opdracht initialisatie; er voor dat het formulier leeg wordt gemaakt
  9. Als eerste regel van de procedure staat nog de opdracht If (aantalwoorden < 1) Then Exit;.
    Die staat er bij omdat, als er helemaal geen woorden zijn ingevoerd, er ook niets hoeft te worden opgeslagen.
    Exit; heeft tot gevolg dat de procedure wordt verlaten, zonder dat er verder iets gebeurt.
De procedure voor het opslaan ziet er dan als volgt uit:

procedure TfrmMenu.mnuOpslaanClick(Sender: TObject);
var bestandsnaam: string;
      a, i: integer;
      // declareer de TSaveDialog variabele
      saveDialog : TSaveDialog;
begin
      if (aantalwoorden < 1) Then exit;
      // laat het SaveDialoog-venster verschijnen
      saveDialog := TSaveDialog.Create(self);
      // Geef het SaveDialoog-venster een titel
      saveDialog.Title := 'Sla het woordjesbestand op';
      // zorg er voor dat de actieve map de startmap van
      // het SaveDialoog-venster wordt
      saveDialog.InitialDir := GetCurrentDir;
      // Zorg er voor dat alleen txt-files kunnen worden opgeslagen
      saveDialog.Filter := 'text files|*.txt';
            // zorg er voor dat de extensie txt wordt
      saveDialog.DefaultExt := 'txt';
      // Als er op Opslaan, OK geklikt is, doe dan het volgende:
      if (saveDialog.Execute) then
      begin
            // leg de gekozen bestandsnaam vast in een variabele
            bestandsnaam := saveDialog.FileName;
            // geef de geheugenruimte voor het saveDialoog-venster weer vrij
            saveDialog.Free;
            a := Pos('.',bestandsnaam);
            If (a > 0) Then bestandsnaam := copy(bestandsnaam, 1, a - 1);
            bestandsnaam := bestandsnaam + '.txt';
            try
            begin
                  // er wordt een bestand met die naam aangemaakt
                  assignFile(f,bestandsnaam);
                  // de schrijfwijzer wordt aan het begin van het bestand gezet
                  rewrite(f);
                  For i := 1 To aantalwoorden do
                  begin
                        writeln(f, woord[i]);
                        writeln(f, vertaling[i]);
                  end;
                  Closefile(f);
            end
            except
            on EInOutError do
            begin
                  ShowMessage ('Het lukt niet om het bestand weg te schrijven');
                  exit;
            end;
      end;
      initialisatie;
      end;
end;
// Related commands
// Append Open a text file to allow appending of text to the end

We kunnen er heel gemakkelijk voor zorgen dat, als je op de stop-button klikt, hetzelfde gebeurt. Dat het bestand dan dus ook wordt opgeslagen. Dan moeten we er voor zorgen dat dezelfde procedure wordt uitgevoerd als hierboven. Dat doe je op de volgende manier:

Dubbelklik in het ontwerpvenster op de stop-button.
Dan kun je de procedure TfrmMenu.cmdStopClick(Sender: TObject); invoeren.
Daar hoef je alleen maar de opdracht mnuOpslaanClick(mnuOpslaan); in te typen.
Dan wordt de procedure, die hierboven staat, aangeroepen. Je moet er nog om denken dat bij de declaratie van de procedure achter de procedurenaam tussen haakjes staat (Sender: TObject). Daarom moet, als je de procedure aanroept, de 'zender' er tussen haakjes achter worden geplaatst. En dat is het object mnuOpslaan
Dan heb je dus de volgende code:

procedure TfrmMenu.cmdStopClick(Sender: TObject);
begin
      mnuOpslaanClick(mnuOpslaan);
end;

  7.9. Een bestand openen.

Dubbelklik in het ontwerpvenster op Bestand → Openen, dan kun je de procedure voor het openen van een bestand invoeren.
Voer daar de volgende code in:

procedure TfrmMenu.mnuOpenClick(Sender: TObject);
var bestandsnaam, extensie: string;
      a, i: integer;
      // declareer de TOpenDialog variabele
      openDialog : TOpenDialog;
begin
      // laat het OpenDialoog-venster verschijnen
      OpenDialog := TOpenDialog.Create(self);
      // zorg er voor dat de actieve map de startmap van
      // het OpenDialoog-venster wordt
      OpenDialog.InitialDir := GetCurrentDir;
      // Zorg er voor dat alleen txt-files worden getoond, en eventueel alle files
      OpenDialog.Filter := 'text files|*.txt|All Files|*.*';
      // Als er op de naam van een bestand geklikt is, doe dan het volgende:
      if (OpenDialog.Execute) then
      begin
            // leg het gekozen bestand vast in een variabele
            bestandsnaam := OpenDialog.FileName;
            // geef de geheugenruimte voor het openDialoog-venster weer vrij
            OpenDialog.Free;
            a := Pos('.',bestandsnaam);
            If (a > 0) Then extensie := copy(bestandsnaam, a + 1) else extensie:='';
            If (extensie <> 'txt') then
            begin
                  ShowMessage ('Je moet een bestand uitkiezen met extensie txt');
                  exit;
            end;
            try
            begin
                  // het bestand wordt geopend
                  assignFile(f,bestandsnaam);
                  // de leeswijzer wordt aan het begin van het bestand gezet
                  reset(f);
                 // We lezen alle woorden in met de bijbehorende vertalingen
                 // tot het einde van de file is bereikt

                 i:=1;
                 while not eof(f) do
                 begin
                       readln(f, woord[i]);
                       if not eof(f) then readln(f, vertaling[i]);
                       aantalwoorden:=i;
                       i:=i+1;
                  end;
                  Closefile(f);
            end
            except
            on EInOutError do
            begin
                  ShowMessage ('Het lukt niet om het bestand in te lezen');
                  exit;
            end;
      end;
      initialisatie;
      mnuOverhoor.Enabled := True;
      mnuWijzig.Enabled := True;
      mnuVoegtoe.Enabled := True;
      end;
end;

Uitleg:
  1. Je hoeft maar één opdracht te geven om er voor te zorgen dat er zo'n venster verschijnt. Die opdracht is:
    openDialog := TOpenDialog.Create(self);
    (je moet dat opendialog-venster wel eerst declareren m.b.v. de opdracht var openDialog : TOpenDialog;)
  2. En de opdracht openDialog.Filter := 'text files|*.txt| Alle files|*.*'; heeft tot gevolg dat standaard alleen de bestanden met de extensie txt worden getoond, en dat bij Bestandstypen staat: text files
    Maar je kunt bij Bestandstypen ook Alle files uitkiezen, en dan worden alle files getoond.
  3. De opdracht bestandsnaam := openDialog.FileName; zorgt er voor dat de variabele bestandsnaam de naam bevat van het bestand waarop geklikt is.
  4. Verder lijken de opdrachten veel op die bij de procedure voor het opslaan.
    Kijk daar voor verdere uitleg, en bij het vorige hoofdstuk.
  5. De laatste drie opdrachten (mnuOverhoor.Enabled := True; enz ) hebben tot gevolg dat de menuopties Overhoor, Wijzig en Voeg toe ook gekozen kunnen worden. Bij de start waren die inactief gemaakt.

  7.10. Overhoren.

De procedure voor het overhoren bevat de volgende programmaregels:

procedure TfrmMenu.mnuOverhoorClick(Sender: TObject);
      maakzichtbaar;
      cmdVolgende.Visible := False;
      lblGoedzo.Caption := 'Tik het antwoord in, druk dan op enter';
      menuoptie := 2;
      aantalgoed := 0;
      aantalgeweest := 0;
      Randomize;
      woordnr := random(aantalwoorden) + 1;
      txtWoord.Text := woord[woordnr];
      geweest[woordnr] := True;
      txtVertaling.SetFocus;
end;

Uitleg:
  • De opdracht maakzichtbaar; heeft tot gevolg dat de interface er als volgt uitziet:



  • De Volgende-knop hoeft in het begin niet zichtbaar te zijn, daarom de opdracht cmdVolgende.Visible := False;
  • De variabele woordnr bevat na de opdracht woordnr := random(aantalwoorden) + 1 een willekeurig nummer tussen 1 en aantalwoorden.
    En het woord met dat nummer verschijnt in het eerste tekstvenster
    (daar zorgt de opdracht txtWoord.Text := woord[woordnr]; voor)
  • Er wordt geregistreerd dat het woord met dat nummer geweest is d.m.v. de opdracht geweest[woordnr] := True;
  • En de opdracht txtVertaling.SetFocus; heeft tot gevolg dat de cursor in het tweede tekstvenster, waarin de vertaling moet worden getypt, wordt geplaatst.
    Anders moet de muis altijd nog worden gebruikt om in dat tekstvenster te klikken, of er moet eerst op de tabtoets worden gedrukt.
    Dat voorkom je door deze opdracht.
Als de vertaling is ingetypt, en er wordt op enter gedrukt, dan moet het antwoord worden gecontroleerd. Daar moeten we een procedure voor schrijven.
Dat doe je op de volgende manier:

Dubbelklik in het ontwerpvenster op het tekstvenster voor de vertaling, waarin het antwoord getypt moet worden.
Dan verschijnt er een programmavenster voor procedure TfrmMenu.txtVertalingChange(Sender: TObject);

Deze procedure moeten we echter niet hebben, we moeten een procedure hebben die op Keypress reageert.
Klik op de edit-box met de naam txtVertaling, 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: txtVertalingKeyPress (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 TfrmMenu.txtVertalingKeypress(Sender: TObject; var Key: Char);
Deze procedure wordt uitgevoerd zodra er op een toets wordt gedrukt in het antwoord-tekstvenster.
Onder begin, na de declaratieregels, begin je met: If (Key = chr(13)) Then
In plaats van If (Key = chr(13)) Then mag je ook typen: If (Key = #13) Then
Dan kun je invoeren wat er moet gebeuren als er in dat venster op de entertoets 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 TfrmMenu.txtVertalingKeypress(Sender: TObject; var Key: Char);
var s: integer;

begin

If (Key = chr(13)) Then
begin
      If (menuoptie = 2) Then
      begin
            If (txtVertaling.Text = vertaling[woordnr]) Then
            begin
                 aantalgoed := aantalgoed + 1;
                 lblGoedzo.Caption := 'Goed zo, je hebt '+IntToStr(aantalgoed)+' goed';
            end
            Else
            begin
                  lblGoedzo.Caption:= 'Nee, het is '+vertaling[woordnr];
            end;
            aantalgeweest := aantalgeweest + 1;
           
            lstWoorden.Items.Add(txtWoord.Text+' = '+vertaling[woordnr]);
            cmdVolgende.Visible := True;
      end;
      If (menuoptie = 3) Then
      begin
            // zie verderop................
            //............................
      end;
end;
end;

Uitleg:
Er wordt gecontroleerd of het antwoord goed was, en dat wordt in het label getoond.
De opdracht lstWoorden.AddItem txtWoord.Text & " = " & vertaling(woordnr) heeft tot gevolg dat het woord met de vertaling ook nog even in de listbox verschijnt.
En de volgende-knop verschijnt in beeld door de opdracht cmdVolgende.Visible := True;

Als er op de volgende-knop wordt geklikt, dan wordt de volgende procedure uitgevoerd:

procedure TfrmMenu.cmdVolgendeClick(Sender: TObject);

If (menuoptie = 1) Then
begin
      // zie hierboven ...................
      // .................................
End;

If (menuoptie = 2) Then
begin
      txtWoord.Text := '';
      txtVertaling.Text := '';
      If (aantalgeweest >= aantalwoorden) Then
      begin
            showmessage ('Alle woorden zijn geweest');
            initialisatie;
            Exit;
      End;
            // Er wordt net zolang om een nummer "gedobbeld" tot er
      // ��n gevonden is die nog niet geweest is
      while (geweest[woordnr] = true) do
      begin
            woordnr := random(aantalwoorden) + 1;
      end;
      // dat nummer wordt dan geregistreerd als
      // geweest zijnde, zodat het niet weer wordt gevraagd
      geweest[woordnr] := True;
      // dat woord verschijnt in de tekstbox
      txtWoord.Text := woord[woordnr];
      // de cursor wordt in het tekstvenster txtVertaling gezet
      // zodat er niet eerst in dat venster geklikt hoeft te worden
      txtVertaling.SetFocus;
      lblGoedzo.Caption := 'Tik het antwoord in, druk dan op enter';
      cmdVolgende.Visible := False;;
End;
end;

Uitleg:
De tekstvensters worden leeggemaakt.
Als alle woorden geweest zijn dan wordt dat in een messegebox getoond.
Er wordt weer een willekeurig nummer uitgezocht, maar dat moet natuurlijk wel een nummer zijn dat nog niet aan de beurt is geweest.
Het woord met dat nummer verschijnt in de bovenste editbox.
En de volgende-knop wordt onzichtbaar gemaakt.

  7.11. Toevoegen en wijzigen.

Er zijn een paar menu-opties, die we nog niet besproken hebben. Die volgen hier.

Eerst de optie "Voeg toe aan bestand".

Dat verschilt weinig van de optie "Nieuw".
Het verschil is dat bij de optie "Voeg toe aan bestand" eerst een bestand wordt ingelezen, en dat er daarna net zo verder wordt gegaan als bij de optie "Nieuw".
Deze optie kan dan ook alleen gekozen worden nadat er een bestand is geopend.
De event-handler wordt als volgt:

procedure TfrmMenu.mnuVoegtoeClick(Sender: TObject);
var i: integer;

begin
      maakzichtbaar;
      lblGoedzo.Visible := False;
      For i := 1 To aantalwoorden do
            lstWoorden.Items.Add (woord[i] + ' = ' + vertaling[i]);
      menuoptie := 1;
end;

Dan de optie "Wijzigen".

Deze optie kan ook alleen gekozen worden nadat er een bestand is geopend.
Net zo als bij de optie "Voeg toe aan bestand" worden de ingelezen woordjes in een listbox getoond.
Als je dan op een woord in de listbox klikt verschijnt dat woord in de editbox txtWoord, en de vertaling in de editbox txtVertaling.
Na een wijziging daarvan (en een druk op enter) worden de oude woorden vervangen door de nieuwe.

Er horen dus drie event-handlers bij deze optie:
  • Voor de menu-keuze.
    De ingelezen woordjes worden in een listbox getoond, en de interface wordt iets aangepast. Die is als volgt:



    De event-handler wordt als volgt:

    procedure TfrmMenu.mnuWijzigClick(Sender: TObject);
    var i: integer;

    begin
          maakzichtbaar;
          cmdVolgende.Visible := False;
          lblGoedzo.Caption := 'Selecteer het woord dat je wilt wijzigen';
          For i := 1 To aantalwoorden do
                lstWoorden.Items.Add (woord[i] + ' = ' + vertaling[i]);
          menuoptie := 3;
          lstWoorden.Selected[0] := True;
          txtWoord.Text := woord[1];
          txtVertaling.Text := vertaling[1];
    end;

  • Voor het klikken in de listbox.
    Als er op een woord in de listbox wordt geklikt dan moet het woord in de editbox txtWoord komen, en de vertaling in txtVertaling.
    De event-handler wordt als volgt:

    procedure TfrmMenu.lstWoordenClick(Sender: TObject);
    var s: integer;

    begin
    If (menuoptie = 3) Then
    begin
          s := lstWoorden.ItemIndex;
          txtWoord.Text := woord[s + 1];
          txtVertaling.Text := vertaling[s + 1];
    End;
    end;

  • Voor de invoer in de edit-box txtVertaling na een druk op enter.
    Als er een woord in de editbox is ingevoerd, en er is op enter gedrukt, dan moeten de woorden gewijzigd worden.
    De event-handler wordt als volgt:

    procedure TfrmMenu.txtVertalingKeypress(Sender: TObject; var Key: Char);
    var s: integer;

    begin

    If (Key = chr(13)) Then
    begin
          If (menuoptie = 2) Then
          // zie hierboven .................
          // ...............................
          If (menuoptie = 3) Then
          begin
                s := lstWoorden.ItemIndex;
                woord[s + 1] := txtWoord.Text;
                vertaling[s + 1] := txtVertaling.Text;
                lstWoorden.Items.Delete(s);
                lstWoorden.Items.Insert(s, txtWoord.Text + ' = ' + txtVertaling.Text);
          end;
          end;
    end;
Tenslotte de optie "Info".

De event-handler wordt als volgt:

procedure TfrmMenu.mnuInfoClick(Sender: TObject);
var info: string;

begin
      info := 'Dit programma werd geschreven door R.J. vd Beek'+Chr(10)+Chr(13);
      info := info + 'Lauwers College' + Chr(10) + Chr(13);
      info := info + 'Buitenpost';
      showmessage(info);
end;

  7.12 Opdrachten.

Opgaven.
Maak nu opgave 7 van de opgaven van Delphi