Delphi - Internetes szavazógép készítése

Szavazógép 2. rész

forráskód letöltése
Cikksorozatunk mostani részében létrehozzuk a szavazógépet megvalósító komponenst és a teszt érdekében elkészítünk egy web lapot is, melyen rögtön kipróbálhatjuk annak működését. A mellékelt példaprogram üzembe helyezéséhez az alábbi lépések szükségesek:
  • A példaprogram megnyitása előtt a WebVote.pas-ban lévő komponenst telepítenie kell a Delphi alá.
  • Ha a múlt héten leírt ASWEBVOTE alias-t még nem hozta létre, akkor kérjük tegye meg. Az alias mutasson arra a könyvtárra, ahova a múlt heti cikkben megjelent Vote.dbf és VoteDet.dbf állományokat helyezte.
  • Ezek után megnyithatja a mellékelt project-et.
  • A WebVote1 komponens HtmlFile property-énél valószínűleg meg kell változtatnia az elérési útvonalat úgy, hogy az a mellékelt Htm könyvtárban lévő 1.htm állományra mutasson.
  • Fordítsa le a programot, majd helyezze el web szervere scripts könyvtárába, illetve oda, ahonnan internetes alkalmazásokat képes futtatni egy böngészőn keresztül.
  • A mellékelt Pic nevű könyvtárban található Ok.gif állományt helyezze el web szerverén egy WebVote nevű könyvtárba. Ha ettől szeretne eltérni, akkor a WebVote.pas-ban módosítania kell a forráskódot: a 127. sorban írja át az elérési útvonalat: … src="/webvote/ok.gif" …
  • Ezzel az alkalmazás kész, indítson el egy böngészőt és írja be a következőt: http://localhost/scripts/WebVote02.exe. A localhost helyett természetesen a saját web szerver nevét használja, hacsak nem magán a web szervert futtató gépen próbálja ki az alkalmazást.



Nézzük tehát miként is hozható létre a komponens és hogyan használható.

Először is helyezzünk el két TTable komponenst és rendeljük hozzá a két már meglévő táblánkat, majd kössük össze master-detail-ba őket az ID mezőjük segítségével.

A WebVote komponens a következő beállításokat igényli a használat előtt:
  • A MasterTable property-ben adjuk meg azt a TTable komponenst, mely a kérdéseket tartalmazó adatbázishoz kapcsolódik.
  • A DetailTable property-ben adjuk meg a válaszokat tartalmazó adatbázishoz kapcsolódó TTable komponens nevét.
  • A HtmlFile property-ben egy olyan HTML állományt kell megadnunk, mely tartalmazza azt a szükséges HTML kódot, mely a szavazógép megjelenítéséhez kell. Ennek pontos formátumát alább részletezzük.
  • A QuestionID property-ben adhatjuk meg, hogy hányas számú kérdést szeretnénk megjeleníteni a web lapon. Az itt megadott szám a Vote.dbf ID mezőjében található számokat takarja.


Fenti beállítások után a komponens üzemképes. Most már csak azt kell eldöntenünk, hogy milyen HTML kódot generáljon: olyat melyen a szavazatot lehet leadni egy adott kérdésre, vagy olyan, amely a leadott szavazatok eredményét mutatja.

Mindkét esetben a Content függvényt kell meghívnunk a komponensnek és paraméterként határozhatjuk meg a két lehetséges módot:
  • vrQuestion - esetén a szavazatok leadása lehetséges
  • vrResult - esetén a leadott szavazatok eredménye jelenik meg


A készítendő internetes alkalmazásunkhoz hozzunk létre egy alapértelmezett akciót és ennek eseményénél állítsuk elő a WebVote komponenssel a szükséges HTML kódot.
procedure TWebModule1.WebModule1WebActionItem1Action
         (Sender: TObject; Request: TWebRequest;
         Response: TWebResponse; var Handled: Boolean);
var
  s: string;
begin
  s:=Request.QueryFields.Values['rn'];
  if s='' then begin
    Response.Content:=WebVote1.Content(vrQuestion);
  end else begin
    WebVote1.Add(StrToInt(Request.QueryFields.Values
        ['questionid']), StrToInt(s));
    Response.Content:=WebVote1.Content(vrResult);
  end;
end;
Látható, hogy a kód két részre bontható annak függvényében, hogy kérdést vagy az eredményt kell-e megjeleníteni. Hogy ez miként történik, azt viszont a komponens működésének ismerete nélkül nem érthetjük meg, így most tekintsük át ezt.

A komponens konstruktorának futásakor létrehozunk egy TPageProducer komponenst belső használatra. Ezzel dolgozzuk majd fel a komponens HtmlFile property-ében megadott web lapot. A HTML-ben lévő címkék kicserélésének érdekében a TPageProducer komponens OnHTMLTag eseményéhez hozzárendelünk egy DoHTMLTag nevű eseménykezelő eljárást.

Amikor a komponens Content függvénye meghívásra kerül, akkor ellenőrizzük első lépésként, hogy a szükséges property-k meg lettek-e adva, majd tároljuk a paraméterként kapott feldolgozási módot (kérdés, vagy eredmény megjelenítés). Ezek után egy Locate utasítással megkeressük az adott kérdést melyet meg kell jeleníteni. Végül visszatérési értékként a TPageProducer Content függvényének értékét adjuk.

A TPageProducer feldolgozza a megadott web lapot, melyen elhelyeztünk néhány címkét. Nézzük mit is tartalmaz a mellékelt 1.htm állomány.

A lényege egy web Form, ahol az adatbevitel, vagyis a szavazat leadása történik. Itt elhelyezünk egy rejtett (hidden) mezőt, melyben eltároljuk, hogy hányadik sorszámú kérdés került megjelenítésre. Ez lesz a questionid címke.

Magát a kérdést a question címkénél helyettesítjük be, míg a lehetséges válaszokat az items címke helyére tesszük. Ezek után jön egy ok címke, ahová egy Ok gomb kerül abban az esetben, ha a kérdésre adható szavazat kerül megjelenítésre és nem az eredmény.

Végül kiírjuk, hogy az adott kérdésre hány szavazat érkezett. Ehhez tartozik az allcount címke, mely a Vote.dbf AllCount mezőjének felel meg.
<form method="get" action="/scripts/webvote02.exe" 
     style="width: 180; background-color:#E0E080; 
     padding=2; margin=12; border-width: 2; 
     border-style: outset; border-color: white">
<input type=hidden name=questionid 
      value=<#questionid>>

<div class=f8b>
<#question>
</div>

<div class=f8>
<#items>
</div>

<div align=right>
<#ok>
</div>

<div class=f8 align=center>
Össesen <#allcount> szavazat érkezett.
</div>

</form>
A WebVote komponensnek a HtmlFile property-ében megadott HTML állomány tehát mindegy, hogy mit tartalmaz, lényeg hogy a fent említett címkék benne legyenek a komponens helyes működése érdekében. Ettől kezdve viszont teljesen szabadon formázhatjuk a web lapunkat, így a szavazógép külseje teljesen egyedileg formázható.

Ezeket a címkéket tehát a belsőleg létrehozott TPageProducer komponens dolgozza fel a DoHTMLTag eljárásnál.

Itt egyszerűen ellenőrizzük, hogy az adott címke, melyet a TagString nevű paraméterben kapunk meg, mi és ennek függvényében különféle funkciókat hajtunk végre:
A question címkét kicseréljük a vote.dbf question mezőjének értékére.
Az items címkénél végigmegyünk a votedet.dbf összes rekordján, mely az aktuális kérdéshez tartozik és előállítunk egy olyan HTML <input…> beviteli eszközt, melynél minden egyes elemhez egy-egy lehetséges válasz tartozik. Ehhez az <input…>-hoz az RN nevet választjuk és értékként a votedet.dbf SUBID mezőjének értékét rendeljük, mely egy egyedi számot tartalmaz minden egyes kérdésre nézve.
A questionid címkét kicseréljük a vote.dbf ID mezőjének értékére.
Az allcount esetében szintén egy egyszerű cserét hajtunk végre, de most a vote.dbf ALLCOUNT mezőjének értékére.
Az ok címkénél egy OK gombot jelenítünk meg, de csak abban az esetben, ha éppen egy kérdést kell a szavazógépnek megjelenítenie és nem a szavazatok eredményét.
procedure TWebVote.DoHTMLTag(Sender: TObject; 
     Tag: TTag; const TagString: string; 
     TagParams: TStrings; var ReplaceText: string);
begin
  if TagString='question' then begin
    ReplaceText:=FMasterTable.FieldByName('QUESTION').Value;
  end else begin
    if TagString='items' then begin
      ReplaceText:='';
      FDetailTable.First;
      while not FDetailTable.Eof do begin
        if FActVoteResponse=vrQuestion then begin
          ReplaceText:=ReplaceText+'<input type=radio
              name=rn value='+FDetailTable.FieldByName
              ('SUBID').AsString+'> ';
        end else begin
          ReplaceText:=ReplaceText+'['+FDetailTable.
              FieldByName('COUNT').AsString+'] ';
        end;
        ReplaceText:=ReplaceText+FDetailTable.
              FieldByName('TITLE').Value+'<br>';
        FDetailTable.Next;
      end;
    end else begin
      if TagString='questionid' then begin
        ReplaceText:=FMasterTable.FieldByName('ID').AsString;
      end else begin
        if TagString='allcount' then begin
          ReplaceText:=FMasterTable.FieldByName
               ('ALLCOUNT').AsString;
        end else begin
          if (TagString='ok') and (FActVoteResponse=
                    vrQuestion) then begin
            ReplaceText:='<input border=0 type=image 
               src="/webvote/ok.gif" width=31 height=14>';
          end;
        end;
      end;
    end;
  end;
end;

Ezek után már jobban megérthetjük, hogy a Unit1.pas-ban miként működik a fent már említett rövid forráskód:
procedure TWebModule1.WebModule1WebActionItem1Action
         (Sender: TObject; Request: TWebRequest;
         Response: TWebResponse; var Handled: Boolean);
var
  s: string;
begin
  s:=Request.QueryFields.Values['rn'];
  if s='' then begin
    Response.Content:=WebVote1.Content(vrQuestion);
  end else begin
    WebVote1.Add(StrToInt(Request.QueryFields.Values
        ['questionid']), StrToInt(s));
    Response.Content:=WebVote1.Content(vrResult);
  end;
end;

Amikor egy kérdésre ad le szavazatot a felhasználó, akkor a következő web lap címzés áll elő: http://localhost/scripts/webvote02.exe?questionid=2&rn=4

Ez azt jelenti, hogy a 2-es kérdés jelent meg, amire a felhasználó a 4. választ jelölte meg. Látható, hogy a címben szerepel az RN változó, mely az adott <input…> megnevezése. Ha tehát a fenti kódban ellenőrizzük ezt, akkor eldönthetjük, hogy a kérdést kell megjeleníteni, vagy éppen egy választ kell tárolni és az eredményt megjeleníteni.

Ha nincs RN változó, akkor a WebVote1 komponens Content függvényét a vrQuestion paraméterrel hívhatjuk meg. Ekkor a komponens előállítja azt a HTML kódot, melyben megjelenik az adott kérdés és lehetőségünk van a szavazásra.

Ha van RN változó, akkor már megtörtént a szavazás az egyik kérdésre, így ennek eredményét tárolnunk kell, majd az eredmény táblázatot kell megjelenítenünk a WebVote1 komponens Content függvényének a vrResult-al való hívásához.

Amiről még nem esett szó konkrétan, az a szavazat tárolása az adatbázisokba. Amint fenti kódból látható a WebVote komponens rendelkezik egy Add eljárással. Ennek segítségével lehet egy szavazatot eltárolni, hozzáadni a többihez.

Paraméterként két számot vár: az első adja meg, hogy melyik kérdésre történt válaszadás, ez nem más mint a vote.dbf ID mezőjének értéke, míg a második paraméter azonosítja a lehetséges választ, mely a votedet.dbf SUBID mezőjének értéke lesz.

Ezek alapján az Add működése egyszerű: egy Locate utasítással megkeressük a vote.dbf-ben azt a rekordot, melynek ID mezője megegyezik a paraméterként kapott értékkel. Ha ez megvan, akkor egy újabb Locate hívással megkeressük a votedet.dbf-ben azt a rekordot, amely az adott kérdéshez tartozó adott választ tartalmazza.

Ezek után növeljük a vote.dbf ALLCOUNT mezőjének értékét, valamint a votedet.dbf COUNT mezőjének értékét.
procedure TWebVote.Add(id, subid: integer);
begin
  if FMasterTable.Locate('ID', id, []) then begin
    if FDetailTable.Locate('SUBID', subid, []) then begin
      FMasterTable.Edit;
      FMasterTable.FieldByName('ALLCOUNT').Value:=
          FMasterTable.FieldByName('ALLCOUNT').Value+1;
      FMasterTable.Post;
      
      FDetailTable.Edit;
      FDetailTable.FieldByName('COUNT').Value:=
        FDetailTable.FieldByName('COUNT').Value+1;
      FDetailTable.Post;
    end;
  end;
end;

Szavazógép cikksorozat

Internetes szavazógép készítése - Szavazógép 1. rész

Internetes szavazógép készítése - Szavazógép 2. rész