Delphi Programming Guide
Delphi Programmer 

Menu  Table of contents

Part I - Foundations
  Chapter 1 – Delphi 7 and Its IDE
  Chapter 2 – The Delphi Programming Language
  Chapter 3 – The Run-Time Library
  Chapter 4 – Core Library classes
  Chapter 5 – Visual Controls
  Chapter 6 – Building the User Interface
  Chapter 7 – Working with Forms
Part II - Delphi Object-Oriented Architectures
  Chapter 8 – The Architecture of Delphi Applications
  Chapter 9 – Writing Delphi Components
  Chapter 10 – Libraries and Packages
  Chapter 11 – Modeling and OOP Programming (with ModelMaker)
  Chapter 12 – From COM to COM+
Part III - Delphi Database-Oriented Architectures
  Chapter 13 – Delphi's Database Architecture
  Chapter 14 – Client/Server with dbExpress
  Chapter 15 – Working with ADO
  Chapter 16 – Multitier DataSnap Applications
  Chapter 17 – Writing Database Components
  Chapter 18 – Reporting with Rave
Part IV - Delphi, the Internet, and a .NET Preview
  Chapter 19 – Internet Programming: Sockets and Indy
  Chapter 20 – Web Programming with WebBroker and WebSnap
  Chapter 21 – Web Programming with IntraWeb
  Chapter 22 – Using XML Technologies
  Chapter 23 – Web Services and SOAP
  Chapter 24 – The Microsoft .NET Architecture from the Delphi Perspective
  Chapter 25 – Delphi for .NET Preview: The Language and the RTL
       
  Appendix A – Extra Delphi Tools by the Author
  Appendix B – Extra Delphi Tools from Other Sources
  Appendix C – Free Companion Books on Delphi
       
  Index    
  List of Figures    
  List of tables    
  List of Listings    
  List of Sidebars  

 
Previous Section Next Section

Practical Examples

After this general introduction to developing server-side applications with WebBroker, I'll end this part of the chapter with two practical examples. The first is a classic web counter. The second is an extension of the WebFind program presented in Chapter 19, which produces a dynamic page instead of filling a list box.

A Graphical Web Hit Counter

The server-side applications you've built up to now were based only on text. Of course, you can easily add references to existing graphics files. What's more interesting, however, is to build server-side programs capable of generating graphics that change over time.

A typical example is a page hit counter. To write a web counter, you save the current number of hits to a file and then read and increase the value every time the counter program is called. To return this information, all you need is HTML text with the number of hits. The code is straightforward:

procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  nHit: Integer;
  LogFile: Text;
  LogFileName: string;
begin
  LogFileName := 'WebCont.log';
  System.Assign (LogFile, LogFileName);
  try
    // read if the file exists
    if FileExists (LogFileName) then
    begin
      Reset (LogFile);
      Readln (LogFile, nHit);
      Inc (nHit);
    end
    else
      nHit := 0;
    // saves the new data
    Rewrite (LogFile);
    Writeln (LogFile, nHit);
  finally
    Close (LogFile);
  end;
  Response.Content := IntToStr (nHit);
end;
Warning 

This simple file handling does not scale. When multiple visitors hit the page at the same time, this code may return false results or fail with a file I/O error because a request in another thread has the file open for reading while this thread tries to open the file for writing. To support a similar scenario, you'll need to use a mutex (or a critical section in a multithreaded program) to let each subsequent thread wait until the thread currently using the file has completed its task.

It's more interesting to create a graphical counter that can be easily embedded into any HTML page. There are two approaches to building a graphical counter: You can prepare a bitmap for each digit up front and then combine them in the program, or you can let the program draw over a memory bitmap to produce the graphic you want to return. In the WebCount program, I chose the second approach.

Basically, you can create an Image component that holds a memory bitmap, which you can paint on with the usual methods of the TCanvas class. Then you can attach this bitmap to a TJpegImage object. Accessing the bitmap through the JpegImage component converts the image to the JPEG format. Then, you can save the JPEG data to a stream and return it. As you can see, there are many steps, but the code is not complicated:

// create a bitmap in memory
Bitmap := TBitmap.Create;
try
  Bitmap.Width := 120;
  Bitmap.Height := 25;
  // draw the digits
  Bitmap.Canvas.Font.Name := 'Arial';
  Bitmap.Canvas.Font.Size := 14;
  Bitmap.Canvas.Font.Color := RGB (255, 127, 0);
  Bitmap.Canvas.Font.Style := [fsBold];
  Bitmap.Canvas.TextOut (1, 1, 'Hits: ' +
    FormatFloat ('###,###,###', Int (nHit)));
  // convert to JPEG and output
  Jpeg1 := TJpegImage.Create;
  try
    Jpeg1.CompressionQuality := 50;
    Jpeg1.Assign(Bitmap);
    Stream := TMemoryStream.Create;
    Jpeg1.SaveToStream (Stream);
    Stream.Position := 0;
    Response.ContentStream := Stream;
    Response.ContentType := 'image/jpeg';
    Response.SendResponse;
    // the response object will free the stream
  finally
    Jpeg1.Free;
  end;
finally
  Bitmap.Free;
end;

The three statements responsible for returning the JPEG image are the two that set the ContentStream and ContentType properties of the Response and the final call to SendResponse. The content type must match one of the possible MIME types accepted by the browser, and the order of these three statements is relevant. The Response object also has a SendStream method, but it should be called only after sending the type of the data with a separate call. Here you can see the effect of this program:

Click To expand

To embed the program in a page, add the following code to the HTML:

<img src="http://localhost/scripts/webcount.exe" border=0 alt="hit counter">

Searching with a Web Search Engine

In Chapter 19, I discussed the use of the Indy HTTP client component to retrieve the result of a search on the Google website. Let's extend the example, turning it into a server-side application. The WebSearcher program, available as a CGI application or a Web App Debugger executable, has two actions: The first returns the HTML retrieved by the search engine; and the second parses the HTML filling a client data set component, which is hooked to a table page producer for generating the final output. Here is the code for the second action:

const
  strSearch = 'http://www.google.com/search?as_q=borland+delphi&num=100';
   
procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  I: integer;
begin
  if not cds.Active then
    cds.CreateDataSet
  else
    cds.EmptyDataSet;
  for i := 0 to 5 do // how many pages?
  begin
    // get the data form the search site
    GrabHtml (strSearch + '&start=' + IntToStr (i*100));
    // scan it to fill the cds
    HtmlStringToCds;
  end;
  cds.First;
  // return producer content
  Response.Content := DataSetTableProducer1.Content;
end;

The GrabHtml method is identical to the WebFind example. The HtlStringToCds method is similar to the corresponding method of the WebFind example (which adds the items to a list box); it adds the addresses and their textual descriptions by calling

cds.InsertRecord ([0, strAddr, strText]);

The ClientDataSet component is set up with three fields: the two strings plus a line counter. This extra empty field is required in order to include the extra column in the table producer. The code fills the column in the cell-formatting event, which also adds the hyperlink:

procedure TWebModule1.DataSetTableProducer1FormatCell(Sender: TObject; CellRow,
  CellColumn: Integer; var BgColor: THTMLBgColor; var Align: THTMLAlign;
  var VAlign: THTMLVAlign; var CustomAttrs, CellData: String);
begin
  if CellRow <> 0 then
  case CellColumn of
    0: CellData := IntToStr (CellRow);
    1: CellData := '<a href="' + CellData + '">' + SplitLong(CellData) + '</a>';
    2: CellData := SplitLong (CellData);
  end;
end;

The call to SplitLong is used to add extra spaces in the output text, to avoid having grid columns that are too large—the browser won't split the text on multiple lines unless it contains spaces or other special characters. The result of this program is a rather slow application (because of the multiple HTTP requests it must forward) that produces output like that shown in Figure 20.5.

Click To expand
Figure 20.5: The WebSearch program shows the result of multiple searches done on Google.

 
Previous Section Next Section


 


 

Delphi Sources


Copyright © 2004-2024 "Delphi Sources" by BrokenByte Software. Delphi Programming Guide
ร๐๓๏๏เ ยส๎ํ๒เ๊๒ๅ   Facebook   ั๑๛๋๊เ ํเ Twitter