- Delphiartiklar, tips, forum, länksamling - 

      

START | DELPHI | LÄNKARGÄSTBOK 




 Forum

Grundkurs
  »Introduktion
  »Snabbguide
  »Komponenter
  »Händelser
  »Strängar
  »Räkna med Delphi   »Egna typer
  »Selektion
  »Iteration
  »Menyer
  »Funktioner
  »Arraystrukturer

Tips & Tricks
  »Nya tips
  »Blandat
  »Databaser
  »Filer
  »Forms
  »Grafik
  »Internet
  »Komponenter
  »Matematik
  »Multimedia
  »Objekt/ActiveX
  »Skrivare
  »Strängar
  »System
  »Mest lästa tips

Artiklar
  »Delphi och ADO
  »Bygga en DLL
  »Skapa en enkel rapport
  »Hantera registret
  »Enheter, units
  »Klassen TCanvas
  »Använd LookUp Controls

 Nya tips
 Lägg till tips
 Delphilänkar
 Gästbok

 



 FuzzyDizzie » Delphi » Grundkurs » Funktioner
Operativsystem: Windows 95/98/ME/2000/XP
Delphiversion: Delphi 3 eller senare
Komponenter: TEdit, TLabel, TBitBtn
  Publicerad: 2002-02-18
Läst: 4580
Röster: 9
Skribent: Staffan Berg

Rösta på artikeln

Procedurer och funktioner 

De procedurer som vi hanterat i tidigare avsnitt har alla varit händelseprocedurer som Delphi ställt i ordning en stomme till. Vi skall nu ge oss på att skapa några egna procedurer som inte nödvändigtvis behöver vara kopplade till någon komponent.

Ett exempel på en procedur
Anta att vi har tillverkat ett program som innehåller tre editeringsrutor, som vi vill tömma vid olika tillfällen. Vi skulle kunna lösa det genom att lägga till en knapp på formuläret och sedan skriva kod för detta. Men denna metod förefaller lite överarbetad. Istället löser vi detta genom att skriva en fristående procedur.

Vi börjar med att skriva in proceduren namn i formulärets Private-del. 

private
 
{ private declarations }
procedure
RensaTextrutor; //Detta lägger du till
public

  { public declarations }
end;

Vi lägger deklarationen i private-delen, därför att inga andra enheter som vi eventuellt använder oss av, skall kunna använda denna procedur. Detta är en allmän princip. Det som inte andra delar behöver känna till, skall de fortfarande vara ovetande om.

Detta räcker emellertid inte utan vi måste också tala om för kompilatorn vad proceduren skall utföra. Vi måste implementera proceduren. I enhetens implementationsdel, förslagsvis efter kompileringsdirektivet. 

implementation
 
{$R *.DFM}

procedure
TForm1.RensaTextrutor;
begin
  Edit1.Text := '';
  Edit2.Text := '';
  Edit3.Text := '';

end;

Lägg märke till att vi måste tala om för kompilatorn att detta är en procedur som är knuten till formulärtypen TForm1. Det räcker alltså inte med att bara skriva

procedure RensaTextrutor; 

Varje gång som vi nu behöver rensa de tre textrutorna räcker det med att skriva

 RensaTextrutor;

Ett exempel på en funktion
Underprogram kan också utgöras av funktioner. En funktion fungerar precis som en procedur med enda undantaget att den returnerar ett värde. Detta värde kan man lagra i en variabel, använda den i ett beräkningsuttryck, skriva ut på skärmen etc.

Observera att man i princip kan använda en funktion överallt där man annars använder en konstant. Till skillnad från en konstant, som har ett konstant värde, beräknar en funktion alltid det värde den returnerar.

Värdet som en funktion returnerar kan vara av olika datatyp. Funktionens värde måste därför deklareras vad beträffar datatypen, precis på samma sätt som man anger datatypen för en variabel.

Vi skall visa hur en funktion ser ut genom att skriva ett enkelt program där vi anger sidorna i en triangel.

Placera ut komponenter på ett formulär enligt bilden nedan.

Dubbelklicka på knappen och skriv in följande händelseprocedur.

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  a,b,c : double;
  ok : boolean;
begin
a := StrToFloat(Edit1.Text);
b := StrToFloat(Edit2.Text);
c := StrToFloat(Edit3.Text);
ok := (a+b>c) and (a+c>b) and (b+c>a);
if ok then
  Label4.caption := 'Detta kan vara sidor i en triangel'
else
  Label4.caption := 'Detta är inga triangelsidor';
end;

Kör programmet och testa olika sidor. I händelseproceduren används en logisk variabel ok. Den skall innehålla värdet av testen att sidorna utgör triangelsidor, vilket den får i satsen

ok := (a+b>c) and (a+c>b) and (b+c>a);

Anta nu att vi utvidgar vårt program till en jätteprogram. På flera ställen i programmet får vi anledning till att testa om sidorna kan vara triangelsidor. I annat fall skrivs motsatsen ut. Vi lägger då nyss skrivna procedur i en funktion istället. Så här kan en sådan funktion se ut.

private
 
{ private declarations }
procedure
RensaTextrutor; //Detta lägger du till
public

  { public declarations }
end;

implementation
 
{$R *.DFM}

function TForm1.SidorOK : boolean;
var a,b,c : double;
begin
a := StrToFloat(Edit1.Text);
b := StrToFloat(Edit2.Text);
c := StrToFloat(Edit3.Text);
SidorOK := (a+b>c) and (a+c>b) and (b+c>a);
end;

 Sedan ändrar vi proceduren för knappen på följande sätt.

procedure TForm1.BitBtn1Click(Sender: TObject);

begin
      //SidorOK ger samma värde som ok tidigare.
if SidorOK then
  Label4.caption := 'Detta kan vara sidor i en triangel'
else
  Label4.caption := 'Detta är inga triangelsidor';
end;
 

När vi nu behöver testa våra triangelsidor räcker det med att anropa funktionen med att skriva SidorOK så får vi reda på det.

I deklarationen av funktionen kallas den första satsen

function TForm1.SidorOK : boolean;

för funktionshuvudet. Det börjar med det reserverade ordet function och följs av namnet på funktionen. Därefter anges datatypen på det värde som funktionen skall returnera. Eftersom vi knutit funktionen till formulärtypen måste vi kvalificera namnet på funktionen SidorOK med TForm1

Det vanligaste felet vid funktioner är att man glömmer att returnera ett värde, dvs. man glömmer att sätta funktionsnamnet lika med det värde som skall returneras. Kompilatorn protesterar inte mot detta!

Beträffande händelseproceduren för OK-knappen behöver vi inga lokala variabler för att uföra några tester. Här överlåts alla tester till funktionen SidorOK.

Värdeparametrar till underprogram
Vi har tidigare tagit upp underprogram som använder sig av parametrar, t ex standardfunktionen Succ.

Succ returnerar efterföljaren till det den anropas med.

Label1.Caption := Succ('A'); { Ett B skrivs ut på etiketten }

Efter Succ anger vi det vi vill att Succ skall arbeta med. Till funktionen överlämnas data, ett argument, via en inkanal som här utgörs av en värdeparameter. Hur kan deklarationen tänkas se ut? Låt oss se på ett exempel, där vi begränsar Succ till att arbeta enbart med bokstäver. 

 

function Succ(x:char):char;
{Succ är deklarerat i och med att det står i funktionshuvudet.}

begin
  Inc(x);
  Succ := x;
end;

I funktionshuvudet deklareras i parentesen efter namnet på funktionen en värdeparameter x av datatypen char. Efter parentesen skriver vi ett kolon och datatypen på det värde som funktionen skall returnera.

Den datatyp som anges för parametrar måste vara deklarerad tidigare, dvs. vara en datatyp som är standard eller tidigare deklarerad i en type-deklaration. I parameterlistan får alltså inte ingå någon form av typbeskrivning.

Vid ett anrop av Succ kommer x att fungera som en inkanal, dvs ha ett värde som funktionen kan utnyttja. Alla värdeparametrar fungerar som lokala variabler som får sina värden vid anrop av underprogrammet. Man får funktionen att returnera ett värde genom att tilldela funktionsnamnet själva returvärdet, Succ := x. 



 
 
© Copyright 2005 - Staffan Berg
- Alla rättigheter förbehålles -