Programlama yapalım ve Öğrenelim. - Delphi Eğitim201
  Ana Sayfa
  .NET Eğitim Notları
  Visual C# .NET Örnek Kodları
  VisualBasic.NET Örnek Kodları
  J# Örnekleri
  ASP.NET Örnek Kodları
  Delphi Eğitim
  => Delphi Eğitim1
  => Delphi Eğitim2
  => Delphi Eğitim3
  => Delphi Eğitim4
  => Delphi Eğitim5
  => Delphi Eğitim6
  => Delphi Eğitim7
  => Delphi Eğitim8
  => Delphi Eğitim9
  => Delphi Eğitim10
  => Delphi Eğitim11
  => Delphi Eğitim13
  => Delphi Eğitim14
  => Delphi Eğitim15
  => Delphi Eğitim16
  => Delphi Eğitim17
  => Delphi Eğitim18
  => Delphi Eğitim19
  => Delphi Eğitim20
  => Delphi Eğitim21
  => Delphi Eğitim22
  => Delphi Eğitim23
  => Delphi Eğitim24
  => Delphi Eğitim25
  => Delphi Eğitim26
  => Delphi Eğitim27
  => Delphi Eğitim28
  => Delphi Eğitim29
  => Delphi Eğitim30
  => Delphi Eğtim31
  => Delphi Eğitim32
  => Delphi Eğitim33
  => Delphi Eğitim34
  => Delphi Eğitim35
  => Delphi Eğitim36
  => Delphi Eğitim37
  => Delphi Eğitim38
  => Delphi Eğitim39
  => Delphi Eğitim40
  => Delphi Eğitim41
  => Delphi Eğitim42
  => Delphi Eğitim43
  => Delphi Eğitim44
  => Delphi Eğitim45
  => Delphi Eğitim46
  => Delphi Eğitim47
  => Delphi Eğitim48
  => Delphi Eğitim49
  => Delphi Eğitim50
  => Delphi Eğitim51
  => Delphi Eğitim52
  => Delphi Eğitim53
  => Delphi Eğitim54
  => Delphi Eğitim55
  => Delphi Eğitim56
  => Delphi Eğitim57
  => Delphi Eğitim58
  => Delphi Eğitim59
  => Delphi Eğitim60
  => Delphi Eğitim61
  => Delphi Eğitim62
  => Delphi Eğitim63
  => Delphi Eğitim64
  => Delphi Eğitim65
  => Delphi Eğitim66
  => Delphi Eğitim67
  => Delphi Eğitim68
  => Delphi Eğitim69
  => Delphi Eğitim70
  => Delphi Eğitim71
  => Delphi Eğitim72
  => Delphi Eğitim73
  => Delphi Eğitim74
  => Delphi Eğitim75
  => Delphi Eğitim76
  => Delphi Eğitim77
  => Delphi Eğitim78
  => Delphi Eğitim79
  => Delphi Eğitim80
  => Delphi Eğitim81
  => Delphi Eğitim82
  => Delphi Eğitim83
  => Delphi Eğitim84
  => Delphi Eğitim85
  => Delphi Eğitim86
  => Delphi Eğitim87
  => Delphi Eğitim88
  => Delphi Eğitim89
  => Delphi Eğitim90
  => Delphi Eğitim91
  => Delphi Eğitim92
  => Delphi Eğitim93
  => Delphi Eğitim94
  => Delphi Eğitim95
  => Delphi Eğitim96
  => Delphi Eğitim97
  => Delphi Eğitim98
  => Delphi Eğitim99
  => Delphi Eğitim100
  => Delphi Eğitim101
  => Delphi Eğitim102
  => Delphi Eğitim103
  => Delphi Eğitim104
  => Delphi Eğitim105
  => Delphi Eğitim106
  => Delphi Eğitim107
  => Delphi Eğitim108
  => Delphi Eğitim109
  => Delphi Eğitim110
  => Delphi Eğitim111
  => Delphi Eğitim112
  => Delphi Eğitim113
  => Delphi Eğitim114
  => Delphi Eğitim115
  => Delphi Eğitim116
  => Delphi Eğitim117
  => Delphi Eğitim118
  => Delphi Eğitim119
  => Delphi Eğitim120
  => Delphi Eğitim121
  => Delphi Eğitim122
  => Delphi Eğitim123
  => Delphi Eğitim124
  => Delphi Eğitim125
  => Delphi Eğitim126
  => Delphi Eğitim127
  => Delphi Eğitim128
  => Delphi Eğitim129
  => Delphi Eğitim130
  => Delphi Eğitim131
  => Delphi Eğitim132
  => Delphi Eğitim133
  => Delphi Eğitim134
  => Delphi Eğitim135
  => Delphi Eğitim136
  => Delphi Eğitim137
  => Delphi Eğitim138
  => Delphi Eğitim139
  => Delphi Eğitim140
  => Delphi Eğitim141
  => Delphi Eğitim142
  => Delphi Eğitim143
  => Delphi Eğitim144
  => Delphi Eğitim145
  => Delphi Eğitim146
  => Delphi eğitim147
  => Delphi Eğitim148
  => Delphi Eğitim149
  => Delphi Eğitim150
  => Delphi Eğitim151
  => Delphi Eğitim152
  => Delphi Eğitim153
  => Delphi Eğitim154
  => Delphi Eğitim155
  => Delphi Eğitim156
  => Delphi Eğitim157
  => Delphi Eğitim158
  => Delphi Eğitim159
  => Delphi Eğitim160
  => Delphi Eğitim161
  => Delphi Eğitim162
  => Delphi Eğitim164
  => Delphi Eğitim165
  => Delphi Eğitim166
  => Delphi Eğitim167
  => Delphi Eğitim168
  => Delphi Eğitim169
  => Delphi Eğitim170
  => Delphi Eğitim171
  => Delphi Eğitim172
  => Delphi Eğitim173
  => Delphi Eğitim174
  => Delphi Eğitim175
  => Delphi Eğitim176
  => Delphi Eğitim177
  => Delphi Eğitim178
  => Delphi Eğitim179
  => Delphi Eğitim180
  => Delphi Eğitim181
  => Delphi Eğitim182
  => Delphi Eğitim183
  => Delphi Eğitim184
  => Delphi Eğitim185
  => Delphi Eğitim186
  => Delphi Eğitim187
  => Delphi Eğitim188
  => Delphi Eğitim189
  => Delphi Eğitim190
  => Delphi Eğitim191
  => Delphi Eğitim192
  => Delphi Eğitim193
  => Delphi Eğitim194
  => Delphi Eğitim195
  => Delphi Eğitim196
  => Delphi Eğitim197
  => Delphi Eğitim198
  => Delphi Eğitim199
  => Delphi Eğitim200
  => Delphi Eğitim201
  => Delphi Eğitim202
  => Delphi Eğitim203
  => Delphi Eğitim204
  => Delphi Eğitim205
  => Delphi Eğitim206
  => Delphi Eğitim207
  => Delphi Eğitim208
  => Delphi Eğitim209
  => Delphi Eğitim210
  => Delphi Eğitim211
  => Delphi Eğitim212
  => Delphi Eğitim213
  => Delphi Eğitim214
  => Delphi Eğitim215
  => Delphi Eğitim216
  => Delphi Eğitim217
  => Delphi Eğitim218
  => Delphi Eğitim219
  => Delphi Eğitim220
  => Delphi Eğitim221
  => Delphi Eğitim222
  => Delphi Eğitim223
  => Delphi Eğitim224
  => Delphi Eğitim225
  => Delphi Eğitim226
  => Delphi Eğitim227
  => Delphi Eğitim228
  => Delphi Eğitim229
  => Delphi Eğitim230
  => Delphi Eğitim231
  => Delphi Eğitim232
  => Delphi Eğitim233
  => Delphi Eğitim234
  => Delphi Eğitim235
  => Delphi Eğitim236
  => Delphi Eğitim237
  => Delphi Eğitim238
  => Delphi Eğitim239
  => Delphi Eğitim240
  => Delphi Eğitim241
  => Delphi Eğitim242
  İletişim

neoturk - ...Making an active web-page, part 3 using cookies ?...

We've all heard about cookies. In this chapter I will give an example of how to set a cookie, and how to read one. Using cookies is one way to overcome HTTP's stateless nature, and this property is what we are going to make use of in this login-session example. I'm not going to go into details about cookies, but if you want to, check out: www.cookiecentral.com or www.netscape.com

 

Well let's start. We are going to use a WebModule with three different actions. The actions will be:

 

Show login page if user is not logged on, else tell user that he has already access. Default action.

If login was OK then send a cookie to the client and show success message. If login wasn't OK, tell user.

Read cookie and if cookie is OK, show protected page, else tell user that he's not authorized.

 

Set the project:s output directory to: <your server>/cgi-bin and save the project as login.cgi.

 

 

What is a cookie ?

Cookies are a list of pair values (Name=Value). In this example we're only going to use one pair, but there could be lot's of them. A cookie could for example hold special user-information used by a Webserver to present a page in a way that's convinient for the user. Or as we will see in this example, identify a user.

 

To send the cookie to the browser we will use the Response.SetCookiefield method:

 

procedure SetCookieField(Values: TStrings; const ADomain, APath: string ; AExpires: TDateTime; ASecure: Boolean);

 

ADomain will be blank, APath='/cgi-bin', AExpires = -1 (The Cookie will be killed when we close the browser-session), ASecure=false (In real life you should use a safe connection when using a cookie for this purpose, or else the cookie could be sniffed.)

 

To read the cookie we will use the Request.CookieFields.Values property.

 

 

 

 

Let's start the coding with action 2, where we send the cookie with CookieField1='Authorized', if we find 'Delphi6' in the request contentfield: 'PW'

 

 

procedure TWebModule1.WebModule1WebActionItem2Action(Sender: TObject;

  Request: TWebRequest; Response: TWebResponse; var Handled: boolean);

var masCookie: TStringList;

begin

  masCookie:= TStringList.Create;

  try

    // If password OK, send cookie to client.

    if (Request.ContentFields.Values['PW'] = 'Delphi6') then

    begin

      with masCookie do begin

        Clear;

        Append('CookieField1=Authorized');

      end;

      Response.SetCookieField

        (masCookie, '', '/cgi-bin/', -1, false);

      Response.Content:=

        '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

        'You''re authorized to access the protected page. <BR>' +

        'Click button to continue...' +

        '<FORM ACTION="/cgi-bin/login.cgi/prot" METHOD="ANY">' +

        '<INPUT TYPE="SUBMIT" NAME="Submit1" VALUE="OK"></FORM>';

    end

    else

      // If not, send client to MAS Delphi page

      Response.Content:=

        '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

        'Incorrect login. <BR>Click button to continue...' +

        '<FORM ACTION="http://213.65.224.200" METHOD="ANY">' +

        '<INPUT TYPE="SUBMIT" NAME="Submit1" VALUE="OK"></FORM>';

  finally

    masCookie.Free;

  end;

end;

 

 

 

 

Let's make a function that returns true if the cookie is present and OK:

 

 

function TWebModule1.CheckCookie: boolean;

begin

  if Request.CookieFields.Values['CookieField1'] = 'Authorized' then

    Result:= true

  else

    Result:= false;

end;

 

 

 

Continue with action 1, where we show the login page or tell user that he already has access:

 

 

procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;

  Request: TWebRequest; Response: TWebResponse; var Handled: boolean);

begin

  // Ask for password if not already logged in. Should be done with a safe protocol !!!

  if CheckCookie then

    Response.Content:=

      '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

      'You have already access to the protected page.<BR><BR>' +

      '<FORM ACTION="/cgi-bin/login.cgi/prot" METHOD="ANY">' +

      '<INPUT TYPE="SUBMIT" NAME="Submit1" VALUE="Go to protected page"></FORM>'

  else

    Response.Content:=

      '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

      'Login for protected page.<BR><BR>' +

      '<FONT FACE="Arial"><B><FONT SIZE="-1" COLOR="#000000">' +

      '<FORM ACTION="/cgi-bin/login.cgi/passw" METHOD="POST">' +

      '<P><INPUT TYPE="PASSWORD" NAME="PW"></P>' +

      '<BR><INPUT TYPE="SUBMIT" NAME="Submit1" VALUE="OK"></FORM>';

end;

 

 

 

Last we make action 3, where we show the protected page if the cookie is alright:

 

procedure TWebModule1.WebModule1WebActionItem3Action(Sender: TObject;

  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);

begin

  // Show protected page if Cookie is OK

  if CheckCookie then

    Response.Content:=

      '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

      'Welcome to the protected page.'

  else

    Response.Content:=

      '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

      'You''re not authorized to view this page!';

end;

 

 

 

That would be all.

Time to test if it's working. Put http://<your servername>/cgi-bin/login.cgi/prot into your webbrowser and you should get this response:

You're not authorized to view this page!

 

 

 

Put http://<your servername>/cgi-bin/login.cgi into the browser. Login with "Delphi6", and you should get this:

You're authorized to access the protected page. Click button to continue...

 

 

 

Clicking the button should bring you to the protected page:

Welcome to the protected page.

 

You should now be able to reach the protected page as long as you don't exit your browser-session. If you try and exit your browser and start it again, you will find that you have to login again to reach the protected page.

 

Delphi - .....................................

 

neoturk - ...Making an active web-page, part 3 using cookies ?...

We've all heard about cookies. In this chapter I will give an example of how to set a cookie, and how to read one. Using cookies is one way to overcome HTTP's stateless nature, and this property is what we are going to make use of in this login-session example. I'm not going to go into details about cookies, but if you want to, check out: www.cookiecentral.com or www.netscape.com

 

Well let's start. We are going to use a WebModule with three different actions. The actions will be:

 

Show login page if user is not logged on, else tell user that he has already access. Default action.

If login was OK then send a cookie to the client and show success message. If login wasn't OK, tell user.

Read cookie and if cookie is OK, show protected page, else tell user that he's not authorized.

 

Set the project:s output directory to: <your server>/cgi-bin and save the project as login.cgi.

 

 

What is a cookie ?

Cookies are a list of pair values (Name=Value). In this example we're only going to use one pair, but there could be lot's of them. A cookie could for example hold special user-information used by a Webserver to present a page in a way that's convinient for the user. Or as we will see in this example, identify a user.

 

To send the cookie to the browser we will use the Response.SetCookiefield method:

 

procedure SetCookieField(Values: TStrings; const ADomain, APath: string ; AExpires: TDateTime; ASecure: Boolean);

 

ADomain will be blank, APath='/cgi-bin', AExpires = -1 (The Cookie will be killed when we close the browser-session), ASecure=false (In real life you should use a safe connection when using a cookie for this purpose, or else the cookie could be sniffed.)

 

To read the cookie we will use the Request.CookieFields.Values property.

 

 

 

 

Let's start the coding with action 2, where we send the cookie with CookieField1='Authorized', if we find 'Delphi6' in the request contentfield: 'PW'

 

 

procedure TWebModule1.WebModule1WebActionItem2Action(Sender: TObject;

  Request: TWebRequest; Response: TWebResponse; var Handled: boolean);

var masCookie: TStringList;

begin

  masCookie:= TStringList.Create;

  try

    // If password OK, send cookie to client.

    if (Request.ContentFields.Values['PW'] = 'Delphi6') then

    begin

      with masCookie do begin

        Clear;

        Append('CookieField1=Authorized');

      end;

      Response.SetCookieField

        (masCookie, '', '/cgi-bin/', -1, false);

      Response.Content:=

        '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

        'You''re authorized to access the protected page. <BR>' +

        'Click button to continue...' +

        '<FORM ACTION="/cgi-bin/login.cgi/prot" METHOD="ANY">' +

        '<INPUT TYPE="SUBMIT" NAME="Submit1" VALUE="OK"></FORM>';

    end

    else

      // If not, send client to MAS Delphi page

      Response.Content:=

        '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

        'Incorrect login. <BR>Click button to continue...' +

        '<FORM ACTION="http://213.65.224.200" METHOD="ANY">' +

        '<INPUT TYPE="SUBMIT" NAME="Submit1" VALUE="OK"></FORM>';

  finally

    masCookie.Free;

  end;

end;

 

 

 

 

Let's make a function that returns true if the cookie is present and OK:

 

 

function TWebModule1.CheckCookie: boolean;

begin

  if Request.CookieFields.Values['CookieField1'] = 'Authorized' then

    Result:= true

  else

    Result:= false;

end;

 

 

 

Continue with action 1, where we show the login page or tell user that he already has access:

 

 

procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;

  Request: TWebRequest; Response: TWebResponse; var Handled: boolean);

begin

  // Ask for password if not already logged in. Should be done with a safe protocol !!!

  if CheckCookie then

    Response.Content:=

      '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

      'You have already access to the protected page.<BR><BR>' +

      '<FORM ACTION="/cgi-bin/login.cgi/prot" METHOD="ANY">' +

      '<INPUT TYPE="SUBMIT" NAME="Submit1" VALUE="Go to protected page"></FORM>'

  else

    Response.Content:=

      '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

      'Login for protected page.<BR><BR>' +

      '<FONT FACE="Arial"><B><FONT SIZE="-1" COLOR="#000000">' +

      '<FORM ACTION="/cgi-bin/login.cgi/passw" METHOD="POST">' +

      '<P><INPUT TYPE="PASSWORD" NAME="PW"></P>' +

      '<BR><INPUT TYPE="SUBMIT" NAME="Submit1" VALUE="OK"></FORM>';

end;

 

 

 

Last we make action 3, where we show the protected page if the cookie is alright:

 

procedure TWebModule1.WebModule1WebActionItem3Action(Sender: TObject;

  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);

begin

  // Show protected page if Cookie is OK

  if CheckCookie then

    Response.Content:=

      '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

      'Welcome to the protected page.'

  else

    Response.Content:=

      '<FONT FACE="Arial"><B><FONT SIZE="+1" COLOR="#0000FF">' +

      'You''re not authorized to view this page!';

end;

 

 

 

That would be all.

Time to test if it's working. Put http://<your servername>/cgi-bin/login.cgi/prot into your webbrowser and you should get this response:

You're not authorized to view this page!

 

 

 

Put http://<your servername>/cgi-bin/login.cgi into the browser. Login with "Delphi6", and you should get this:

You're authorized to access the protected page. Click button to continue...

 

 

 

Clicking the button should bring you to the protected page:

Welcome to the protected page.

 

You should now be able to reach the protected page as long as you don't exit your browser-session. If you try and exit your browser and start it again, you will find that you have to login again to reach the protected page.

 

Delphi - .....................................

 

neoturk - ...Indy mailer ?...

If you have used Delphi for Internet programming, you have probably already learned what Indy components are. Indy components allow you to write TCP/IP applications very easily. The Indy components set includes both client and server components, so you could quickly write your own HTTP server if the need arises. Indy components, or Internet Direct more precisely, are now shipped along with Delphi 6, but these components are open-source and can be downloaded freely from: www.nevrona.com/indy.

 

To demonstrate how easy and straightforward programming with Indy is, I made this mail-client.

 

 

 

If you wan't the files, they're here:

 

 

 

 

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, IdMessage, IdBaseComponent, IdComponent, IdTCPConnection,

  IdTCPClient, IdMessageClient, IdSMTP, StdCtrls;

 

type

  TForm1 = class(TForm)

    Button1: TButton;

    GroupBox1: TGroupBox;

    Label1: TLabel;

    Edit1: TEdit;

    Label2: TLabel;

    Edit2: TEdit;

    Label3: TLabel;

    Edit3: TEdit;

    Label4: TLabel;

    Memo1: TMemo;

    GroupBox2: TGroupBox;

    Edit4: TEdit;

    Edit5: TEdit;

    Label5: TLabel;

    Label6: TLabel;

    procedure Button1Click(Sender: TObject);

  private

    Msg: TIdMessage;

    SMTP: TIdSMTP;

    procedure SMTPDisconnected(Sender: TObject);

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  Msg:= TIdMessage.Create(Self);

  SMTP:= TIdSMTP.Create(Self);

  try

    SMTP.OnDisconnected:= SMTPDisconnected;

    Msg.From.Address:= Edit1.Text;

    // If more then one recipients, separate with commas

    Msg.Recipients.EMailAddresses:= Edit2.Text;

    Msg.Subject:= Edit3.Text;

    Msg.Body.Add(Memo1.Text);

    SMTP.Host:= Edit4.Text;

    SMTP.UserId:= Edit5.Text;

 

    with SMTP do

    begin

      Connect;

      Send(Msg);

      Disconnect;

    end;

 

    MessageDlg('Your mail has been sent successfully !', mtInformation, [mbOK], 0);

 

  except

    on E: Exception do

      MessageDlg('Something went wrong with your EMail !' + #13 + #10 +

        'Errormessage: ' + #13 + #10 + E.message, mtError, [mbOK], 0);

  end;

end;

 

procedure TForm1.SMTPDisconnected(Sender: TObject);

begin

  Msg.Free;

  SMTP.Free;

end;

 

end.

 

Delphi - .....................................

 

neoturk - ...Indy mailer ?...

If you have used Delphi for Internet programming, you have probably already learned what Indy components are. Indy components allow you to write TCP/IP applications very easily. The Indy components set includes both client and server components, so you could quickly write your own HTTP server if the need arises. Indy components, or Internet Direct more precisely, are now shipped along with Delphi 6, but these components are open-source and can be downloaded freely from: www.nevrona.com/indy.

 

To demonstrate how easy and straightforward programming with Indy is, I made this mail-client.

 

 

 

If you wan't the files, they're here:

 

 

 

 

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, IdMessage, IdBaseComponent, IdComponent, IdTCPConnection,

  IdTCPClient, IdMessageClient, IdSMTP, StdCtrls;

 

type

  TForm1 = class(TForm)

    Button1: TButton;

    GroupBox1: TGroupBox;

    Label1: TLabel;

    Edit1: TEdit;

    Label2: TLabel;

    Edit2: TEdit;

    Label3: TLabel;

    Edit3: TEdit;

    Label4: TLabel;

    Memo1: TMemo;

    GroupBox2: TGroupBox;

    Edit4: TEdit;

    Edit5: TEdit;

    Label5: TLabel;

    Label6: TLabel;

    procedure Button1Click(Sender: TObject);

  private

    Msg: TIdMessage;

    SMTP: TIdSMTP;

    procedure SMTPDisconnected(Sender: TObject);

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  Msg:= TIdMessage.Create(Self);

  SMTP:= TIdSMTP.Create(Self);

  try

    SMTP.OnDisconnected:= SMTPDisconnected;

    Msg.From.Address:= Edit1.Text;

    // If more then one recipients, separate with commas

    Msg.Recipients.EMailAddresses:= Edit2.Text;

    Msg.Subject:= Edit3.Text;

    Msg.Body.Add(Memo1.Text);

    SMTP.Host:= Edit4.Text;

    SMTP.UserId:= Edit5.Text;

 

    with SMTP do

    begin

      Connect;

      Send(Msg);

      Disconnect;

    end;

 

    MessageDlg('Your mail has been sent successfully !', mtInformation, [mbOK], 0);

 

  except

    on E: Exception do

      MessageDlg('Something went wrong with your EMail !' + #13 + #10 +

        'Errormessage: ' + #13 + #10 + E.message, mtError, [mbOK], 0);

  end;

end;

 

procedure TForm1.SMTPDisconnected(Sender: TObject);

begin

  Msg.Free;

  SMTP.Free;

end;

 

end.

 

Delphi - .....................................

 

neoturk - ...Indy client - server ?...

This time I will show you how to make a multithreaded Client/Server-application with Indy. The server will simulate a state change: "working / idle" every 10 secs. The client polls the server at a given interval, and presents the server-state. Possible exceptions are trapped. Try connecting with multiple clients.

 

Indy components are open-source and can be downloaded freely from: www.nevrona.com/indy.

 

If you wan't the project-files, they're here:

 

 

 

 

{-----------------------------------------------------------------------------

 Unit Name: sUnit1

 Author:    Mats Asplund

 Purpose:   IndyServer

-----------------------------------------------------------------------------}

 

unit sUnit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, IdBaseComponent, IdComponent, IdTCPServer, IdException, ExtCtrls, StdCtrls;

 

type

  TForm1 = class(TForm)

    Label1: TLabel;

    Timer1: TTimer;

    IdTCPServer1: TIdTCPServer;

    Label2: TLabel;

    procedure Timer1Timer(Sender: TObject);

    procedure IdTCPServer1Connect(AThread: TIdPeerThread);

    procedure IdTCPServer1Disconnect(AThread: TIdPeerThread);

    procedure FormCreate(Sender: TObject);

  private

    Working, Disconnected: Boolean;

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  IdTCPServer1.DefaultPort:= 12345;

  IdTCPServer1.Active:= true;

  Timer1.Interval:= 10000;

  Timer1.Enabled:= true;

end;

 

procedure TForm1.Timer1Timer(Sender: TObject);

begin

  Working:= not Working;

end;

 

procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);

begin

  Disconnected:= false;

  with IdTCPServer1 do

  begin

    try

      while not Disconnected do

      begin

        if Working then

        begin

          AThread.Connection.Writeln('Working');

          Label2.Caption:= 'Sent: "Working"';

        end

        else

        begin

          AThread.Connection.Writeln('Idle');

          Label2.Caption:= 'Sent: "Idle"';

        end;

        Sleep(500);

        Label2.Caption:= '';

        Sleep(500);

      end;

    except

//      on EIdSocketError do

//        ShowMessage('Client disconnected !');

    end;

  end

end;

 

procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);

begin

  Disconnected:= true;

end;

 

end.

 

 

 

 

 

{-----------------------------------------------------------------------------

 Unit Name: cUnit1

 Author:    Mats Asplund

 Purpose:   IndyClient

-----------------------------------------------------------------------------}

 

unit cUnit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,

  StdCtrls, ExtCtrls, Buttons, passoverbtn, IdException;

 

type

  TForm1 = class(TForm)

    IdTCPClient1: TIdTCPClient;

    Memo1: TMemo;

    Label1: TLabel;

    Timer1: TTimer;

    Edit1: TEdit;

    Label2: TLabel;

    Edit2: TEdit;

    Label3: TLabel;

    Button1: TButton;

    Button2: TButton;

    procedure Timer1Timer(Sender: TObject);

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

  private

  public

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  Timer1.Interval:= 100;

  Timer1.Enabled:= false;

  IdTCPClient1.Host:= '127.0.0.1';

  IdTCPClient1.Port:= 12345;

end;

 

procedure TForm1.Timer1Timer(Sender: TObject);

begin

  try

    Memo1.Lines.Add(IdTCPClient1.ReadLn);

  except

    on EIdConnClosedGracefully do

    begin

      Timer1.Enabled:= false;

      ShowMessage('The server closed the connection !' + #13#10 +

        'Try connecting again.');

    end;

  end;

end;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  try

    IdTCPClient1.Host:= Edit1.Text;

    IdTCPClient1.Connect;

    ShowMessage('Connected to ' + Edit1.Text);

    Timer1.Interval:= StrToInt(Edit2.Text);

    Timer1.Enabled:= true;

  except

    on EIdConnClosedGracefully do

      ShowMessage('The server closed the connection !');

    on EIdAlreadyConnected do

      ShowMessage('Your''e already connected !');

    on EIdSocketError do

      ShowMessage('Can''t connect to server !');

  end;

end;

 

procedure TForm1.Button2Click(Sender: TObject);

begin

  Timer1.Enabled:= false;

  IdTCPClient1.Disconnect;

  ShowMessage('Disconnected from ' + Edit1.Text);

end;

 

end.

 

Delphi - .....................................

 

neoturk - ...Indy client - server ?...

This time I will show you how to make a multithreaded Client/Server-application with Indy. The server will simulate a state change: "working / idle" every 10 secs. The client polls the server at a given interval, and presents the server-state. Possible exceptions are trapped. Try connecting with multiple clients.

 

Indy components are open-source and can be downloaded freely from: www.nevrona.com/indy.

 

If you wan't the project-files, they're here:

 

 

 

 

{-----------------------------------------------------------------------------

 Unit Name: sUnit1

 Author:    Mats Asplund

 Purpose:   IndyServer

-----------------------------------------------------------------------------}

 

unit sUnit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, IdBaseComponent, IdComponent, IdTCPServer, IdException, ExtCtrls, StdCtrls;

 

type

  TForm1 = class(TForm)

    Label1: TLabel;

    Timer1: TTimer;

    IdTCPServer1: TIdTCPServer;

    Label2: TLabel;

    procedure Timer1Timer(Sender: TObject);

    procedure IdTCPServer1Connect(AThread: TIdPeerThread);

    procedure IdTCPServer1Disconnect(AThread: TIdPeerThread);

    procedure FormCreate(Sender: TObject);

  private

    Working, Disconnected: Boolean;

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  IdTCPServer1.DefaultPort:= 12345;

  IdTCPServer1.Active:= true;

  Timer1.Interval:= 10000;

  Timer1.Enabled:= true;

end;

 

procedure TForm1.Timer1Timer(Sender: TObject);

begin

  Working:= not Working;

end;

 

procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);

begin

  Disconnected:= false;

  with IdTCPServer1 do

  begin

    try

      while not Disconnected do

      begin

        if Working then

        begin

          AThread.Connection.Writeln('Working');

          Label2.Caption:= 'Sent: "Working"';

        end

        else

        begin

          AThread.Connection.Writeln('Idle');

          Label2.Caption:= 'Sent: "Idle"';

        end;

        Sleep(500);

        Label2.Caption:= '';

        Sleep(500);

      end;

    except

//      on EIdSocketError do

//        ShowMessage('Client disconnected !');

    end;

  end

end;

 

procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);

begin

  Disconnected:= true;

end;

 

end.

 

 

 

 

 

{-----------------------------------------------------------------------------

 Unit Name: cUnit1

 Author:    Mats Asplund

 Purpose:   IndyClient

-----------------------------------------------------------------------------}

 

unit cUnit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,

  StdCtrls, ExtCtrls, Buttons, passoverbtn, IdException;

 

type

  TForm1 = class(TForm)

    IdTCPClient1: TIdTCPClient;

    Memo1: TMemo;

    Label1: TLabel;

    Timer1: TTimer;

    Edit1: TEdit;

    Label2: TLabel;

    Edit2: TEdit;

    Label3: TLabel;

    Button1: TButton;

    Button2: TButton;

    procedure Timer1Timer(Sender: TObject);

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

  private

  public

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  Timer1.Interval:= 100;

  Timer1.Enabled:= false;

  IdTCPClient1.Host:= '127.0.0.1';

  IdTCPClient1.Port:= 12345;

end;

 

procedure TForm1.Timer1Timer(Sender: TObject);

begin

  try

    Memo1.Lines.Add(IdTCPClient1.ReadLn);

  except

    on EIdConnClosedGracefully do

    begin

      Timer1.Enabled:= false;

      ShowMessage('The server closed the connection !' + #13#10 +

        'Try connecting again.');

    end;

  end;

end;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  try

    IdTCPClient1.Host:= Edit1.Text;

    IdTCPClient1.Connect;

    ShowMessage('Connected to ' + Edit1.Text);

    Timer1.Interval:= StrToInt(Edit2.Text);

    Timer1.Enabled:= true;

  except

    on EIdConnClosedGracefully do

      ShowMessage('The server closed the connection !');

    on EIdAlreadyConnected do

      ShowMessage('Your''e already connected !');

    on EIdSocketError do

      ShowMessage('Can''t connect to server !');

  end;

end;

 

procedure TForm1.Button2Click(Sender: TObject);

begin

  Timer1.Enabled:= false;

  IdTCPClient1.Disconnect;

  ShowMessage('Disconnected from ' + Edit1.Text);

end;

 

end.

 

Delphi - .....................................

 

neoturk - ...Indy client - server 2 ?...

Another Client/Server-application with Indy.

When a client connects, the server will send back an identity number 0-9 to the client, and show a shape which will indicate the clients condition. The client simulates a state change: "working / idle" every 5 secs. When a client disconnects the associated shape will turn invisible, and the ID-No will be free to use with another client connection. If more than ten client tries to connect, the server will send back a message that it's full, which is also presented at the client side.

 

Indy components are open-source and can be downloaded freely from: www.nevrona.com/indy.

 

If you wan't the project-files, they're here:

 

 

 

 

{-----------------------------------------------------------------------------

 Unit Name: sUnit

 Author:    Mats Asplund, 2001-11-09

 Purpose:   Indy client/server demo, server-part

-----------------------------------------------------------------------------}

 

unit sUnit;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, IdBaseComponent, IdComponent, IdTCPServer, StdCtrls, ExtCtrls;

 

type

  TForm1 = class(TForm)

    IdTCPServer1: TIdTCPServer;

    Timer1: TTimer;

    Memo1: TMemo;

    Label2: TLabel;

    Edit1: TEdit;

    procedure IdTCPServer1Execute(AThread: TIdPeerThread);

    procedure FormCreate(Sender: TObject);

    procedure FormClose(Sender: TObject; var Action: TCloseAction);

    procedure IdTCPServer1Connect(AThread: TIdPeerThread);

    procedure IdTCPServer1Disconnect(AThread: TIdPeerThread);

    procedure FormActivate(Sender: TObject);

  private

    ClientList: TStringList;

    ClientStatus: array[0..9] of TShape;

    procedure ShowClientStatus;

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

 

uses IdTCPConnection;

 

{$R *.dfm}

 

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);

var

  ClientMsg: string;

begin

  with AThread.Connection do

  begin

// Read message

    ClientMsg := ReadLn('', -2);

// If client disconnected, delete from ClientList

    if Pos('disconnecting...', ClientMsg) > 1 then

    begin

      ClientList.Delete(ClientList.IndexOf(Copy(ClientMsg, 7, 1)));

      ClientStatus[StrToInt(Copy(ClientMsg, 7, 1))].Visible := false;

    end

    else

// else update Shape associated with client.

      if Pos('working', ClientMsg) > 1 then

      begin

        ClientStatus[StrToInt(Copy(ClientMsg, 7, 1))].Visible := true;

        ClientStatus[StrToInt(Copy(ClientMsg, 7, 1))].Brush.Color := clLime;

      end

      else

      begin

        ClientStatus[StrToInt(Copy(ClientMsg, 7, 1))].Visible := true;

        ClientStatus[StrToInt(Copy(ClientMsg, 7, 1))].Brush.Color := clRed;

      end;

    Edit1.Text := ClientMsg;

  end;

  ShowClientStatus;

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  ClientList := TStringList.Create;

end;

 

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

var

  n: integer;

begin

  ClientList.Free;

  for n := 0 to 9 do

    ClientStatus[n].Free;

end;

 

procedure TForm1.ShowClientStatus;

begin

  Memo1.Lines.Text := ClientList.Text;

end;

 

procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);

var

  n: integer;

  Full: boolean;

begin

  with AThread.Connection do

  begin

    Full:= true;

    for n := 0 to 9 do

// Look for first free ID-no

      if (ClientList.IndexOf(IntToStr(n)) = -1) then

      begin

        ClientList.Add(IntToStr(n));

// Write ID-no back to Client

        WriteLn(IntToStr(n));

        Full:= false;

        Break;

      end;

    if Full then WriteLn('Server full');

  end;

  ShowClientStatus;

end;

 

procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);

begin

  ShowClientStatus;

end;

 

procedure TForm1.FormActivate(Sender: TObject);

var

  n: integer;

begin

// Create ten invisible shapes

  for n := 0 to 9 do

  begin

    ClientStatus[n] := TShape.Create(Self);

    ClientStatus[n].Parent := Form1;

    ClientStatus[n].Height := 10;

    ClientStatus[n].Width := 10;

    ClientStatus[n].Shape := stRectangle;

    ClientStatus[n].Top := 35;

    ClientStatus[n].Left := 8 + (15 * n);

    ClientStatus[n].Visible := false;

  end;

end;

 

end.

 

 

 

{-----------------------------------------------------------------------------

 Unit Name: cUnit

 Author:    Mats Asplund, 2001-11-09

 Purpose:   Indy client/server demo, client-part

-----------------------------------------------------------------------------}

 

unit cUnit;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,

  ExtCtrls, StdCtrls;

 

type

  TForm1 = class(TForm)

    Timer1: TTimer;

    IdTCPClient1: TIdTCPClient;

    Label1: TLabel;

    Shape1: TShape;

    Edit1: TEdit;

    Label2: TLabel;

    Button1: TButton;

    procedure Timer1Timer(Sender: TObject);

    procedure FormClose(Sender: TObject; var Action: TCloseAction);

    procedure Button1Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

  private

    ServerDown, Idle: Boolean;

    ClientNo: string;

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.Timer1Timer(Sender: TObject);

begin

  try

    with IdTCPClient1 do

    begin

      Timer1.Interval:= 5000;

// Turn off timer in case of server going down.

      Timer1.Enabled:= false;

      Idle:= not Idle;

      if Idle then

      begin

        Writeln('Client' + ClientNo + ' idle...');

        Shape1.Brush.Color:= clRed;

// Turn it on again

        Timer1.Enabled:= true;

      end

      else

      begin

        Writeln('Client' + ClientNo + ' working...');

        Shape1.Brush.Color:= clLime;

// Turn it on again

        Timer1.Enabled:= true;

      end;

    end;

  except

    on E: Exception do

    begin

      MessageDlg('The server is down.' + #13#10 +

        'Restart the client some other time.', mtError, [mbOK], 0);

      LAbel1.Caption:= 'No contact with server..';

      ServerDown:= true;

    end;

  end;

end;

 

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

  if not ServerDown then

    with IdTCPClient1 do

    begin

      Writeln('Client' + ClientNo + ' disconnecting...');

      Disconnect;

    end;

  Action:= caFree;

end;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  try

    Timer1.Interval:= 1000;

    Timer1.Enabled:= true;

// Connect to server

    with IdTCPClient1 do

    begin

      Host:= Edit1.Text;

      Connect;

// Read ID-no

      ClientNo:= Readln('', 5000); // Timeout 5 secs

      if ClientNo = 'Server full' then

      begin

        MessageDlg('There''s already ten clients connected. ' + #13#10 +

          'Try connecting some other time !', mtWarning, [mbOK], 0);

      end

      else

        if ClientNo = '' then

        begin

          Label1.Caption:= 'Client' + ClientNo + ' connection refused...';

        end

        else

        begin

// Connection accepted by server.

          ServerDown:= false;

          Caption:= 'Client' + ClientNo;

          Button1.Enabled:= false;

          Label1.Caption:= 'Client' + ClientNo + ' connection accepted...';

        end;

    end;

  except

    on E: Exception do

    begin

      Label1.Caption:= 'Client' + ClientNo + ' connection refused...';

    end;

  end;

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  ServerDown:= true;

end;

 

end.

 

Delphi - .....................................

 

neoturk - ...Indy client - server 2 ?...

Another Client/Server-application with Indy.

When a client connects, the server will send back an identity number 0-9 to the client, and show a shape which will indicate the clients condition. The client simulates a state change: "working / idle" every 5 secs. When a client disconnects the associated shape will turn invisible, and the ID-No will be free to use with another client connection. If more than ten client tries to connect, the server will send back a message that it's full, which is also presented at the client side.

 

Indy components are open-source and can be downloaded freely from: www.nevrona.com/indy.

 

If you wan't the project-files, they're here:

 

 

 

 

{-----------------------------------------------------------------------------

 Unit Name: sUnit

 Author:    Mats Asplund, 2001-11-09

 Purpose:   Indy client/server demo, server-part

-----------------------------------------------------------------------------}

 

unit sUnit;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, IdBaseComponent, IdComponent, IdTCPServer, StdCtrls, ExtCtrls;

 

type

  TForm1 = class(TForm)

    IdTCPServer1: TIdTCPServer;

    Timer1: TTimer;

    Memo1: TMemo;

    Label2: TLabel;

    Edit1: TEdit;

    procedure IdTCPServer1Execute(AThread: TIdPeerThread);

    procedure FormCreate(Sender: TObject);

    procedure FormClose(Sender: TObject; var Action: TCloseAction);

    procedure IdTCPServer1Connect(AThread: TIdPeerThread);

    procedure IdTCPServer1Disconnect(AThread: TIdPeerThread);

    procedure FormActivate(Sender: TObject);

  private

    ClientList: TStringList;

    ClientStatus: array[0..9] of TShape;

    procedure ShowClientStatus;

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

 

uses IdTCPConnection;

 

{$R *.dfm}

 

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);

var

  ClientMsg: string;

begin

  with AThread.Connection do

  begin

// Read message

    ClientMsg := ReadLn('', -2);

// If client disconnected, delete from ClientList

    if Pos('disconnecting...', ClientMsg) > 1 then

    begin

      ClientList.Delete(ClientList.IndexOf(Copy(ClientMsg, 7, 1)));

      ClientStatus[StrToInt(Copy(ClientMsg, 7, 1))].Visible := false;

    end

    else

// else update Shape associated with client.

      if Pos('working', ClientMsg) > 1 then

      begin

        ClientStatus[StrToInt(Copy(ClientMsg, 7, 1))].Visible := true;

        ClientStatus[StrToInt(Copy(ClientMsg, 7, 1))].Brush.Color := clLime;

      end

      else

      begin

        ClientStatus[StrToInt(Copy(ClientMsg, 7, 1))].Visible := true;

        ClientStatus[StrToInt(Copy(ClientMsg, 7, 1))].Brush.Color := clRed;

      end;

    Edit1.Text := ClientMsg;

  end;

  ShowClientStatus;

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  ClientList := TStringList.Create;

end;

 

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

var

  n: integer;

begin

  ClientList.Free;

  for n := 0 to 9 do

    ClientStatus[n].Free;

end;

 

procedure TForm1.ShowClientStatus;

begin

  Memo1.Lines.Text := ClientList.Text;

end;

 

procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);

var

  n: integer;

  Full: boolean;

begin

  with AThread.Connection do

  begin

    Full:= true;

    for n := 0 to 9 do

// Look for first free ID-no

      if (ClientList.IndexOf(IntToStr(n)) = -1) then

      begin

        ClientList.Add(IntToStr(n));

// Write ID-no back to Client

        WriteLn(IntToStr(n));

        Full:= false;

        Break;

      end;

    if Full then WriteLn('Server full');

  end;

  ShowClientStatus;

end;

 

procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);

begin

  ShowClientStatus;

end;

 

procedure TForm1.FormActivate(Sender: TObject);

var

  n: integer;

begin

// Create ten invisible shapes

  for n := 0 to 9 do

  begin

    ClientStatus[n] := TShape.Create(Self);

    ClientStatus[n].Parent := Form1;

    ClientStatus[n].Height := 10;

    ClientStatus[n].Width := 10;

    ClientStatus[n].Shape := stRectangle;

    ClientStatus[n].Top := 35;

    ClientStatus[n].Left := 8 + (15 * n);

    ClientStatus[n].Visible := false;

  end;

end;

 

end.

 

 

 

{-----------------------------------------------------------------------------

 Unit Name: cUnit

 Author:    Mats Asplund, 2001-11-09

 Purpose:   Indy client/server demo, client-part

-----------------------------------------------------------------------------}

 

unit cUnit;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,

  ExtCtrls, StdCtrls;

 

type

  TForm1 = class(TForm)

    Timer1: TTimer;

    IdTCPClient1: TIdTCPClient;

    Label1: TLabel;

    Shape1: TShape;

    Edit1: TEdit;

    Label2: TLabel;

    Button1: TButton;

    procedure Timer1Timer(Sender: TObject);

    procedure FormClose(Sender: TObject; var Action: TCloseAction);

    procedure Button1Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

  private

    ServerDown, Idle: Boolean;

    ClientNo: string;

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.Timer1Timer(Sender: TObject);

begin

  try

    with IdTCPClient1 do

    begin

      Timer1.Interval:= 5000;

// Turn off timer in case of server going down.

      Timer1.Enabled:= false;

      Idle:= not Idle;

      if Idle then

      begin

        Writeln('Client' + ClientNo + ' idle...');

        Shape1.Brush.Color:= clRed;

// Turn it on again

        Timer1.Enabled:= true;

      end

      else

      begin

        Writeln('Client' + ClientNo + ' working...');

        Shape1.Brush.Color:= clLime;

// Turn it on again

        Timer1.Enabled:= true;

      end;

    end;

  except

    on E: Exception do

    begin

      MessageDlg('The server is down.' + #13#10 +

        'Restart the client some other time.', mtError, [mbOK], 0);

      LAbel1.Caption:= 'No contact with server..';

      ServerDown:= true;

    end;

  end;

end;

 

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

  if not ServerDown then

    with IdTCPClient1 do

    begin

      Writeln('Client' + ClientNo + ' disconnecting...');

      Disconnect;

    end;

  Action:= caFree;

end;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  try

    Timer1.Interval:= 1000;

    Timer1.Enabled:= true;

// Connect to server

    with IdTCPClient1 do

    begin

      Host:= Edit1.Text;

      Connect;

// Read ID-no

      ClientNo:= Readln('', 5000); // Timeout 5 secs

      if ClientNo = 'Server full' then

      begin

        MessageDlg('There''s already ten clients connected. ' + #13#10 +

          'Try connecting some other time !', mtWarning, [mbOK], 0);

      end

      else

        if ClientNo = '' then

        begin

          Label1.Caption:= 'Client' + ClientNo + ' connection refused...';

        end

        else

        begin

// Connection accepted by server.

          ServerDown:= false;

          Caption:= 'Client' + ClientNo;

          Button1.Enabled:= false;

          Label1.Caption:= 'Client' + ClientNo + ' connection accepted...';

        end;

    end;

  except

    on E: Exception do

    begin

      Label1.Caption:= 'Client' + ClientNo + ' connection refused...';

    end;

  end;

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  ServerDown:= true;

end;

 

end.

 

Delphi - .....................................

 

neoturk - ...Application design using frames ?...

When Delphi 5 first shipped, it included a new, visual container class that represents an important advance in rapid application development (RAD) programming. This class, TFrame, provides you with the ability to visually configure a set of one or more components, and then to easily reuse this configuration throughout your application. This capability is so powerful that Delphi 5's integrated development environment (IDE) was re-designed, making extensive use of frames. Frames are now available in C++ Builder 5 and later, as well as Kylix.

This paper provides you with a detailed overview of frames. It begins with a general discussion of what frames are and what benefits they provide. It continues with a demonstration of how to create frames, and how to modify the properties of objects that appear on frame instances. Next, you will learn how to create event handlers for frames, and how to override or extend these event handlers in frame instances. This paper concludes by showing you how to add frames to the Component Palette and the Object Repository, and what benefits you gain by doing so.

 

Overview of Frames

There are two primary benefits of frames. The first is that, under certain circumstances, frames can dramatically reduce the amount of resources that need to be stored in a project. The second, and generally more important benefit, is that frames permit you to visually create objects that can be duplicated from and extended. These happen to be the same two benefits that you enjoy with visual form inheritance (VFI).

VFI permits you to create form objects that can be inherited from easily. The main limit to VFI is that you must use the form in an all-or-nothing fashion. Specifically, when you use VFI you always create an entirely new form. Frames, on the other hand, are more similar to panels in this respect. That is, a single form can contain two or more frames. Importantly, every frame maintains its relationship with the  TFrame class that defines it, meaning that subsequent changes to the defining class are automatically inherited by the instances. While you could achieve a similar effect using TPanels, doing so would be a strictly code-based operation. That is, you would have to write the code to define the TPanel descendants manually. Frames, on the other hand, are designed visually, just like forms.

 

Frames can also be thought of as sharing some similarities with component templates (a group of one or more components that are saved to the component palette by selecting Component | Create Component Template). But the similarities are limited to the fact that both component templates and frames are designed visually (unlike traditional component design, which is an exclusively code-based process). But the differences between component templates and frames are actually very great. As you have already learned, a frame is an instance of a defining class, and as such, is changed when the defining class is changed. By comparison, component templates are aggregates of components. A change to a component template has no effect on objects previously created from that template.

 

Creating a Frame

The following steps demonstrate how to create a frame.

1. Begin by selecting File | New Application to create a new project.

 

2. Select File | New Frame to create a new Frame. Place on this frame 3 Labels and DBEdits. Also place a DBNavigator and a DataSource. Set the Captions of the Labels to ID, First Name, Last Name. Set the DataSource property of each DBEdit as well as the DBNavigator to DataSource1. When you are done the frame may look something like that shown in Figure 1.

 

 

 

Figure 1. A simple frame for displaying an ID number, as well as a first and last name.

 

3. With this frame still selected, set its Name property to NameFrame. More so than other objects, it is particularly important to give a frame a meaningful name. Finally, save the frame by selecting File | Save As to save this frame. In this case save the frame using the filename NAMEFRAM.PAS.

 

That's all there is to creating a frame. The following section demonstrates how to use this frame.

 

Using a Frame

A frame is a component. Its typical use, however, differs from other components that appear on the component palette. The following steps demonstrate how to use a frame.

1. Select Form1 of the application that you started in the preceding steps.

 

2. Add two group boxes to the form, one above the other. Set the Caption of the first groupbox to Customers and the caption of the second to Employees. Your form may look something like that shown in Figure 2.

 

 

 

Figure 2. A form ready for the placement of frames

 

3. Now add the frames. With the Standard page of the component palette selected, click on the Frame component and drop it within the Customer groupbox. The designer responds by displaying the Select frame to insert dialog box shown in Figure 3.

 

 

 

Figure 3. The Select frame to insert dialog box

 

4. Select NameFrame. The frame now appears within the Customer groupbox. Repeat this process, this time placing the frame within the Employee groupbox. You may have to select each frame and correct its size, depending on how you placed it originally. When you are done your form may look something like the one you see in Figure 4.

 

 

 

Figure 4. Two instances of the NameFrame appear on this form

 

5. Continue by placing two Table components onto the form. Set the DatabaseName property of both tables to IBLocal. Set the TableName property of Table1 to CUSTOMER and the TableName property of Table2 to EMPLOYEE. Make both tables active by setting their Active property to True.

 

6. Now here is where things get interesting. Select the data source in the Customer frame and set its DataSet property to Table1. Normally you cannot directly select objects that appear within a component. But frames are special. You can select any of the objects that appear within a frame and work with their properties. Next, repeat this operation by selecting the data source in the Employee frame and setting its DataSet property to Table2.

 

7. Finally, hook up all of the DBEdits. Assign the DataField property of the three DBEdits on the Customer frame to CUST_NO, CONTACT_FIRST, and CONTACT_LAST, respectively. For the Employee frame set the DataField properties of these same DBEdits to EMP_NO, FIRST_NAME, and LAST_NAME.

 

8. Save this project and then run it. The running project will look something like that shown in Figure 5.

 

 

 

Figure 5. The running frame project

 

Frames and Inheritance

Up to this point there may seem to be only a little benefit to the use of frames. However, it is when you use the same frame in a number of different situations, and then want to change all instances, that the power of frames really becomes obvious. For example, imagine that you decided that you want your NameFrame to be a read-only frame. This can be accomplished easily by simply changing the original frame. Each frame instance immediately inherits all changes.

You can demonstrate this yourself by following these steps:

 

1. With the project created in the preceding section open, press Shift-F12 and select NameFrame from the displayed list of forms.

 

2. Set the AutoEdit property of the DataSource to False.

 

3. Next, select the DBNavigator, expand its VisibleButtons property, and set the nbInsert, nbDelete, nbEdit, nbPost, and nbCancel flags to False.

 

4. Now look at your main form. Notice that both of the NameFrame descendants have inherited the changes that you made to the frame. Your frame may now look like the one shown in Figure 6.

 

 

 

Figure 6. Updating the NameFrame automatically causes all instances to be updated as well.

 

Overriding Contained Component Properties

 

One of the advantages of frames, one shared with VFI, is that you can change the properties and event handlers associated with the objects inside the inherited frame. These changes override the values inherited. Specifically, subsequent changes to the overridden property in the original frame has no affect on the inherited value.

 

The following steps demonstrate this behavior:

 

1. Select the label whose caption is ID in the Customer frame. Using the Object Inspector, change its Caption property to Customer No:. Now select the ID label for the Employee frame and change it to Employee ID:.

 

2. Press Shift-F12 and select the NameFrame. Change the Caption of this ID label to Identifier.

 

3. Return to the main form. Notice that the Caption properties of the labels have not changed to Identifier. They still use their overridden values.

 

This effect is accomplished through information stored in the DFM file. Figure 7 displays a relevant part of the DFM file for this project:

 

 

 

Figure 7. A DFM file containing property overrides for a frame instance

 

Notice that information about all components contained within the frame whose property values have been changed appear in the frame's inline section of the DFM file. This section, however, only lists those values that have been changed. All other properties are assigned their values based either on the values set for the original frame (and which are stored in the frame's DFM file), or are designated as default values in the individual component's class declarations.

 

Contained Object Event Handlers

Objects contained within a frame may also have event handlers. While events are simply properties of a method pointer type, they are treated differently than other types of properties when it comes to overriding the default behavior defined for the frame.

Let's begin by considering how an event handler is defined for a frame object. Consider the frame shown in Figure 8. (This code is found in the Frame2 project found in the download for this paper). This frame contains two buttons, one labeled Help and the other labeled Done. (Of course, these captions can be overridden in descendant frames). These buttons also have OnClick event handlers, shown in the following code segment:

 

procedure TTwoButtonFrame.Button1Click(Sender: TObject);

begin

  if (TComponent(Sender).Tag = 0) or

    (Application.HelpFile = '') then

    MessageBox(Application.Handle,'Help not available','Help',MB_OK)

  else

    Application.HelpContext(TComponent(Sender).Tag);

  end;

 

 

procedure TTwoButtonFrame.Button2Click(Sender: TObject);

var

  AParent: TComponent;

begin

  AParent := TComponent(Sender).GetParentComponent;

  while not (AParent is TCustomForm) do

  begin

    if AParent = nil then Exit;

    AParent := AParent.GetParentComponent;

  end;

  TCustomForm(AParent).Close;

end;

 

Figure 8. A frame with components that have event handlers

 

Just as the event handlers for objects on a form are published methods of that form's class, the event handlers of objects on a frame are published methods of that frame. (The code segment does not actually depict the fact that these methods are published, but they are declared in the default visibility section of the frame's class declaration, and the default visibility is published.)

 

If you inspect the code associated with the Button2Click event handler, which is associated with the Done button, you will notice that the fact that the event handlers are associated with the frame introduces an interesting artifact. Specifically, Self is the frame, and not the form in which the frame is contained. Consequently, it is not possible to simply invoke the Close method from within this event handler to close the form. When an unqualified method invocation appears in code, the compiler assumes that you want it to apply to Self. Since a TFrame object does not have a Close method, the compiler generates an error if you simply use an unqualified call to Close.

 

Since the frame in this example is designed to be embedded within a form, the event handler uses the GetParentComponent method of the frame to climb the containership hierarchy within which the frame is nested. Once a TCustomForm instance is found (which will either be a TForm descendant or a custom form based upon TCustomForm), that reference is used to invoke to containing form's Close method.

 

Overridding Contained Object Event Handlers

 

If you are familiar with event overriding in VFI you will recall that the IDE embeds a call to inherited from within an overridden event handler on a descendant form. You can then alter the generated code to either add additional behavior prior to, or following the call to inherited, conditionally invoke inherited, or omit the call altogether.

 

Frame descendants do not use inherited when invoking the event handler for an object embedded on the parent frame. Instead, the ancestor frame's method is called directly. For example, if you place the TwoButtonFrame frame (shown Figure onto a form and then double-click it, Delphi will generate the following code:

 

procedure TForm1.TwoButtonFrame1Button2Click(Sender: Object);

begin

  TwoButtonFrame1.Button2Click(Sender);

end;

In this generated code TwoButtonFrame1 is an instance of the TTwoButtonFrame (the defining frame class). Button2Click, as you saw in the earlier code segment, is the event handler for the Done button on that frame. As a result, what this code does is to invoke the defining classes riginal event handler, passing to it the Sender that was passed to the button on the frame instance.

This means of event handling introduces another interesting feature. Specifically, in these situations, Sender is generally not a member of the Self object. Indeed, Sender is usually a member of the form object, while Self is the frame object.

 

The following is an overridden event handler for a TwoButtonFrame instance that was placed on a form. Notice that in this case the original behavior is comment out, meaning that the new behavior completely replaces the originally defined behavior for the Done button.

 

procedure TForm1.TwoButtonFrame1Button2Click(Sender: TObject);<

begin

  with TForm2.Create(Self) do

  begin

    ShowModal;

    Release;

  end;

// The following is the original, auto-generated code

// TwoButtonFrame1.Button2Click(Sender);

end;

The Caption of this button was also overridden, so that it displays the text Start. Figure 9 shows the form on which this TwoButtonFrame descendant appears.

 

 

Figure 9. This TwoButtonFrame instances overrides both the Caption and the OnClick event handler.

 

Frames that Save Resources

The form shown in Figure 9 actually contains two frames. We have already discussed the TwoButtonFrame frame. The second frame is the one that shows the company logo. This frame is named LogoFrame.

The LogoFrame appears on more than one form in the FramDemo project. The alternative to using a frame to display the logo is to place an Image object on each form upon which you want the logo to appear. However, the use of a frame for this purpose significantly reduces the amount of resources that must be compiled into the .EXE, and therefore results in a smaller executable.

 

The reason for this can be seen if you consider this segment of the DFM file for the form shown in the preceding figure:

 

inline LogoFrame1: TLogoFrame

  Left = 6

  Top = 6

  Width = 211

  Height = 182

  inherited Image1: TImage

    Width = 211

    Height = 182

  end

end

If a TImage instance had been placed onto the form instead, the DFM file for the form would have had to contain the entire binary representation of the logo. Furthermore, each and every form containing one of these images would have repeated this resource. However, when a frame is used that resource is defined only once, as shown from this segment of the LogoFrame's DFM file:

object LogoFrame: TLogoFrame

  Left = 0

  Top = 0

  Width = 239

  Height = 178

  TabOrder = 0

  object Image1: TImage

  Left = 0

  Top = 0

  Width = 239

  Height = 178

  Align = alClient

  Picture.Data = {

    07544269746D6170D6540000424DD6540000000000007600000028000000F000

    0000B40000000100040000000000605400000000000000000000100000000000

    0000000000000000800000800000008080008000000080008000808000007F7F

    7F00BFBFBF000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFF

    FF00000000000000000000000000000000000000000000000000000000000000

    0000000000000000000000000000000000000000000044446C6C767677776767

Note that this segment includes less than 1% of the entire hexadecimal representation of the binary resource.

Simplifying Frame Usage

Within a single, small project it is fairly easy to use the Frame component on the Standard page of the component palette. But for larger projects, or for situations where you want to use the same frame in multiple applications, you need something easier. Fortunately, Delphi permits you to place individual frames onto the Component Palette, permitting these frames to be used easily and repeatedly, without the extra steps required by the Frame component. A frame can also be placed into the Object Repository, permitting it to be copied or inherited from easily. Both of these techniques are described in the following sections.

Adding a Frame to the Component Palette

By placing a particular frame onto the Component Palette, you make its placement as simple as placing almost any other component. By comparison, using the Frame component on the Standard page of the component palette requires four steps, and limits you to placing frames already defined within your project.

To place a particular frame onto the Component Palette, use the following steps:

 

1. Save your frame to disk. If you want to use this frame in multiple applications it is highly recommended that you save the frame to a directory that will not be deleted when you update Delphi. For example, create a folder named c:Program FilesBorlandDelphiFrames and store your frames there (you will also want to add this directory to your Library search path using the Enviroment Options dialog box).

 

2. Select the frame and right-click it. Select Add to Palette. Delphi displays the Component Template Information dialog box.

 

3. Define the name of the frame component in the Component Name field, the page of the Component Palette on which you want the frame to appear in the Palette page field, and, if you have created a custom 24 x 24 pixel, 16-color icon for the frame, use the Change button to select this bitmap file. Click OK when done.

 

Using a Frame from the Component Palette

To use a frame previously placed on the Component Palette, use the following steps:

1. Select the page of the Component Palette onto which you saved the frame.

 

2. Select the frame's icon and drop it onto the form on which you want an instance of that frame to appear. Notice that this process required only two steps, while using the Frame component from the Standard page requires four steps.

 

Adding a Frame to the Object Repository

By adding a frame to the object repository you make it easy to copy it into a new project. Especially important is the ability to use the inheritance offered by the Object Repository to place an inherited frame into a new project, thereby maintaining the relationship between the frame and its ancestor.

To add a frame to the Object Repository use the following steps:

 

1. Save your frame to disk. You can save this frame to any directory, including the same one to which you save frames that you add to the Component Palette, to Delphi's OBJREPOS directory, or to a shared directory. (Saving the frame to a shared directory is especially nice if you are using a shared object repository. This permits multiple developers to share one or more frames.)

 

2. Right-click the frame and select Add to Repository. Delphi responds by displaying the Add to Repository dialog box.

 

3. Fill out the Add to Repository dialog box just as you would for any template you are adding to the Object Repository. Click OK when done.

 

Using a Frame from the Object Repository

To use a frame from the Object Repository use the following steps:

1. Select File | New.

 

2. Select the page of the Object Repository to which you saved your frame template.

 

3. Select the icon for the frame and then click the Inherit radio button on the Object Repository dialog box.

 

4. Click OK to add an inherited version of the frame to your project.

 

Note that if you use the Copy radio button instead of the Inherit radio button, the newly adding frame will be a copy of the original frame. This is useful when you want to create a new frame, but do not want to maintain a relationship between the copy and the original.

 

Component Palette versus Object Repository

Does is make a difference whether you place a frame that you want to reuse on the Component Palette or the Object Repository? The answer is a strong "Yes!". In most cases you will want to place frames that you want to use frequently onto the Component Palette. When you place a frame from the Component Palette you are always placing an instance of the frame class. You can then easily change the properties and event handlers of this instance, as described earlier in this paper. By comparison, placing a frame from the Object Repository creates a new class, not an instance. This new class is either a copy of the original, or a descendant, depending on which radio button you select on the Object Repository dialog box.

If you want to use a frame in a project I personally think that it makes a great deal of sense to always place an instance, rather than define a new class for your frame. For this purpose, saving the frame to the Component Palette is the best approach.

 

The one situation where you might want to use the Object Repository is when you are specifically creating hierarchies of frames, where each frame descendant introduces additional objects, methods, or event handlers. Here the inheritance offered by the Object Repository makes it easier for you to create each new descendant. However, once you have define the frame descendants that you want to use regularly, I would again suggest that you add these to the Component Palette to simplify their use.

 

Turning Frames into True Components

Frames, like other classes that descend from TComponent, can be added to a design-time package in order to place the component on the Component palette. This is an interesting thing to do to a frame class, but it is not something that you will always want to do. Once you have placed a frame onto the Component palette, it is no longer treated as a frame by the designer. Instead it is treated like a compound component. The primary difference is that with a frame you can modify the properties of the objects contained in the frame, but with a compound component you cannot.

Because the power of frames lies in your ability to modify the frame at design time, you might be inclined to rule out ever adding a frame to the component palette. But there are times when adding a frame to the component palette makes a lot of sense. Once you have visually designed the frame, adding it to the component palette locks its features, preventing the component user from making changes to the encapsulated components. Also, once a frame has been added to the component palette, you can easily create an ActiveX wrapper for it.

 

Summary

A frame is a container class that permits you to visually design compound components. In addition, the design understands the relationship between a frame and the components it contains, permit you to override the properties and event handlers of objects that appear in frame instances. By including frames in your application, you can improve object reuse, reduce maintainance overhead, and make more efficient use of Windows resources.

 

About the Author

Cary Jensen is President of Jensen Data Systems, Inc., a Houston-based training and consulting company. He is an award-winning, best-selling co-author of eighteen books, including Building Kylix Applications (2001, Osborne Media Group), Oracle JDeveloper (1998, Oracle Press), JBuilder Essentials (1998, Osborne/McGraw-Hill), Delphi In Depth (1996, Osborne/McGraw-Hill), and Programming Paradox 5 for Windows (1995, Sybex). Cary is also Contributing Editor of Delphi Informant Magazine, where he writes the column DBNavigator. He is a popular speaker at conferences, workshops, and training seminars throughout North America and Europe. Cary has a Ph.D. in Human Factors Psychology, specializing in human-computer interaction. You can contact Cary at cjensen@JensenDataSystems.com. The Jensen Data Systems, Inc. web site is at www.JensenDataSystems.com.

Cary is available for onsite training in Delphi and Kylix. For information on available courses, please visit www.JensenDataSystems.com.

 

Delphi - .....................................

 

neoturk - ...Application design using frames ?...

When Delphi 5 first shipped, it included a new, visual container class that represents an important advance in rapid application development (RAD) programming. This class, TFrame, provides you with the ability to visually configure a set of one or more components, and then to easily reuse this configuration throughout your application. This capability is so powerful that Delphi 5's integrated development environment (IDE) was re-designed, making extensive use of frames. Frames are now available in C++ Builder 5 and later, as well as Kylix.

This paper provides you with a detailed overview of frames. It begins with a general discussion of what frames are and what benefits they provide. It continues with a demonstration of how to create frames, and how to modify the properties of objects that appear on frame instances. Next, you will learn how to create event handlers for frames, and how to override or extend these event handlers in frame instances. This paper concludes by showing you how to add frames to the Component Palette and the Object Repository, and what benefits you gain by doing so.

 

Overview of Frames

There are two primary benefits of frames. The first is that, under certain circumstances, frames can dramatically reduce the amount of resources that need to be stored in a project. The second, and generally more important benefit, is that frames permit you to visually create objects that can be duplicated from and extended. These happen to be the same two benefits that you enjoy with visual form inheritance (VFI).

VFI permits you to create form objects that can be inherited from easily. The main limit to VFI is that you must use the form in an all-or-nothing fashion. Specifically, when you use VFI you always create an entirely new form. Frames, on the other hand, are more similar to panels in this respect. That is, a single form can contain two or more frames. Importantly, every frame maintains its relationship with the  TFrame class that defines it, meaning that subsequent changes to the defining class are automatically inherited by the instances. While you could achieve a similar effect using TPanels, doing so would be a strictly code-based operation. That is, you would have to write the code to define the TPanel descendants manually. Frames, on the other hand, are designed visually, just like forms.

 

Frames can also be thought of as sharing some similarities with component templates (a group of one or more components that are saved to the component palette by selecting Component | Create Component Template). But the similarities are limited to the fact that both component templates and frames are designed visually (unlike traditional component design, which is an exclusively code-based process). But the differences between component templates and frames are actually very great. As you have already learned, a frame is an instance of a defining class, and as such, is changed when the defining class is changed. By comparison, component templates are aggregates of components. A change to a component template has no effect on objects previously created from that template.

 

Creating a Frame

The following steps demonstrate how to create a frame.

1. Begin by selecting File | New Application to create a new project.

 

2. Select File | New Frame to create a new Frame. Place on this frame 3 Labels and DBEdits. Also place a DBNavigator and a DataSource. Set the Captions of the Labels to ID, First Name, Last Name. Set the DataSource property of each DBEdit as well as the DBNavigator to DataSource1. When you are done the frame may look something like that shown in Figure 1.

 

 

 

Figure 1. A simple frame for displaying an ID number, as well as a first and last name.

 

3. With this frame still selected, set its Name property to NameFrame. More so than other objects, it is particularly important to give a frame a meaningful name. Finally, save the frame by selecting File | Save As to save this frame. In this case save the frame using the filename NAMEFRAM.PAS.

 

That's all there is to creating a frame. The following section demonstrates how to use this frame.

 

Using a Frame

A frame is a component. Its typical use, however, differs from other components that appear on the component palette. The following steps demonstrate how to use a frame.

1. Select Form1 of the application that you started in the preceding steps.

 

2. Add two group boxes to the form, one above the other. Set the Caption of the first groupbox to Customers and the caption of the second to Employees. Your form may look something like that shown in Figure 2.

 

 

 

Figure 2. A form ready for the placement of frames

 

3. Now add the frames. With the Standard page of the component palette selected, click on the Frame component and drop it within the Customer groupbox. The designer responds by displaying the Select frame to insert dialog box shown in Figure 3.

 

 

 

Figure 3. The Select frame to insert dialog box

 

4. Select NameFrame. The frame now appears within the Customer groupbox. Repeat this process, this time placing the frame within the Employee groupbox. You may have to select each frame and correct its size, depending on how you placed it originally. When you are done your form may look something like the one you see in Figure 4.

 

 

 

Figure 4. Two instances of the NameFrame appear on this form

 

5. Continue by placing two Table components onto the form. Set the DatabaseName property of both tables to IBLocal. Set the TableName property of Table1 to CUSTOMER and the TableName property of Table2 to EMPLOYEE. Make both tables active by setting their Active property to True.

 

6. Now here is where things get interesting. Select the data source in the Customer frame and set its DataSet property to Table1. Normally you cannot directly select objects that appear within a component. But frames are special. You can select any of the objects that appear within a frame and work with their properties. Next, repeat this operation by selecting the data source in the Employee frame and setting its DataSet property to Table2.

 

7. Finally, hook up all of the DBEdits. Assign the DataField property of the three DBEdits on the Customer frame to CUST_NO, CONTACT_FIRST, and CONTACT_LAST, respectively. For the Employee frame set the DataField properties of these same DBEdits to EMP_NO, FIRST_NAME, and LAST_NAME.

 

8. Save this project and then run it. The running project will look something like that shown in Figure 5.

 

 

 

Figure 5. The running frame project

 

Frames and Inheritance

Up to this point there may seem to be only a little benefit to the use of frames. However, it is when you use the same frame in a number of different situations, and then want to change all instances, that the power of frames really becomes obvious. For example, imagine that you decided that you want your NameFrame to be a read-only frame. This can be accomplished easily by simply changing the original frame. Each frame instance immediately inherits all changes.

You can demonstrate this yourself by following these steps:

 

1. With the project created in the preceding section open, press Shift-F12 and select NameFrame from the displayed list of forms.

 

2. Set the AutoEdit property of the DataSource to False.

 

3. Next, select the DBNavigator, expand its VisibleButtons property, and set the nbInsert, nbDelete, nbEdit, nbPost, and nbCancel flags to False.

 

4. Now look at your main form. Notice that both of the NameFrame descendants have inherited the changes that you made to the frame. Your frame may now look like the one shown in Figure 6.

 

 

 

Figure 6. Updating the NameFrame automatically causes all instances to be updated as well.

 

Overriding Contained Component Properties

 

One of the advantages of frames, one shared with VFI, is that you can change the properties and event handlers associated with the objects inside the inherited frame. These changes override the values inherited. Specifically, subsequent changes to the overridden property in the original frame has no affect on the inherited value.

 

The following steps demonstrate this behavior:

 

1. Select the label whose caption is ID in the Customer frame. Using the Object Inspector, change its Caption property to Customer No:. Now select the ID label for the Employee frame and change it to Employee ID:.

 

2. Press Shift-F12 and select the NameFrame. Change the Caption of this ID label to Identifier.

 

3. Return to the main form. Notice that the Caption properties of the labels have not changed to Identifier. They still use their overridden values.

 

This effect is accomplished through information stored in the DFM file. Figure 7 displays a relevant part of the DFM file for this project:

 

 

 

Figure 7. A DFM file containing property overrides for a frame instance

 

Notice that information about all components contained within the frame whose property values have been changed appear in the frame's inline section of the DFM file. This section, however, only lists those values that have been changed. All other properties are assigned their values based either on the values set for the original frame (and which are stored in the frame's DFM file), or are designated as default values in the individual component's class declarations.

 

Contained Object Event Handlers

Objects contained within a frame may also have event handlers. While events are simply properties of a method pointer type, they are treated differently than other types of properties when it comes to overriding the default behavior defined for the frame.

Let's begin by considering how an event handler is defined for a frame object. Consider the frame shown in Figure 8. (This code is found in the Frame2 project found in the download for this paper). This frame contains two buttons, one labeled Help and the other labeled Done. (Of course, these captions can be overridden in descendant frames). These buttons also have OnClick event handlers, shown in the following code segment:

 

procedure TTwoButtonFrame.Button1Click(Sender: TObject);

begin

  if (TComponent(Sender).Tag = 0) or

    (Application.HelpFile = '') then

    MessageBox(Application.Handle,'Help not available','Help',MB_OK)

  else

    Application.HelpContext(TComponent(Sender).Tag);

  end;

 

 

procedure TTwoButtonFrame.Button2Click(Sender: TObject);

var

  AParent: TComponent;

begin

  AParent := TComponent(Sender).GetParentComponent;

  while not (AParent is TCustomForm) do

  begin

    if AParent = nil then Exit;

    AParent := AParent.GetParentComponent;

  end;

  TCustomForm(AParent).Close;

end;

 

Figure 8. A frame with components that have event handlers

 

Just as the event handlers for objects on a form are published methods of that form's class, the event handlers of objects on a frame are published methods of that frame. (The code segment does not actually depict the fact that these methods are published, but they are declared in the default visibility section of the frame's class declaration, and the default visibility is published.)

 

If you inspect the code associated with the Button2Click event handler, which is associated with the Done button, you will notice that the fact that the event handlers are associated with the frame introduces an interesting artifact. Specifically, Self is the frame, and not the form in which the frame is contained. Consequently, it is not possible to simply invoke the Close method from within this event handler to close the form. When an unqualified method invocation appears in code, the compiler assumes that you want it to apply to Self. Since a TFrame object does not have a Close method, the compiler generates an error if you simply use an unqualified call to Close.

 

Since the frame in this example is designed to be embedded within a form, the event handler uses the GetParentComponent method of the frame to climb the containership hierarchy within which the frame is nested. Once a TCustomForm instance is found (which will either be a TForm descendant or a custom form based upon TCustomForm), that reference is used to invoke to containing form's Close method.

 

Overridding Contained Object Event Handlers

 

If you are familiar with event overriding in VFI you will recall that the IDE embeds a call to inherited from within an overridden event handler on a descendant form. You can then alter the generated code to either add additional behavior prior to, or following the call to inherited, conditionally invoke inherited, or omit the call altogether.

 

Frame descendants do not use inherited when invoking the event handler for an object embedded on the parent frame. Instead, the ancestor frame's method is called directly. For example, if you place the TwoButtonFrame frame (shown Figure onto a form and then double-click it, Delphi will generate the following code:

 

procedure TForm1.TwoButtonFrame1Button2Click(Sender: Object);

begin

  TwoButtonFrame1.Button2Click(Sender);

end;

In this generated code TwoButtonFrame1 is an instance of the TTwoButtonFrame (the defining frame class). Button2Click, as you saw in the earlier code segment, is the event handler for the Done button on that frame. As a result, what this code does is to invoke the defining classes riginal event handler, passing to it the Sender that was passed to the button on the frame instance.

This means of event handling introduces another interesting feature. Specifically, in these situations, Sender is generally not a member of the Self object. Indeed, Sender is usually a member of the form object, while Self is the frame object.

 

The following is an overridden event handler for a TwoButtonFrame instance that was placed on a form. Notice that in this case the original behavior is comment out, meaning that the new behavior completely replaces the originally defined behavior for the Done button.

 

procedure TForm1.TwoButtonFrame1Button2Click(Sender: TObject);<

begin

  with TForm2.Create(Self) do

  begin

    ShowModal;

    Release;

  end;

// The following is the original, auto-generated code

// TwoButtonFrame1.Button2Click(Sender);

end;

The Caption of this button was also overridden, so that it displays the text Start. Figure 9 shows the form on which this TwoButtonFrame descendant appears.

 

 

Figure 9. This TwoButtonFrame instances overrides both the Caption and the OnClick event handler.

 

Frames that Save Resources

The form shown in Figure 9 actually contains two frames. We have already discussed the TwoButtonFrame frame. The second frame is the one that shows the company logo. This frame is named LogoFrame.

The LogoFrame appears on more than one form in the FramDemo project. The alternative to using a frame to display the logo is to place an Image object on each form upon which you want the logo to appear. However, the use of a frame for this purpose significantly reduces the amount of resources that must be compiled into the .EXE, and therefore results in a smaller executable.

 

The reason for this can be seen if you consider this segment of the DFM file for the form shown in the preceding figure:

 

inline LogoFrame1: TLogoFrame

  Left = 6

  Top = 6

  Width = 211

  Height = 182

  inherited Image1: TImage

    Width = 211

    Height = 182

  end

end

If a TImage instance had been placed onto the form instead, the DFM file for the form would have had to contain the entire binary representation of the logo. Furthermore, each and every form containing one of these images would have repeated this resource. However, when a frame is used that resource is defined only once, as shown from this segment of the LogoFrame's DFM file:

object LogoFrame: TLogoFrame

  Left = 0

  Top = 0

  Width = 239

  Height = 178

  TabOrder = 0

  object Image1: TImage

  Left = 0

  Top = 0

  Width = 239

  Height = 178

  Align = alClient

  Picture.Data = {

    07544269746D6170D6540000424DD6540000000000007600000028000000F000

    0000B40000000100040000000000605400000000000000000000100000000000

    0000000000000000800000800000008080008000000080008000808000007F7F

    7F00BFBFBF000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFF

    FF00000000000000000000000000000000000000000000000000000000000000

    0000000000000000000000000000000000000000000044446C6C767677776767

Note that this segment includes less than 1% of the entire hexadecimal representation of the binary resource.

Simplifying Frame Usage

Within a single, small project it is fairly easy to use the Frame component on the Standard page of the component palette. But for larger projects, or for situations where you want to use the same frame in multiple applications, you need something easier. Fortunately, Delphi permits you to place individual frames onto the Component Palette, permitting these frames to be used easily and repeatedly, without the extra steps required by the Frame component. A frame can also be placed into the Object Repository, permitting it to be copied or inherited from easily. Both of these techniques are described in the following sections.

Adding a Frame to the Component Palette

By placing a particular frame onto the Component Palette, you make its placement as simple as placing almost any other component. By comparison, using the Frame component on the Standard page of the component palette requires four steps, and limits you to placing frames already defined within your project.

To place a particular frame onto the Component Palette, use the following steps:

 

1. Save your frame to disk. If you want to use this frame in multiple applications it is highly recommended that you save the frame to a directory that will not be deleted when you update Delphi. For example, create a folder named c:Program FilesBorlandDelphiFrames and store your frames there (you will also want to add this directory to your Library search path using the Enviroment Options dialog box).

 

2. Select the frame and right-click it. Select Add to Palette. Delphi displays the Component Template Information dialog box.

 

3. Define the name of the frame component in the Component Name field, the page of the Component Palette on which you want the frame to appear in the Palette page field, and, if you have created a custom 24 x 24 pixel, 16-color icon for the frame, use the Change button to select this bitmap file. Click OK when done.

 

Using a Frame from the Component Palette

To use a frame previously placed on the Component Palette, use the following steps:

1. Select the page of the Component Palette onto which you saved the frame.

 

2. Select the frame's icon and drop it onto the form on which you want an instance of that frame to appear. Notice that this process required only two steps, while using the Frame component from the Standard page requires four steps.

 

Adding a Frame to the Object Repository

By adding a frame to the object repository you make it easy to copy it into a new project. Especially important is the ability to use the inheritance offered by the Object Repository to place an inherited frame into a new project, thereby maintaining the relationship between the frame and its ancestor.

To add a frame to the Object Repository use the following steps:

 

1. Save your frame to disk. You can save this frame to any directory, including the same one to which you save frames that you add to the Component Palette, to Delphi's OBJREPOS directory, or to a shared directory. (Saving the frame to a shared directory is especially nice if you are using a shared object repository. This permits multiple developers to share one or more frames.)

 

2. Right-click the frame and select Add to Repository. Delphi responds by displaying the Add to Repository dialog box.

 

3. Fill out the Add to Repository dialog box just as you would for any template you are adding to the Object Repository. Click OK when done.

 

Using a Frame from the Object Repository

To use a frame from the Object Repository use the following steps:

1. Select File | New.

 

2. Select the page of the Object Repository to which you saved your frame template.

 

3. Select the icon for the frame and then click the Inherit radio button on the Object Repository dialog box.

 

4. Click OK to add an inherited version of the frame to your project.

 

Note that if you use the Copy radio button instead of the Inherit radio button, the newly adding frame will be a copy of the original frame. This is useful when you want to create a new frame, but do not want to maintain a relationship between the copy and the original.

 

Component Palette versus Object Repository

Does is make a difference whether you place a frame that you want to reuse on the Component Palette or the Object Repository? The answer is a strong "Yes!". In most cases you will want to place frames that you want to use frequently onto the Component Palette. When you place a frame from the Component Palette you are always placing an instance of the frame class. You can then easily change the properties and event handlers of this instance, as described earlier in this paper. By comparison, placing a frame from the Object Repository creates a new class, not an instance. This new class is either a copy of the original, or a descendant, depending on which radio button you select on the Object Repository dialog box.

If you want to use a frame in a project I personally think that it makes a great deal of sense to always place an instance, rather than define a new class for your frame. For this purpose, saving the frame to the Component Palette is the best approach.

 

The one situation where you might want to use the Object Repository is when you are specifically creating hierarchies of frames, where each frame descendant introduces additional objects, methods, or event handlers. Here the inheritance offered by the Object Repository makes it easier for you to create each new descendant. However, once you have define the frame descendants that you want to use regularly, I would again suggest that you add these to the Component Palette to simplify their use.

 

Turning Frames into True Components

Frames, like other classes that descend from TComponent, can be added to a design-time package in order to place the component on the Component palette. This is an interesting thing to do to a frame class, but it is not something that you will always want to do. Once you have placed a frame onto the Component palette, it is no longer treated as a frame by the designer. Instead it is treated like a compound component. The primary difference is that with a frame you can modify the properties of the objects contained in the frame, but with a compound component you cannot.

Because the power of frames lies in your ability to modify the frame at design time, you might be inclined to rule out ever adding a frame to the component palette. But there are times when adding a frame to the component palette makes a lot of sense. Once you have visually designed the frame, adding it to the component palette locks its features, preventing the component user from making changes to the encapsulated components. Also, once a frame has been added to the component palette, you can easily create an ActiveX wrapper for it.

 

Summary

A frame is a container class that permits you to visually design compound components. In addition, the design understands the relationship between a frame and the components it contains, permit you to override the properties and event handlers of objects that appear in frame instances. By including frames in your application, you can improve object reuse, reduce maintainance overhead, and make more efficient use of Windows resources.

 

About the Author

Cary Jensen is President of Jensen Data Systems, Inc., a Houston-based training and consulting company. He is an award-winning, best-selling co-author of eighteen books, including Building Kylix Applications (2001, Osborne Media Group), Oracle JDeveloper (1998, Oracle Press), JBuilder Essentials (1998, Osborne/McGraw-Hill), Delphi In Depth (1996, Osborne/McGraw-Hill), and Programming Paradox 5 for Windows (1995, Sybex). Cary is also Contributing Editor of Delphi Informant Magazine, where he writes the column DBNavigator. He is a popular speaker at conferences, workshops, and training seminars throughout North America and Europe. Cary has a Ph.D. in Human Factors Psychology, specializing in human-computer interaction. You can contact Cary at cjensen@JensenDataSystems.com. The Jensen Data Systems, Inc. web site is at www.JensenDataSystems.com.

Cary is available for onsite training in Delphi and Kylix. For information on available courses, please visit www.JensenDataSystems.com.

 

Delphi - .....................................

 

neoturk - ...Simple html to text converter ?...

I often get questions like: "How can I cut out the text I wan't from a HTML-file ?"

One way to do this is to first remove all taginformation, and make a clean textfile of it. How can I do that? Well it's quite simple. A HTML-file consists of tags and text. Everything that's surrounded by a '<' and a '>' - character is what we call tags. Tags is information which the webbrowser will respond to in different ways. On the other hand, things between a '>' and '<' is pure text (with some exceptions), which the browser will write to the screen.

Lets consider two exceptions in our simple converter: '&nbsp;' - nonbreaking space and '&quot;' - quotation mark.

Let's convert the break-tag '<BR>' to a carriage return (#13#10).

Finally we delete empty lines and save the file with a txt-extension.

 

Here's the code:

 

 

 

 

procedure TForm1.ConvertHTMLToText(FileName: TFileName);

var

  Dummy: TStringList;

  Str, ResText: string;

  Count, n: Integer;

  MayBeText: Boolean;

begin

  Dummy:= TStringList.Create;

  try

    Dummy.LoadFromFile(FileName);

    Str:= Dummy.Text;

    Count:= 0;

    MayBeText:= false;

    ResText:= '';

    for n:= 1 to Length(Str) do

    begin

      if Count > 0 then

        Dec(Count)

      else

      begin

        if (Str[n] = '&') and   // &NBSP;

          (Uppercase(Str[n + 1]) = 'N') and

          (Uppercase(Str[n + 2]) = 'B') and

          (Uppercase(Str[n + 3]) = 'S') and

          (Uppercase(Str[n + 4]) = 'P') and

          (Uppercase(Str[n + 5]) = ';') then

        begin

          // Skip next five chars

          Count:= 5;

          ResText:= ResText + ' ';

        end

        else

           if (Str[n] = '&') and  // &QUOT;

            (Uppercase(Str[n + 1]) = 'Q') and

            (Uppercase(Str[n + 2]) = 'U') and

            (Uppercase(Str[n + 3]) = 'O') and

            (Uppercase(Str[n + 4]) = 'T') and

            (Uppercase(Str[n + 5]) = ';') then

          begin

            // Skip next five chars

            Count:= 5;

            ResText:= ResText + '"';

          end

          else

            if MayBeText and (Str[n] <> '<') then  // Consider as text

              ResText:= ResText + Str[n];

        if Str[n] = '<' then

        begin

          MayBeText:= false;

          // <BR>

          if (Uppercase(Str[n + 1]) = 'B') and (Uppercase(Str[n + 2]) = 'R') and

            (Uppercase(Str[n + 3]) = '>') then

            ResText:= ResText + #13#10;

        end;

        if Str[n] = '>' then

          MayBeText:= true;

      end;

    end;

    Str:= '';

    Str:= ResText;

    ResText:= '';

    Count:= 0;

    // suppress empty lines

    for n:= 1 to Length(Str) do

    begin

      if Count > 0 then

        Dec(Count)

      else

      begin

        if (Str[n] = #13) and (Str[n + 1] = #10) and (Str[n + 2] = #13) and

          (Str[n + 3] = #10) then

          Count:= 1

        else

          ResText:= ResText + Str[n];

      end;

    end;

    Dummy.Text:= ResText;

    Dummy.SaveToFile(Copy(FileName, 1, Pos('.', FileName)) + 'txt');

  finally

    Dummy.Free;

  end;

end;

 

Delphi - .....................................

 

neoturk - ...Simple html to text converter ?...

I often get questions like: "How can I cut out the text I wan't from a HTML-file ?"

One way to do this is to first remove all taginformation, and make a clean textfile of it. How can I do that? Well it's quite simple. A HTML-file consists of tags and text. Everything that's surrounded by a '<' and a '>' - character is what we call tags. Tags is information which the webbrowser will respond to in different ways. On the other hand, things between a '>' and '<' is pure text (with some exceptions), which the browser will write to the screen.

Lets consider two exceptions in our simple converter: '&nbsp;' - nonbreaking space and '&quot;' - quotation mark.

Let's convert the break-tag '<BR>' to a carriage return (#13#10).

Finally we delete empty lines and save the file with a txt-extension.

 

Here's the code:

 

 

 

 

procedure TForm1.ConvertHTMLToText(FileName: TFileName);

var

  Dummy: TStringList;

  Str, ResText: string;

  Count, n: Integer;

  MayBeText: Boolean;

begin

  Dummy:= TStringList.Create;

  try

    Dummy.LoadFromFile(FileName);

    Str:= Dummy.Text;

    Count:= 0;

    MayBeText:= false;

    ResText:= '';

    for n:= 1 to Length(Str) do

    begin

      if Count > 0 then

        Dec(Count)

      else

      begin

        if (Str[n] = '&') and   // &NBSP;

          (Uppercase(Str[n + 1]) = 'N') and

          (Uppercase(Str[n + 2]) = 'B') and

          (Uppercase(Str[n + 3]) = 'S') and

          (Uppercase(Str[n + 4]) = 'P') and

          (Uppercase(Str[n + 5]) = ';') then

        begin

          // Skip next five chars

          Count:= 5;

          ResText:= ResText + ' ';

        end

        else

           if (Str[n] = '&') and  // &QUOT;

            (Uppercase(Str[n + 1]) = 'Q') and

            (Uppercase(Str[n + 2]) = 'U') and

            (Uppercase(Str[n + 3]) = 'O') and

            (Uppercase(Str[n + 4]) = 'T') and

            (Uppercase(Str[n + 5]) = ';') then

          begin

            // Skip next five chars

            Count:= 5;

            ResText:= ResText + '"';

          end

          else

            if MayBeText and (Str[n] <> '<') then  // Consider as text

              ResText:= ResText + Str[n];

        if Str[n] = '<' then

        begin

          MayBeText:= false;

          // <BR>

          if (Uppercase(Str[n + 1]) = 'B') and (Uppercase(Str[n + 2]) = 'R') and

            (Uppercase(Str[n + 3]) = '>') then

            ResText:= ResText + #13#10;

        end;

        if Str[n] = '>' then

          MayBeText:= true;

      end;

    end;

    Str:= '';

    Str:= ResText;

    ResText:= '';

    Count:= 0;

    // suppress empty lines

    for n:= 1 to Length(Str) do

    begin

      if Count > 0 then

        Dec(Count)

      else

      begin

        if (Str[n] = #13) and (Str[n + 1] = #10) and (Str[n + 2] = #13) and

          (Str[n + 3] = #10) then

          Count:= 1

        else

          ResText:= ResText + Str[n];

      end;

    end;

    Dummy.Text:= ResText;

    Dummy.SaveToFile(Copy(FileName, 1, Pos('.', FileName)) + 'txt');

  finally

    Dummy.Free;

  end;

end;

 

Delphi - .....................................

 

neoturk - ...Creating asp com objects with delphi 5-6 ?...

Creating ASP com objects, or Active Server Objects with Delphi 5-6 is very easy, once you know how to do it!

 

What follows is a step by step instruction for creating your first ASP com object.

 

File - New - ActiveX - ActiveX Library

File - New - ActiveX - Active Server Object

CoClassName=janaspdemo

Instancing=Muliple Instance

Threading Model=Both

Active Server Type=Page Level Events Model

Options= (checked) Generate a template test script for this object

In the type libary editor select Ijanaspdemo

Click Method on the toolbar and enter report as method name.

Select the parameters tab

Click under Name and type strInOut

Click under Type and select Variant*

Click under Modifier, click the ellipsed and check In and Out in the flags popup

Click Refresh on the toolbar

Move the type library editor window away so that you can see Unit1 which was generated by the type library editor.

 

Press ctrl+F12 (view units) and select Project1_TLB

 

Have a look at the type library generated by the editor. You normally don't have to touch the Porject1_TLB unit, as the type library editor will do the changes for you.

 

View Unit1 , positition the cursor on procedure report and press ctrl+shift+down to jump to the procedure report implementation. You can see that the type library editor has created an empty sceleton for you.

 

For the time being just type // implement later between the begin and end;

 

Switch back to the type library editor.

 

In the type libary editor select Ijanaspdemo

Click Property Read/Write on the toolbar

Change the first property1 name to heading. The second porperty1 will be automatically changed to heading as well.

Select the first heading, the one with modifier [out,retval] and long* as Type.

Click under Type and select Variant* (we want the header to be a string, not an integer)

Select the second heading, the one with modifier [in] and long as Type.

Click under Type and select BSTR.

Click Refresh on the toolbar.

Now first have a look in Project1_TLB and look below: Ijanaspdemo = interface(IDispatch)

 

See how the type library editor has added three lines:

 

function Get_heading: WideString; safecall;

 

procedure Set_heading(const Value: WideString); safecall;

 

property heading: WideString read Get_heading write Set_heading;

 

Move to Unit1 and have a look at the top part:

 

function Get_heading: WideString; safecall;

 

procedure Set_heading(const Value: WideString); safecall;

 

Note that you don't see a property here, just the Get_heading and Set_heading function and procedure.

 

Note

 

When adding methods or properties to an Active Server Object, always do this in the type library editor. This will create the code for you, both in Project1_TLB and in Unit1.

 

Put the cursor on function get_heading and press ctrl+shift+down to jump to the implementation part.

 

See that it is still empy. In this case I want both the get_heading and the set_heading to use a private field.

 

Go to the top and insert the private FHeading as shown below:

 

type

 

Tjanaspdemo = class(TASPObject, Ijanaspdemo)

 

private

 

FHeading:widestring;

 

protected

 

procedure OnEndPage; safecall;

 

You don't have to do this is you want to handle your header in a different way, but many times you just want to use a private field of the object.

 

Now go the Get_heading implementation and type:

 

result:=FHeading;

 

Go to the Set_heading implementation and type:

 

FHeading:=Value;

 

Now it is time to save your project.

 

Press the Save All button on the IDE toolbar.

Save the unit as janspdemoU.pas

Save the asp template as janaspdemo.asp

Save the project as janaspdemo.

Build the project and register the asp component with Run - Register ActiveX Server.

 

Your janaspdemo component is contained within the just generated janaspdemo.dll.

 

 

 

Modify the asp file

 

You are now ready to modify the asp template.

 

Open it with e.g. Notepad.

 

It contains the following:

 

<HTML>

 

<BODY>

 

<TITLE> Testing Delphi ASP </TITLE>

 

<CENTER>

 

<H3> You should see the results of your Delphi Active Server method below </H3>

 

</CENTER>

 

<HR>

 

<% Set DelphiASPObj = Server.CreateObject("janaspdemo.janaspdemo")

 

DelphiASPObj.{Insert Method name here}

 

%>

 

<HR>

 

</BODY>

 

</HTML>

 

 

 

Change Server.CreateObject("Project1.janaspdemo") to

 

Server.CreateObject("janaspdemo.janaspdemo")

 

Change DelphiASPObj.{Insert Method name here} to

 

DelphiASPObj.heading ="my first aspdemo heading"

 

Response.write DelphiASPObj.heading

 

Save janaspdemo.asp

 

We are not ready yet but first something important:

 

When you request an asp page in your browser from Personal Web Server, any dll loaded will remain in memory, even after you move to a different page, or after you closed your browser, or even after you stopped PWS. This means that when in Delphi you try to make changes and recompile you get a message telling you that the output file can not be created. This is because it has not been released from memory.

 

Can we then only recompile after we have restarted the computer?

 

How do I unlock a Active Server Library DLL?

At first I thought that the only way to unlock a ASP component DLL was to reboot the computer. There is however a better way.

 

Create a new start menu shortcut:

 

c:windowssysteminetsrvpws.exe /stop /y

 

It is the /y that does the trick. Not only will it stop PWS, as does the stop button in the Personal Web Manager, but it will also unload the Inetinfo.exe process from memory, unlocking any locked ASP component library DLL's.

 

This way you can compile your ASP component with Delphi, start your web application and use the just created shortcut to unload the DLL from memory, allowing you to recompile from Delphi without rebooting your computer. A big time saver!

 

C:WINDOWSSYSTEMinetsrvinetinfo.exe -e w3svc will restart PWS

 

Unlocking Active Server Library DLL's under Windows NT

 

Type net stop iisadmin /y to shutdown the parent service of IIS, IIS Admin. This will also shut down FTP, STMP, and any other services that are children of IIS Admin. It will unload the inetinfo.exe process from memory. If you type only net stop w3svc, to unload just the Web server, inetinfo.exe will not be unloaded.

 

Type net start w3svc to restart the Web server.

 

So how do I test an asp component?

The way to go here is to create a new project specifically for testing your asp component.

 

Somethings just can't be checked within a test project but most routines can be checked and tested and it will save you a lot of rebooting.

 

Create a test application

As explained above, asp components created with server.createobject stay in memory until you shutdown your computer. This prohibits recompiling from Delphi. So the way out is a test application.

 

Start a new Delphi project with File - New Application.

Add a private field to the form: FVar:OleVariant;

In the formcreate event handler include: FVar:=createoleobject('janaspdemo.janaspdemo');

In the formdestroy event handler include: FVar:=Unassigned;

You can now add buttons,menu items, text boxes etc, to the form. Whatever you need to test the asp component.

 

You can set the heading with: Fvar.heading:="my first heading";

 

Or retrieve it with s:=Fvar.heading;

 

Delphi - .....................................

 

neoturk - ...Creating asp com objects with delphi 5-6 ?...

Creating ASP com objects, or Active Server Objects with Delphi 5-6 is very easy, once you know how to do it!

 

What follows is a step by step instruction for creating your first ASP com object.

 

File - New - ActiveX - ActiveX Library

File - New - ActiveX - Active Server Object

CoClassName=janaspdemo

Instancing=Muliple Instance

Threading Model=Both

Active Server Type=Page Level Events Model

Options= (checked) Generate a template test script for this object

In the type libary editor select Ijanaspdemo

Click Method on the toolbar and enter report as method name.

Select the parameters tab

Click under Name and type strInOut

Click under Type and select Variant*

Click under Modifier, click the ellipsed and check In and Out in the flags popup

Click Refresh on the toolbar

Move the type library editor window away so that you can see Unit1 which was generated by the type library editor.

 

Press ctrl+F12 (view units) and select Project1_TLB

 

Have a look at the type library generated by the editor. You normally don't have to touch the Porject1_TLB unit, as the type library editor will do the changes for you.

 

View Unit1 , positition the cursor on procedure report and press ctrl+shift+down to jump to the procedure report implementation. You can see that the type library editor has created an empty sceleton for you.

 

For the time being just type // implement later between the begin and end;

 

Switch back to the type library editor.

 

In the type libary editor select Ijanaspdemo

Click Property Read/Write on the toolbar

Change the first property1 name to heading. The second porperty1 will be automatically changed to heading as well.

Select the first heading, the one with modifier [out,retval] and long* as Type.

Click under Type and select Variant* (we want the header to be a string, not an integer)

Select the second heading, the one with modifier [in] and long as Type.

Click under Type and select BSTR.

Click Refresh on the toolbar.

Now first have a look in Project1_TLB and look below: Ijanaspdemo = interface(IDispatch)

 

See how the type library editor has added three lines:

 

function Get_heading: WideString; safecall;

 

procedure Set_heading(const Value: WideString); safecall;

 

property heading: WideString read Get_heading write Set_heading;

 

Move to Unit1 and have a look at the top part:

 

function Get_heading: WideString; safecall;

 

procedure Set_heading(const Value: WideString); safecall;

 

Note that you don't see a property here, just the Get_heading and Set_heading function and procedure.

 

Note

 

When adding methods or properties to an Active Server Object, always do this in the type library editor. This will create the code for you, both in Project1_TLB and in Unit1.

 

Put the cursor on function get_heading and press ctrl+shift+down to jump to the implementation part.

 

See that it is still empy. In this case I want both the get_heading and the set_heading to use a private field.

 

Go to the top and insert the private FHeading as shown below:

 

type

 

Tjanaspdemo = class(TASPObject, Ijanaspdemo)

 

private

 

FHeading:widestring;

 

protected

 

procedure OnEndPage; safecall;

 

You don't have to do this is you want to handle your header in a different way, but many times you just want to use a private field of the object.

 

Now go the Get_heading implementation and type:

 

result:=FHeading;

 

Go to the Set_heading implementation and type:

 

FHeading:=Value;

 

Now it is time to save your project.

 

Press the Save All button on the IDE toolbar.

Save the unit as janspdemoU.pas

Save the asp template as janaspdemo.asp

Save the project as janaspdemo.

Build the project and register the asp component with Run - Register ActiveX Server.

 

Your janaspdemo component is contained within the just generated janaspdemo.dll.

 

 

 

Modify the asp file

 

You are now ready to modify the asp template.

 

Open it with e.g. Notepad.

 

It contains the following:

 

<HTML>

 

<BODY>

 

<TITLE> Testing Delphi ASP </TITLE>

 

<CENTER>

 

<H3> You should see the results of your Delphi Active Server method below </H3>

 

</CENTER>

 

<HR>

 

<% Set DelphiASPObj = Server.CreateObject("janaspdemo.janaspdemo")

 

DelphiASPObj.{Insert Method name here}

 

%>

 

<HR>

 

</BODY>

 

</HTML>

 

 

 

Change Server.CreateObject("Project1.janaspdemo") to

 

Server.CreateObject("janaspdemo.janaspdemo")

 

Change DelphiASPObj.{Insert Method name here} to

 

DelphiASPObj.heading ="my first aspdemo heading"

 

Response.write DelphiASPObj.heading

 

Save janaspdemo.asp

 

We are not ready yet but first something important:

 

When you request an asp page in your browser from Personal Web Server, any dll loaded will remain in memory, even after you move to a different page, or after you closed your browser, or even after you stopped PWS. This means that when in Delphi you try to make changes and recompile you get a message telling you that the output file can not be created. This is because it has not been released from memory.

 

Can we then only recompile after we have restarted the computer?

 

How do I unlock a Active Server Library DLL?

At first I thought that the only way to unlock a ASP component DLL was to reboot the computer. There is however a better way.

 

Create a new start menu shortcut:

 

c:windowssysteminetsrvpws.exe /stop /y

 

It is the /y that does the trick. Not only will it stop PWS, as does the stop button in the Personal Web Manager, but it will also unload the Inetinfo.exe process from memory, unlocking any locked ASP component library DLL's.

 

This way you can compile your ASP component with Delphi, start your web application and use the just created shortcut to unload the DLL from memory, allowing you to recompile from Delphi without rebooting your computer. A big time saver!

 

C:WINDOWSSYSTEMinetsrvinetinfo.exe -e w3svc will restart PWS

 

Unlocking Active Server Library DLL's under Windows NT

 

Type net stop iisadmin /y to shutdown the parent service of IIS, IIS Admin. This will also shut down FTP, STMP, and any other services that are children of IIS Admin. It will unload the inetinfo.exe process from memory. If you type only net stop w3svc, to unload just the Web server, inetinfo.exe will not be unloaded.

 

Type net start w3svc to restart the Web server.

 

So how do I test an asp component?

The way to go here is to create a new project specifically for testing your asp component.

 

Somethings just can't be checked within a test project but most routines can be checked and tested and it will save you a lot of rebooting.

 

Create a test application

As explained above, asp components created with server.createobject stay in memory until you shutdown your computer. This prohibits recompiling from Delphi. So the way out is a test application.

 

Start a new Delphi project with File - New Application.

Add a private field to the form: FVar:OleVariant;

In the formcreate event handler include: FVar:=createoleobject('janaspdemo.janaspdemo');

In the formdestroy event handler include: FVar:=Unassigned;

You can now add buttons,menu items, text boxes etc, to the form. Whatever you need to test the asp component.

 

You can set the heading with: Fvar.heading:="my first heading";

 

Or retrieve it with s:=Fvar.heading;

 

Delphi - .....................................

 

neoturk - ...Date-time-day client-server with com ?...

This example shows step by step how to make a COM Client-Server application that informs about current date, time and weekday. The Server will have three methods: GetDate, GetTime and GetWeekDay. The server could run local or remote.

 

The Server:

 

Select: New application.

Put a Label on the Form and in the caption write: "DateTimeDay-server" or whatever you like. This form will be shown when the server executes.

Select: New-ActiveX-Automation Object.

Give the Object a CoClass name: MasDateTime

Instancing: Multiple instance

Threading model: Both

Click OK.

 

 

In the Project-Library wizard:

 

Click on the interface: IMasDateTime

Select: New - Method. Give the method a name: GetDate

Select: Parameters - and in return type select: widestring (or BSTR* if you're using IDL. You can change this if you wan't to: Select Tools/Environmental options/Type Library and change Language.)

Do the same with GetTime and GetWeekDay.

Refresh implementation, and save the project as: MasTDD.dpr.

If everything is OK, your project should consist of: Unit1 and Form1, Unit2 and the typelibrary: MasTDD_TLB.

The typelibrary is where the description of your interface is, normally you don't have to change here. Unit2 is where the implementation is done.

 

 

 

 

Take a look at Unit2. As you can see, the wizard has already made a skeleton for your methods. Let's fill it with some code:

 

 

 

function TMasDateTime.GetDate: WideString;

begin

  Result:= DateToStr(Now);

end;

 

function TMasDateTime.GetTime: WideString;

begin

  Result:= TimeToStr(Now);

end;

 

function TMasDateTime.GetWeekDay: WideString;

var

  Day: integer;

begin

  Day:= DayOfTheWeek(Now);

  case Day of

    1: Result:= 'Monday';

    2: Result:= 'Tuesday';

    3: Result:= 'Wednesday';

    4: Result:= 'Thursday';

    5: Result:= 'Friday';

    6: Result:= 'Saturday';

    7: Result:= 'Sunday';

  end;

end;

 

 

Put: SysUtils, DateUtils in the Uses clause.

Compile and save the project.

 

 

 

The Client :

 

Choose: New application.

Put five buttons, a Label and an EditBox on the Form.

Save the unit as Cl.pas and the project as Client.dpr

Put: MASTDD_TLB in the upper uses clause:

Put this code in the private clause:

Server: IMasDateTime;

 

Here's the rest of the code:

 

 

 

implementation

 

{$R *.dfm}

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  ShowMessage(Server.GetDate);

end;

 

procedure TForm1.Button4Click(Sender: TObject);

begin

  Server:= CoMasDateTime.CreateRemote(Edit1.Text);

end;

 

procedure TForm1.Button2Click(Sender: TObject);

begin

  ShowMessage(Server.GetTime);

end;

 

procedure TForm1.Button3Click(Sender: TObject);

begin

  ShowMessage(Server.GetWeekDay);

end;

 

procedure TForm1.Button5Click(Sender: TObject);

begin

  Server:= CoMasDateTime.Create;

end;

 

end.

 

Delphi - .....................................

 

neoturk - ...Date-time-day client-server with com ?...

This example shows step by step how to make a COM Client-Server application that informs about current date, time and weekday. The Server will have three methods: GetDate, GetTime and GetWeekDay. The server could run local or remote.

 

The Server:

 

Select: New application.

Put a Label on the Form and in the caption write: "DateTimeDay-server" or whatever you like. This form will be shown when the server executes.

Select: New-ActiveX-Automation Object.

Give the Object a CoClass name: MasDateTime

Instancing: Multiple instance

Threading model: Both

Click OK.

 

 

In the Project-Library wizard:

 

Click on the interface: IMasDateTime

Select: New - Method. Give the method a name: GetDate

Select: Parameters - and in return type select: widestring (or BSTR* if you're using IDL. You can change this if you wan't to: Select Tools/Environmental options/Type Library and change Language.)

Do the same with GetTime and GetWeekDay.

Refresh implementation, and save the project as: MasTDD.dpr.

If everything is OK, your project should consist of: Unit1 and Form1, Unit2 and the typelibrary: MasTDD_TLB.

The typelibrary is where the description of your interface is, normally you don't have to change here. Unit2 is where the implementation is done.

 

 

 

 

Take a look at Unit2. As you can see, the wizard has already made a skeleton for your methods. Let's fill it with some code:

 

 

 

function TMasDateTime.GetDate: WideString;

begin

  Result:= DateToStr(Now);

end;

 

function TMasDateTime.GetTime: WideString;

begin

  Result:= TimeToStr(Now);

end;

 

function TMasDateTime.GetWeekDay: WideString;

var

  Day: integer;

begin

  Day:= DayOfTheWeek(Now);

  case Day of

    1: Result:= 'Monday';

    2: Result:= 'Tuesday';

    3: Result:= 'Wednesday';

    4: Result:= 'Thursday';

    5: Result:= 'Friday';

    6: Result:= 'Saturday';

    7: Result:= 'Sunday';

  end;

end;

 

 

Put: SysUtils, DateUtils in the Uses clause.

Compile and save the project.

 

 

 

The Client :

 

Choose: New application.

Put five buttons, a Label and an EditBox on the Form.

Save the unit as Cl.pas and the project as Client.dpr

Put: MASTDD_TLB in the upper uses clause:

Put this code in the private clause:

Server: IMasDateTime;

 

Here's the rest of the code:

 

 

 

implementation

 

{$R *.dfm}

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  ShowMessage(Server.GetDate);

end;

 

procedure TForm1.Button4Click(Sender: TObject);

begin

  Server:= CoMasDateTime.CreateRemote(Edit1.Text);

end;

 

procedure TForm1.Button2Click(Sender: TObject);

begin

  ShowMessage(Server.GetTime);

end;

 

procedure TForm1.Button3Click(Sender: TObject);

begin

  ShowMessage(Server.GetWeekDay);

end;

 

procedure TForm1.Button5Click(Sender: TObject);

begin

  Server:= CoMasDateTime.Create;

end;

 

end.

 

Delphi - .....................................

 

neoturk - ...Email validation ?...

Here is a little function that will validate an EMail-address.

It will check the EMail:s basic construction with five different tests.

You cannot, of course, be sure that the address will be a working one, but at least it will have all chances to it!

 

Here is what it will check:

 

That the "@"-character is present.

That there's at least one character before "@".

That there's at least one dot (".") after "@".

That there's at least one character between "@" and the dot.

That there's at least one character after the dot.

 

function EMailValid(EMail: string): Boolean;

begin

  Result:= false;

  if Pos('@', EMail) > 0 then

    if Length(Copy(EMail, 1, Pos('@', EMail) - 1)) > 0 then

      if Pos('.', Copy(EMail, Pos('@', EMail) + 1, 1000)) > 0 then

        if Length(Copy(EMail, Pos('@', EMail) + 1, Pos('.', Copy(EMail, Pos('@',

          EMail) + 1, 1000)))) > 0 then

          if Length(Copy(EMail, Pos('.', EMail) + 1, 1000)) > 0 then

            Result:= true;

end;

 

Delphi - .....................................

 

neoturk - ...Email validation ?...

Here is a little function that will validate an EMail-address.

It will check the EMail:s basic construction with five different tests.

You cannot, of course, be sure that the address will be a working one, but at least it will have all chances to it!

 

Here is what it will check:

 

That the "@"-character is present.

That there's at least one character before "@".

That there's at least one dot (".") after "@".

That there's at least one character between "@" and the dot.

That there's at least one character after the dot.

 

function EMailValid(EMail: string): Boolean;

begin

  Result:= false;

  if Pos('@', EMail) > 0 then

    if Length(Copy(EMail, 1, Pos('@', EMail) - 1)) > 0 then

      if Pos('.', Copy(EMail, Pos('@', EMail) + 1, 1000)) > 0 then

        if Length(Copy(EMail, Pos('@', EMail) + 1, Pos('.', Copy(EMail, Pos('@',

          EMail) + 1, 1000)))) > 0 then

          if Length(Copy(EMail, Pos('.', EMail) + 1, 1000)) > 0 then

            Result:= true;

end;

 

Delphi - .....................................

 

neoturk - ...Drag - drop example ?...

Have you ever been using WinAmp? If you haven't, I could tell you that it's a widely spread freeware

music-mediaplayer, where you can have a tracklist with your favourite songs. The songs in this list could very

easy be moved to any position with the use of drag & drop functionality.

This example shows how to implement it with Delphi.

 

 

 

 

 

{-----------------------------------------------------------------------------

 Unit Name: Unit1

 Author: Mats Asplund

 Description: Drag & drop example with a Listbox as source and destination.

-----------------------------------------------------------------------------}

 

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

  StdCtrls;

 

type

  TForm1 = class(TForm)

    ListBox1: TListBox;

    procedure ListBox1DragOver(Sender, Source: TObject; X, y: Integer;

      State: TDragState; var Accept: Boolean);

    procedure ListBox1DragDrop(Sender, Source: TObject; X, y: Integer);

    procedure ListBox1MouseDown(Sender: TObject; Button: TMouseButton;

      Shift: TShiftState; X, y: Integer);

    procedure FormCreate(Sender: TObject);

  private

    FromPos, ToPos: TPoint;

    procedure MoveItem(FromPos, ToPos: Integer);

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

{$R *.DFM}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  ListBox1.DragMode:= dmAutomatic;

  // Fill the listbox with some items

  ListBox1.Items.Add('Item 1');

  ListBox1.Items.Add('Item 2');

  ListBox1.Items.Add('Item 3');

  ListBox1.Items.Add('Item 4');

  ListBox1.Items.Add('Item 5');

end;

 

procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, y: Integer;

  State: TDragState; var Accept: Boolean);

begin

  // Accept Listbox as source

  Accept:= Source is TListBox;

end;

 

procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, y: Integer);

begin

  // Put coordinates in ToPos

  ToPos.X:= X;

  ToPos.y:= y;

  // Check that both sender and source is a ListBox

 

  if (Sender is TListBox) and (Source is TListBox) then

  begin

    // Get ListBox-item indexes and send them to the MoveItem procedure

    MoveItem(ListBox1.ItemAtPos(FromPos, true), ListBox1.ItemAtPos(ToPos,

      true));

  end;

end;

 

procedure TForm1.ListBox1MouseDown(Sender: TObject; Button: TMouseButton;

  Shift: TShiftState; X, y: Integer);

begin

  // Get sourceitem position

  FromPos.X:= X;

  FromPos.y:= y;

end;

 

procedure TForm1.MoveItem(FromPos, ToPos: Integer);

var

  n: Integer;

  DummyList: TStringList;

begin

  DummyList:= TStringList.Create;

  try

    if (FromPos > -1) and (ToPos > -1) then

    begin

 

      // Copy listbox to DummyList

      DummyList.Text:= ListBox1.Items.Text;

 

      if FromPos > ToPos then

      begin

        // If item is dragged downwards rearrange the list this way

        ListBox1.Items[ToPos]:= ListBox1.Items[FromPos];

        for n:= (ToPos + 1) to FromPos do

          ListBox1.Items[n]:= DummyList[n - 1];

      end

      else

      begin

        // If item is dragged upwards rearrange the list this way

        ListBox1.Items[ToPos]:= ListBox1.Items[FromPos];

        for n:= (ToPos - 1) downto FromPos do

          ListBox1.Items[n]:= DummyList[n + 1];

      end;

 

    end;

  finally

    DummyList.Free;

  end;

end;

 

end.

 

Delphi - .....................................

 

neoturk - ...Drag - drop example ?...

Have you ever been using WinAmp? If you haven't, I could tell you that it's a widely spread freeware

music-mediaplayer, where you can have a tracklist with your favourite songs. The songs in this list could very

easy be moved to any position with the use of drag & drop functionality.

This example shows how to implement it with Delphi.

 

 

 

 

 

{-----------------------------------------------------------------------------

 Unit Name: Unit1

 Author: Mats Asplund

 Description: Drag & drop example with a Listbox as source and destination.

-----------------------------------------------------------------------------}

 

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

  StdCtrls;

 

type

  TForm1 = class(TForm)

    ListBox1: TListBox;

    procedure ListBox1DragOver(Sender, Source: TObject; X, y: Integer;

      State: TDragState; var Accept: Boolean);

    procedure ListBox1DragDrop(Sender, Source: TObject; X, y: Integer);

    procedure ListBox1MouseDown(Sender: TObject; Button: TMouseButton;

      Shift: TShiftState; X, y: Integer);

    procedure FormCreate(Sender: TObject);

  private

    FromPos, ToPos: TPoint;

    procedure MoveItem(FromPos, ToPos: Integer);

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

{$R *.DFM}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  ListBox1.DragMode:= dmAutomatic;

  // Fill the listbox with some items

  ListBox1.Items.Add('Item 1');

  ListBox1.Items.Add('Item 2');

  ListBox1.Items.Add('Item 3');

  ListBox1.Items.Add('Item 4');

  ListBox1.Items.Add('Item 5');

end;

 

procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, y: Integer;

  State: TDragState; var Accept: Boolean);

begin

  // Accept Listbox as source

  Accept:= Source is TListBox;

end;

 

procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, y: Integer);

begin

  // Put coordinates in ToPos

  ToPos.X:= X;

  ToPos.y:= y;

  // Check that both sender and source is a ListBox

 

  if (Sender is TListBox) and (Source is TListBox) then

  begin

    // Get ListBox-item indexes and send them to the MoveItem procedure

    MoveItem(ListBox1.ItemAtPos(FromPos, true), ListBox1.ItemAtPos(ToPos,

      true));

  end;

end;

 

procedure TForm1.ListBox1MouseDown(Sender: TObject; Button: TMouseButton;

  Shift: TShiftState; X, y: Integer);

begin

  // Get sourceitem position

  FromPos.X:= X;

  FromPos.y:= y;

end;

 

procedure TForm1.MoveItem(FromPos, ToPos: Integer);

var

  n: Integer;

  DummyList: TStringList;

begin

  DummyList:= TStringList.Create;

  try

    if (FromPos > -1) and (ToPos > -1) then

    begin

 

      // Copy listbox to DummyList

      DummyList.Text:= ListBox1.Items.Text;

 

      if FromPos > ToPos then

      begin

        // If item is dragged downwards rearrange the list this way

        ListBox1.Items[ToPos]:= ListBox1.Items[FromPos];

        for n:= (ToPos + 1) to FromPos do

          ListBox1.Items[n]:= DummyList[n - 1];

      end

      else

      begin

        // If item is dragged upwards rearrange the list this way

        ListBox1.Items[ToPos]:= ListBox1.Items[FromPos];

        for n:= (ToPos - 1) downto FromPos do

          ListBox1.Items[n]:= DummyList[n + 1];

      end;

 

    end;

  finally

    DummyList.Free;

  end;

end;

 

end.

Bu web sitesi ücretsiz olarak Bedava-Sitem.com ile oluşturulmuştur. Siz de kendi web sitenizi kurmak ister misiniz?
Ücretsiz kaydol