menu
  Home  ==>  articles  ==>  web  ==>  intraweb_tutorial   

IntraWeb Tutorial - John COLIBRI.


1 - Présentation IntraWeb

Intraweb est un jeu de composants Delphi permettant de développer des applications Web de façon visuelle: le développeur choisit ses composants sur la Palette, les dépose sur la Forme, modifie ses propriétés dans l'Inspecteur d'Objet, et effectue des traitements dans du code Pascal (Delphi)

Depuis Delphi 2, Borland a fait de gros efforts pour nous offrir des composants permettant de créer des sites Web. Ces composants (WebBroker, WebSnap) étaient cependant surtout orientés vers la création de pages dynamiques par code. La partie construction visuelle de la présentation de la page (mise en page, image, couleurs) n'était pas possible visuellement.

Personne n'a compris pourquoi une société capable de poser et ajuster quelques labels et boutons sur une tForm Windows a choisi de ne pas permettre de poser quelques labels et boutons sur une future page .HTML.

C'est donc ce vide immense qui a été comblé par Intraweb, et nous allons présenter l'utilisation de cette technique.

Nous allons utiliser Delphi 2006, mais ce que nous présentons pourrait être réalisé avec les composants Intraweb disponibles pour les versions Delphi 5, Delphi 6, Delphi 7, Delphi 8, Delphi 2005, Delphi 2006, Turbo Delphi et Delphi 2007




2 - La Première Applications IntraWeb

Commençons par l'exemple simple de la calculette:
   l'utilisateur tape l'adresse Web d'une page permettant de faire des multiplications
   son explorateur web lui présente une page avec 2 Edit et un bouton
   l'utilisateur tape 2 nombre et clic le bouton
   son explorateur lui renvoie le résultat


Nous allons donc construire une page Web
  • avec deux Edit et un Bouton
  • lorsque l'utilisateur cliquera le bouton, nous calculerons le résultat et l'afficherons dans un label


Par conséquent
   créez sur votre disque un dossier 01_calculator
   lancez Delphi 2006
   lancez le Wizard Intraweb en sélectionnant "File | New | Other | Intraweb | Intraweb wizard"

image

L'emplacement des Wizards Intraweb dans les menus Delphi ainsi que le contenu des différents dialogues varie avec les versions de Delphi, mais le mécanisme reste le même

   Intraweb présente un dialogue permettant spécifier le type d'application Intraweb que vous souhaitez créer

image

   les valeurs par défaut ("StandAlone", et "with Datamodule") conviennent. Ajoutez simplement le chemin

    C:\programs\fr\web\intraweb\01_calculator

et le nom de votre projet

    p_01_calculator

et cliquez "Ok"

   Intraweb crée 3 unités
  • celle qui communiquera le Serveur Web
  • celle qui gèrera les sessions
  • et surtout l'unité correspondant à la page que verra l'utilisateur
Ces fichiers sont visibles dans le gestionnaire de projet:

image

   sauvegardez le projet et ses unités avec des noms correspondant à l'application dans le bon répertoire.

Cette étape peut être sautée, mais notre expérience de Delphi 2006 nous a appris à effectuer cette sauvegarde avant de poursuivre. Donc sélectionnez chaque unité tour à tour et sélectionnez "Save As" pour

  • sauvegarder ServerController sous le nom de u_01_server_controller
  • sauvegarder UserSessionUnit sous le nom de u_01_user_session_unit
  • sauvegarder Unit1 sous le nom de u_01_calculator
en vérifiant que chaque fichier va bien dans notre répertoire

Puis, dans u_01_server_controler, dans le USES, changez le nom UserSessionUnit en u_01_user_session_unit

   Compilez pour vérifier que tout est cohérent

   comme nous utilisons XP avec son pare feu Internet, la sécurité Windows nous demande si nous acceptons exécuter ce programme

image

   cliquez "Débloquer"

   le Serveur IntraWeb est affiché

image

   fermez ce Serveur (l'icône "x" en haut à droite)

   de retour dans Delphi, sélectionnez la page u_01_calculator (pas le contrôleur ou la session).

Puis dans la Palette, sélectionnez la page correspondant aux composants visuels "IW Standard", puis sélectionnez un tIwEdit

image

et posez-le sur la Forme.

Posez-en un second, puis, de la même page de la Palette, un tIwButton et un tIwLabel

   La Forme aura l'allure suivante:

image

   créez l'événement qui va calculer la multiplication en double-cliquant sur IwButton1 (exactement comme pour une application Windows), et tapez le code qui va effectuer le calcul

procedure TIWForm1.IWButton1Click(SenderTObject);
  begin
    IwLabel1.Caption:= 
      IntToStr(StrToInt(IwEdit1.Text)* StrToInt(IwEdit2.Text));
  end// IWButton1Click

   compilez

   le Serveur Internet Intraweb est affiché:

image

   lancez l'explorateur Web
  • soit en cliquant sur l'icône désignée par la flèche rouge
  • soit en tapant F9
  • soit par le menu "File | Execute"
   Internet Explorer est lancé, et notre page est présentée:

image

   tapez deux nombres, par exemple 3 et 5 et cliquez "IwButton1"

   le résultat est affiché dans Internet Explorer

image



Notez que:
  • nous avons utilisé IntraWeb en mode "StandAlone": notre application contient en fait un Serveur Web qui est chargé de fournir notre page à Internet Explorer. Il existe un autre mode, dit mode "Page" dont nous parlerons à la fin de notre présentation
  • comme indiqué, l'emplacement dans les menus Delphi du Wizard qui lance le serveur Standalone peut varier énormément selon la version de Delphi. Mais en naviguant un peu dans ces menus, il n'est guère difficile de trouver la page Intraweb, et sur cette page une icône correspondant au mode Standalone
  • lorsque nous exécutons le projet et lançons le Serveur (F9 ou l'icône verte), il ne faut pas trop tarder à remplir la page et cliquer sur le bouton. Il y a en effet une temporisation qui peut bloquer la réponse. Dans ce cas relancez l'exécution Delphi


Nous allons à présent examiner le principe du fonctionnement Intraweb, puis présenter quelques exemples d'applications simples utilisant Intraweb.




3 - Le fonctionnement Intraweb

3.1 - Fonctionnement Internet

Un petit rappel rapide sur le fonctionnement des sites Web:
   un développeur écrit des fichiers avec une syntaxe spéciale (.HTML) correspondant à ses pages. Voici par exemple une page simple avec un texte de bienvenue:

 
<HTML>
  <BODY>
    Bienvenue sur notre site
  </BODY>
</HTML>

La page, qui peut être rédigée en utilisant NotePad (ou tout autre éditeur de texte ASCII) est sauvegardée sur disque, sous le nom de HELLO.HTML, par exemple

save_html_file

   le développeur lance un Serveur Web, qui est une application qui écoute et attend les requêtes provenant de clients. Ce serveur peut être IIS (Internet Information Server), Apache, un serveur Web écrit en utilisant des Sockets Delphi:

start_web_server

   un utilisateur lance un explorateur web (Internet Explorer, Netscape, un client Web écrit avec des Sockets Delphi, ...), et demande à l'explorateur web de rapporter la page HELLO.HTML:

start_web_browser

   le Serveur Web localise HELLO.HTM, l'envoie vers l'explorateur, qui l'affiche:

the_requested_page_is_displayed



3.2 - Fonctionnement Intraweb en mode Application

Si nous utilisons Intraweb,
  • la construction du texte .HTML de la page sera fait de façon visuelle en posant des composants sur la Forme. Les propriétés de ces composants seront utilisées par Intraweb pour générer le fichier .HTML
  • le Serveur Web est un Le fichier .HTML résultant


Ceci peut être schématisé ainsi:
   le développeur charge Delphi avec les composants Intraweb:

delphi_and_intraweb

   en utilisant la Palette, l'Inspecteur d'Objet et les Formes, il construit ses pages et compile l'application, qui est placée sur disque, dans un fichier nommé, par exemple, HELLO.EXE:

create_intraweb_application

   cette application est lancée, et elle correspond à un Serveur Web Intraweb, plus les paramètres des pages construites:

start_intraweb_application

   un utilisateur lance un explorateur web (Internet Explorer, Netscape, un client Web écrit avec des Sockets Delphi, ...), et demande à l'explorateur web de rapporter la page HELLO.HTML:

start_browser_request

   le Serveur Web Intraweb utilise les paramètres de la Forme pour construire la page HELLO.HTML, et la retourne au client qui l'affiche:

intraweb_server_response



La génération d'une page .HTML à partir d'un Forme n'est en fait pas très complexe: il suffit d'analyser les propriétés des contrôles et générer les balises .HTML (<BODY>, <INPUT> etc) correspondantes. Nous avons d'ailleurs présenté dans l'article Delphi Web Designer un projet Delphi permettant de générer une page .HTML à l'aide de contrôles Delphi (tPanel, tEdit, tLabel ...) posés sur une tForm. Notre générateur est bien entendu très simplet par rapport aux contrôles IntraWeb, mais il permet de comprendre le principe. De plus, Intraweb a ajouté le Serveur Web, et même le lancement de l'Explorateur Web.



3.3 - Architecture IntraWeb en mode Application

Voici la structure d'un projet IntraWeb en mode Application:

intraweb_architecture

et:

  • nous utiliserons le Serveur Web IntraWeb (plutôt que les composants WebBroker)
  • ce Serveur est construit à l'aide des composants Indy. Ceci explique d'ailleurs les possibilités SSL (Secure Socket Layer, ou encore mode TCP/IP sécurisé) offertes par Intraweb
  • IwServerController est chargé de gérer l'application, et en particulier
    • les sessions utilisateur
    • les exceptions
    Voici un diagramme de classe UML simplifié (les classes Intraweb représentées sont celles de Delphi 6):

    intraweb_servercontroller

    Les pages sont appelées par un Explorateur Web en utilisant une URL ayant la structure suivante (visible sur la capture d'écran ci-dessus):

    intraweb_url

    et:

    • le port est spécifié par tIwServerController.Port
    • le type de commande est géré par tIwServerController.ExecCmd
    • chaque session a un identificateur (calculé, entre autres, à l'aide de la date), utilisé par les cookies ou les champs cachés
  • tIwAppForm est l'ancêtre de toutes nos formes. Cette classe sert de conteneur pour tous les contrôles et permet de définir les propriétés des pages. Le diagramme de classe simplifié est le suivant:

    intraweb_iwappform

  • pour mettre en page nos Formes, tIwAppForm utilise un descendant de tIwLayoutMgr

    intraweb_iwlayoutmgr

    Si aucun tIwLayoutManager n'est placé sur la Forme, un gestionnaire de position est créé par défaut.



3.4 - Forme CGI

Nos schémas ci-dessus ont présenté la mécanique de requête de page par un Explorateur, et la réponse .HTML du Serveur Web.

Lorsque la page .HTML contient des zones de saisie (texte, checkbox, bouton radio, listbox), il y a un double aller-retour entre l'Explorateur et le Serveur.

Tout d'abord, il faut comprendre que la mécanique utilisée pour qu'un utilisateur échange des informations avec un Serveur est l'antique technique des <FORM> .HTML. Elle fonctionne ainsi:
   le développeur place dans son texte .HTML une balise <FORM> à l'intérieur de laquelle se trouvent des balises pour:
  • au moins un bouton
  • des contrôles de saisie. Par exemple un Edit
Voici une telle page pour convertir des Euros en Dollars:

web_form

et le texte .HTML correspondant est le suivant:

 
<HTML>
  <HEAD>
  </HEAD>
  <BODY>
    <FORM METHOD="POST"
        ACTION="http://www.jcolibri.com/convert.exe">
      valeur en euro ?
      <INPUT TYPE="edit"NAME="les_euros"><BR>
      <INPUT TYPE="submit"VALUE="convertis"><BR>
    </FORM>
  </BODY>
</HTML>

  • <INPUT TYPE="edit" ...> est l'Edit
  • <INPUT TYPE="submit" ...> est le bouton
  • <FORM METHOD="POST" ACTION="http://www.jcolibri.com/convert.exe"> est la balise qui définit le formulaire Web. Cette balise indique quel est le logiciel sur le Serveur qui traitera la conversion: CONVERT.EXE
   le développeur crée donc ce logiciel. Le contenu de ce type de programme a été présenté dans l'article CGI Form. Ce type de logiciel est donc placé sur le Serveur Web:

   le Serveur Web est lancé (IIS, Netscape ...)

Voici alors la situation:

cgi_save_html_exe

   un utilisateur lance son Explorateur, et demande la page EURO.HTML:

cgi_user_request

   le Serveur retourne la page avec la <FORM>:

cgi_server_answer

   l'utilisateur entre un montant (123, par exemple) et clique le bouton "convertis"

cgi_user_fills_and_sends_form

   le Serveur
  • analyze les paramètres (la valeur 123)
  • charge CONVERT.EXE et lui transmet les paramètres
  • CONVERT.EXE effectue la conversion, et construit une nouvelle page .HTML. Supposons que cette réponse contienne uniquement la valeur ne dollars ($ 166). Cette page est renvoyée au Serveur
  • le Serveur retourne cette page .HTML à l'utilisateur
et l'Explorateur affiche la réponse:

cgi_exe_computes_and_builds_response



Le point extrêmement important est que le traitement du "clic" est effectué sur le Serveur. Cette mécanique est chevillée dans le protocole .HTML, et est identique que nous mettions en oeuvre CGI, ISAPI, NSAPI, ASP, ASP.NET ou ... Intraweb. Pour résumer

  • l'utilisateur récupère une <FORM> .HTML
  • il remplit les différentes informations (Edit, CheckBox etc) et envoie les données qu'il a fourni en cliquant un Bouton
  • le Serveur récupère ces informations et en fait ce qu'il veut. En général, il renvoie au moins un accusé de réception, ou bien retourne la même page mise à jour, ou encore renvoie un autre page .HTML


Lorsque nous utilisons une page .HTML construite avec Intraweb et qui contient des contrôles, la mécanique est la même, sauf que
  • le Serveur Web est le Serveur Intraweb
  • ce Serveur est utilisé pour envoyer toutes les pages .HTML: aussi bien la page initiale, que les pages calculées en réponse aux valeurs retournées par l'Explorateur clique sur un Bouton. Et c'est le code situé dans l'événement OnClick du bouton qui est utilisé pour effectuer la suite des traitements (mise à jour d'une base de données, intégration des valeurs dans une réponse etc)
  • tous les calculs se font donc sur le Serveur, et par du code Delphi usuel. Vous avez donc accès à tout: les PROCEDUREs, les CLASSes, les UNITs, les bases de données etc. Et dans un langage décent, pas dans un langage de script à la syntaxe ahurissante.


Le schéma final devient dans ce cas:

cgi_standalone_intraweb

Notez que:

  • TOUTES nos pages, plus le Serveur Intraweb sont contenus dans un seul .EXE (en mode Application).


Nous avons présenté la mécanique CGI pour bien illustrer le fonctionnement sous-jacent. Mais vous n'aurez pas à programmer de CGI, ISAPI, d'écrire de balises .HTML etc: c'est Intraweb qui mettra tout en place. C'est ce que nous allons examiner à présent.




4 - Quelques Techniques IntraWeb

4.1 - Exemples IntraWeb

Maintenant que nous avons présenté un premier exemple ainsi que le fonctionnement de base d'IntraWeb, nous allons examiner quelques exemples un peu plus élaborés:
  • navigation entre plusieurs pages - échange de données entre pages
  • utilisation de contrôles liées aux bases de données (BDE, Interbase, ADO)
  • affichage dans des tIwDbEdit, tIwDbGrid
  • modification de tIwDbGrid


4.2 - Navigation entre plusieurs pages

4.2.1 - Transfert de page

Un site est en général composé de plusieurs pages .HTML, et l'utilisateur navigue d'une page à une autre en utilisant des hyper-liens ou des boutons.

Dans le cas d'Intraweb

  • nous créons autant de pages Intraweb additionnelles que nous souhaitons en utilisant "File | New | Other | Intraweb | New Form"
  • Intraweb gère une pile de pages actives, et
    • au lancement c'est la page par défaut qui est ajoutée à la pile
    • lorsque l'utilisateur clique un bouton, le Serveur prend la main, en fait dans le OnClick du bouton de la page cliquée. Pour que le Serveur renvoie une page vers l'utilisateur, il faut
      • créer la seconde page

        var my_iw_paget_my_iw_page;

          my_iw_page:= t_my_iw_page.Create(WebApplication);

      • l'ajouter au sommet de la pile en appelant:

        my_iw_page.Show

      ce qui peut, dans ce cas de "création + affichage" être abrégé par:

      t_my_iw_page.Create(WebApplication).Show

    • lorsque nous souhaitons qu'une page ne soit pas retournée à l'utilisateur, nous appelons:

      my_iw_page.Hide

      et

      • la page est retirée de la liste des pages actives
      • la page située au sommet de la pile est retournée à l'utilisateur
Notez que:
  • les nouvelles pages sont ajoutées par "File | New | Other | Intraweb | New Form", PAS en ajoutant une nouvelle Forme Windows ("File | New | Form")
  • pour retourner une nouvelle page, il FAUT utiliser iw_page.Show(), et jamais ShowModal. De même pour supprimer une page, il faut utiliser iw_page.Hide() (et pas Visible:= False). Ce sont en effet ces deux primitives Show() et Hide() qui gèrent la pile des pages IntraWeb


4.2.2 - Exemple de transfert de page

Voici un exemple avec deux pages: la première calcule le taux du dollar, la seconde renvoie la valeur.

Commençons par créer une application IntraWeb:
   lancez une nouvelle application IntraWeb par "File | New | Other | Intraweb | Intraweb Application Wizard"
   le wizard est affiché
   tapez le chemin et le nom de l'application, par exemple P_02_TWO_PAGES. et cliquez "OK"
   la nouvelle application est créée
   modifiez aussi le nom de UNIT1 en U_02_TWO_PAGES_1, et le nom de tIwForm1 en tIwForm_page_1
   compilez pour vérifier


Ajoutons la seconde page:
   sélectionnez "File | New | Other | Intraweb | New Form"

new_intraweb_form

   un dialogue de sélection de type de page est affiché:

intraweb_new_form_wizard

   sélectionnez "Application Form", et cliquez "Ok"
   une nouvelle unité avec sa tIwForm est créée
   renommez l'unité U_02_TWO_PAGE_2, et la tIwForm tIwForm_page_2
   compilez pour vérifier


Garnissons la première page
   sélectionnez U_02_TWO_PAGES_1
   de l'onglet "IW Standard" de la Tools Palette, sélectionnez un tIwLabel posez-le sur la Forme, et changez son Caption en "valeur en euros"
   de l'onglet "IW Standard", sélectionnez un tIwEdit, et initialisez Text à une valeur par défaut, par exemple 123
   de l'onglet "IW Standard", sélectionnez un tIwButton, nommez-le "convert", créez son événement OnClick, et calculez la valeur en dollar (multiplication par 1.35 environ), et effectuez le transfert de page:

procedure TIWForm_page_1.convertClick(SenderTObject);
  var l_eurol_dollarDouble;
      l_c_iwform_page_2tiwform_page_2;
  begin
    l_euro:= StrToFloat(IwEdit1.Text);
    l_dollar:= l_euro* 1.35;

    l_c_iwform_page_2:= tiwform_page_2.Create(WebApplication);
    l_c_iwform_page_2.iwlabel1.Caption:= IwEdit1.Text
        + ' euros = 'FloatToStr(l_dollar)+ ' US $';
    l_c_iwform_page_2.Show();

    // -- same as
    // with tiwform_page_2.Create(WebApplication) do
    // begin
    //   iwlabel1.Caption:= IwEdit1.Text+ ...ooo...
    //   Show;
    // end;
  end// convertClick

Ajoutez aussi, après IMPLEMENTATION l'importation de la page 2:

implementation
  uses u_02_two_pages_2;



Et pour que la seconde page permette de revenir à la page 1 pour entrer une nouvelle valeur:
   sélectionnez U_02_TWO_PAGES_2
   de l'onglet "IW Standard" de la Tools Palette, sélectionnez un tIwLabel posez-le sur la Forme
   de l'onglet "IW Standard", sélectionnez un tIwButton, nommez-le "backbutton", créez son événement OnClick, et retirez la seconde page de la pile

procedure TiwForm_page_2.backbuttonClick(SenderTObject);
  begin
    Hide();
    // Release();
  end// backbuttonClick

   compilez et exécutez
   le Serveur est affiché
   clickez l'icône pour lancer l'Explorateur
   la page 1 est affichée

intraweb_default_page

   tapez une valeur et cliquez "convert"
   la seconde page est affichée

intraweb_page_transfer

   cliquez "backbutton"
   la première page est affichée à nouveau:

intraweb_back_to_page_1



Notez que

  • l'URL affiche un nombre d'aller et retour croissant: 0, 1, 2
  • le SessionId en revanche reste le même
  • pour une raison inconnue, nous ne pouvons pas utiliser des Name comportant un souligné "_"


4.2.3 - Architecture de la pile des pages

Au niveau architecture, la CLASS tIwApplication gère les différentes pages (formes):

intraweb_iwapplication

et lorsqu'un nouvel utilisateur se connecte, tIwControllerBase lance une nouvelle session, ce qui crée une nouvelle tIwApplication avec une nouvelle liste de pages, et une page active:

intraweb_servercontroller_application_form

et par la suite, cet utilisateur ajoute ou retire des pages actives à sa liste par Show() et Hide().



4.2.4 - Création et Destruction

Show() et Hide() ne font que manipuler la présence de la page au sommet de la pile, et ne gèrent ni la création, ni la suppression de l'objet.

Pour créer une page, il faut utiliser, comme nous l'avons indiqué ci-dessus:

t_my_iw_page.Create(WebApplication)

et pour libérer une page:

my_iw_page.Release



En fait dans l'exemple ci-dessus nous avons utilisé page_2.Hide(), alors que nous aurions du employer page_2.Release()

Comme chaque page a un référence vers tIwApplication qui contient la liste des pages, il est possible, à titre de debugging, de visualiser cette liste:
   sélectionnez U_02_TWO_PAGES_1
   de l'onglet "IW Standard" de la Tools Palette, sélectionnez un tIwListBox et posez-la sur la Forme
   sélectionnez un tIwButton, nommez-le "pagestack", créez son événement OnClick, et affichez la liste des pages (exécuté par le Serveur lorsqu'il traitera pagelist.Click)

procedure TIWForm_page_1.pagestackbuttonClick(SenderTObject);
  var l_form_indexInteger;
  begin
    with IwListBox1 do
    begin
      Clear;
      for l_form_index:= 0 to WebApplication.FormCount- 1 do
        Items.Add(WebApplication.Forms[l_form_index].Name);
    end// with iwIlistBox1
  end// pagestackbuttonClick

   compilez, exécutez et lancez l'Explorateur
cliquez sur "pagestackbutton"
   notre page est affichée, ainsi qu'un item "--no_selection--" et IwUserSession (qui est le DataModule créé par défaut par le Wizard)

intraweb_page_stack_intial

   cliquez trois fois sur "convert" et "backbutton", et sur "pagelistbutton"
   la pile des page contient bien plusieurs pages 2:

intraweb_page_stack



Maintenant que vous comprenez la mécanique, plusieurs solutions sont possibles:

  • dans la seconde page, dans backbutton.Click, utiliser Release() au lieu de Hide()
  • placer la variable l_c_page_2 dans TIWForm_page_1, et ne créer la seconde page que si cet attribut est NIL
  • placer l_c_page_2 dans un tDataModule associé à la session (cf plus bas)
Notez aussi que
  • une même page (instance de tIwForm_nnn) peut être référencée plusieurs fois dans la pile des pages. Cela peu se produire lorsque l'application exige que cette page soit présentées à plusieurs reprises après des visites à d'autres pages. Si nous appelons Release(), toutes ces instances seront libérées
  • une fois une tiwForm créée, elle existe tant que vous ne la supprimez pas par t_iwForm.Release(). Il est donc très simple de transférer des données d'une page à l'autre en accédant à ses contrôles (ce que nous avons fait en initialisant page_2.Label depuis page_1.ButtonClick), ou à des attributs PUBLIC
  • comme l'ensemble des pages utilise des Threads, il ne faut PAS utiliser des variables globales. Plusieurs alternatives sont possible
    • utiliser les attributs des pages en mémoire
    • utiliser les tDataModules associés à la session (cf plus bas)
    • en dernier recours, utiliser des tThreadVars


4.2.5 - Lancement depuis un Client distant

Pour le moment nous avons affiché nos pages via le Serveur Standalone. Naturellement nos utilisateurs seront sur une machine éloignée, et c'est eux qui lanceront la demande d'une page de notre site.

En fait, il suffit dans Internet Explorer de fournir l'adresse et le port (si ce n'est pas le port 80) pour obtenir la page principale, puis de naviguer à partir de là.

Nous utilisons à l'Institut Pascal un réseau local, et le poste sur lequel est le Serveur Intraweb a l'adresse IP 152.178.41.18 (lancez ipconfig.exe pour éventuellement connaître l'adresse de votre poste). Pour effectuer notre essai, il faut connaître le port. Par conséquent
   compilez votre projet et lancez le Serveur Standalone
   sélectionnez, dans cette application "Tools | Start URL"
   l'URL est copiée dans le presse-papier
   copiez cet URL dans un fichier ASCII
   le port est 8888
   allez sur un autre poste du réseau, lancez Internet Explorer et dans la barre d'adresse, tapez

    http://152.178.41.18:8888/ Entrée

   la page est affichée dans Internet Explorer, comme précédemment


4.3 - Bases de Données

4.3.1 - Un tdbEdit et une Table BDE (dBase)

Commençons par afficher dans des dbEdit les champs de la Table ANIMALS.DBF. Nous allons
  • placer les composants d'accès aux bases de données sur le tDataModule UserSession
  • initialiser la connection avec la base
  • ajouter à la tIwForm quelques champs tIwDb_xxx
Par conséquent:
   lancez une nouvelle application IntraWeb par "File | New | Other | Intraweb | Intraweb Application Wizard"
   le wizard est affiché
   tapez le chemin et le nom de l'application, par exemple P_03_DBEDIT et cliquez "OK"
   la nouvelle application est créée
   modifiez aussi le nom de UNIT1 en U_03_DBEDIT
   compilez pour vérifier


Puis nous armons une Table
   sélectionnez UserSessionUnit et sélectionnez la forme (onglet "Design" en bas)
   initialisez une tTable
  • de l'onglet "BDE" de la Tool Palette, sélectionnez une tTable et posez la sur la forme tIwUserSession
  • dans l'Inspecteur
    • initialisez DataBaseName avec DBDEMOS
    • initialisez TableName avec ANIMALS.DBF
    • basculez Active sur True
   de l'onglet "DataAccess" de la Palette, sélectionnez une tDataSource et posez la sur la forme tIwUserSession. Initialisez DataSet vers Table1


Ajoutons un tIwDbEdit pour afficher un champ:
  • sélectionnez U_03_DBEDIT, sélectionnez le code
  • pour que les composants db_xxx puissent accéder à DataSource1, ajoutez à la clause USES l'importation de UserSessionUnit
  • sélectionnez la forme
  • sélectionnez de l'onglet "IwData" de la Palette, et dans cette page sélectionnez un tiwDbEdit:

    iw_data_iwdbedit

    et posez-le sur la Forme

    Dans l'Inspecteur

    • sélectionnez DatSource. Si vous avez bien importé UserSessionUnit, alors IWUserSession.DataSource1Data sera affiché. Sélectionnez cette source
    • sélectionnez DataField, et choisissez un champ, par exemple AREA
  • compilez et exécutez
  • voici le résultat:

    intraweb_bde_dbedit



Tant qu'a faire, nous pouvons ajouter un navigateur et afficher quelques images:
  • de l'onglet "IwData" de la Palette, sélectionnez un tIwDbNavigator, posez-le sur le Forme, et initialisez DataSource vers DataSource1
  • de cette page sélectionnez un tiwDbImage, posez-le sur la Forme et initialisez
    • DataSource vers DataSource1
    • DataField vers BMP
  • compilez et exécutez
  • voici le résultat:

    intraweb_bde_image



4.4 - tIwDbGrid et la base de données Interbase

4.4.1 - Utilisation d'une DataGrid

Pour varier les plaisirs, voici une application avec une grille et un moteur SQL Interbase. Tout d'abord, créons un nouveau projet:
   lancez une nouvelle application IntraWeb par "File | New | Other | Intraweb | Intraweb Application Wizard"
   le wizard est affiché
   tapez le chemin et le nom de l'application, par exemple P_04_DBGRID et cliquez "OK"
   la nouvelle application est créée
   modifiez aussi le nom de UNIT1 en U_04_DBGRID_INTERBASE
   compilez pour vérifier


Puis nous armons une Table, par exemple EMPLOYEE.COUNTRY
   dans le Gestionnaire de Projet, sélectionnez UserSessionUnit et sélectionnez la forme (onglet "Design" en bas)
   initialisez une tTable
  • de l'onglet "Interbase" de la Tools Palette, sélectionnez une tIbDataBase et posez-la sur la Forme.
    Cliquez deux fois sur IbDatabase1 pour ouvrir l'Editeur de Connection, et initialisez ses propriétés vers votre base. Dans notre cas:
    • DataBase vers
          C:\Program Files\Fichiers communs\Borland Shared\Data\EMPLOYEE.GDB
    • User Name à SYSDBA
    • Password à masterkey
    • Login à False
    Testez, et validez par "Ok"
  • de l'onglet "Interbase" de la Palette, sélectionnez une tIbTransaction et reliez-la à IbDatabase1 et réciproquement
  • de l'onglet "Interbase" de la Palette, sélectionnez une tIbQuery, et initialisez
    • DataBase vers IbDatabase1
    • SQL avec une sélection de Table, par exemple

       
      SELECT * FROM country

    • basculez Active à True
  • de l'onglet "Data Access" de la Palette, sélectionnez une tDataSource, posez-la sur la tForm et initialisez DataSet vers IbQuery1
   voici la vue de notre tDataModule:

datamodule_interbase



Ajoutons un tIwDbGrid pour afficher la Table:
  • sélectionnez U_04_DBGRID_INTERBASE, sélectionnez le "Code"
  • pour que les composants db_xxx puissent accéder à DataSource1, ajoutez à la clause USES l'importation de UserSessionUnit
  • sélectionnez la forme
  • sélectionnez de l'onglet "IwData" de la Palette, et dans cette page sélectionnez un tiwDbGrid et posez-la sur la tForm

    Dans l'Inspecteur sélectionnez DatSource. Si vous avez bien importé UserSessionUnit, alors IWUserSession.DataSource1Data sera affiché. Sélectionnez cette source

  • compilez et exécutez
  • voici le résultat:

    intraweb_datagrid



4.4.2 - Techniques d'affichage d'une tIwDbGrid

Nous pouvons utiliser plusieurs propriétés pour varier l'affichage dans une tIwDbGrid:
  • nous pouvons alterner les couleurs des lignes en utilisant RowAlternateColor
  • la couleur de la ligne au-dessus de laquelle passe la souris peut être modifiée par RollOver, RollOverColor
  • la couleur de la ligne sélectionnée
Voici quelques exemples:
   posez une autre tIwDbGrid sur la tForm, et liez DataSource vers DataSource1
   sélectionnez RowAlternateColor et donnez-lui la valeur clSkyBlue par exemple
   sélectionnez RowHeaderColor, et choisissez, par exemple clWebBisque
   sélectionnez RowCurrentColor, et affectez-lui clWebLime
   sélectionnez RollOver, et basculez la valeur sur True, et affectez à RollOverColor la valeur clWebYellow

   compilez et exécutez
   voici le résultat:

intraweb_datagrid_colors



4.4.3 - Pagination

Lorsque la Table est de grande taille, il est coûteux et inefficace de transférer vers le client toutes les lignes. Nous pouvons limiter le nombre de lignes envoyées en utilisant RowLimit, et en gérant par des boutons la demande de la page précédente ou suivante.

Par exemple:
   posez une autre tIwDbGrid sur la tForm, et
  • liez DataSource vers DataSource1
  • basculez FromStart à False
  • donnez à RowLimit une valeur telle que 4
   posez un tIwButton sur la Forme, créez son événement OnClick et tapez le code qui déplace la ligne courante d'un nombre de lignes égale au nombre de lignes de le tIwDbGrid:

procedure TIWForm1.next1Click(SenderTObject);
  begin
    UserSession.IbQuery1.MoveBy(IwDbGrid3.RowLimit);
  end// next1Click

Importez aussi dans la liste des USES SERVERCONTROLLER pour pouvoir accéder à USERSESSION.IbQuery1

   posez de même un bouton pour reculer

   compilez et exécutez
   voici le résultat :

intraweb_datagrid_paginate



Notez que

  • IbQuery1 est sur le DataModule USERSESSION. Comme indiqué plus haut, il n'y a PAS de variable globale nous permettant de désigner ce DataModule. En revanche, ServerController a créé une FUNCTION, appelée UserSession, qui nous permet d'accéder aux composant de TIWUserSession
  • vous pouvez aussi ajouter le code qui inhibe les boutons lorsque nous dépassons les limites (IbQuery.Eof etc)
  • le lecteur attentif aura remarqué que dans la dbGrid2, la couleur jaune souligne bien que c'est "japan" qui est devenue la ligne courante
  • comme nous ne pouvons utiliser un IwButton1.Name tel que "next_", nous avons utilisé "next1". Le risque est en effet, dans des WITH éventuels, d'utiliser le nom Next ayant une signification pour d'autres composants faisant partie du WITH. Si vous n'employez pas de WITH, nommez les boutons comme bon vous semble.


4.4.4 - tDbGrid modifiable

Nous allons examiner comment l'utilisateur peut changer les valeurs présentées dans un grille. Nous allons en profiter pour montrer comment utiliser une connection ADO.

Commençons par créer l'application:
   lancez une nouvelle application IntraWeb par "File | New | Other | Intraweb | Intraweb Application Wizard"
   le wizard est affiché
   tapez le chemin et le nom de l'application, par exemple P_05_DBGRID_ADO et cliquez "OK"
   la nouvelle application est créée
   modifiez aussi le nom de UNIT1 en U_05_DBGRID_ADO
   compilez pour vérifier


A présent armons une Table ADO

Ici, nous allons utiliser le fichier ACCESS fourni avec Delphi, appelé DBDEMOS.MDB. Ce fichier est situé, dans notre cas, en
    C:\Program Files\Fichiers communs\Borland Shared\Data\
et nous l'avons copié dans un répertoire plus confortable, appelé \_data, proche de notre application

Voici comment utiliser une Table ADO:
   sélectionnez le DataModule USERSESSIONUNIT, et sa tForm ("Design")
   de l'onglet "DbGo" de la Tools Palette, sélectionnez tAdoConnection et posez-le sur la tForm.
   Dans l'Inspecteur, sélectionnez Connection et cliquez sur l'ellipse
   l'Editeur de connection ADO de Microsoft est présenté.
   nous allons construire notre propre chaîne de connection, et nous sélectionnons "use connection string | Build"
   le constructeur de chaînes de connection Microsoft est présenté
   comme nous allons utiliser le moteur Sql ServerADO, nous sélectionnons "Fournisseur | Microsoft 4.0 OleDb Provider", puis cliquons "Suivant"
   la page "Connexion" est présentée
   nous cliquons l'ellipse à côté de "sélectionner la base de données" et allons sélectionner dbdemos.mdb.
   nous cliquons "tester la connexion", qui réussit, et fermons l'éditeur par "ok"
   dans la Palette, nous sélectionnons un tAdoDataset et le posons sur la tForm. Nous initialisons Connection vers AdoConnection1, puis sélectionnons CommandText et cliquons sur l'ellipse
   l'éditeur de requêtes est présenté
   tapez la même requête que ci-dessus (dbdemos.mdb contient la même table que employee.gdb):

 
SELECT * FROM country

   basculez AdoDataSet.Active à True
   pour pouvoir modifier la Table
  • posez un tAdoCommand sur la Forme
  • initialisez Connection vers AdoConnection1
  • basculez CheckParams à False


Voici comment utiliser la Table ADO avec Intraweb:
   sélectionnez U_02_EDIT_DBGRID_ADO
   pour que les composants db_xxx puissent accéder à DataSource1, ajoutez à la clause USES l'importation de UserSessionUnit
   de l'onglet "Data Access" de la Palette, sélectionnez une tDataSource, posez-la sur la tForm et initialisez DataSource1.DataSet vers AdoDataSet1
   de l'onglet "Iw Data", selectionnez une tIwDbGrid et posez-la sur la Forme. Sélectionnez DatataSource et initialisez-la vers DataSource1
   pour que ADO fonctionne, il faut aussi s'occuper de l'initialisation des objets COM:
  • sélectionnez SERVERCONTROLLER.PAS
  • dans l'Inspecteur, initialisez IwServerController.ComInitialization à ciNormal ou ciMultiThreaded
   finalement, pour permettre la modification d'une ligne,
  • ajoutez un composant tAdoCommand à la tForm, et initialisez Connection vers AdoConnection1. Et il faut basculer ParamCheck sur False
  • vous pouvez aussi utiliser un tAdoDataset, qu'il faut également initialiser vers AdoConnection1
   à titre de vérification, lancez l'application et vérifiez que vous voyez bien la table


Notez que:

  • il faut basculler ComInitialization. Si cette étape n'est pas effectuée, vous aurez une erreur "coinitialize" qui est, pour les utilisateurs d'ADO avec IntraWeb, l'erreur la plus fréquente. Cette propriété n'est pas initialisée par IntraWeb par défaut, car elle n'a lieu d'être que pour ADO
  • nous avons aussi montré ici que nous pouvons placer le tDataSource sur la TIWForm1 (comme nous pouvons choisir de le placer sur tIwUserSession)
  • si la connexion ADO ne réussit pas, vous pouvez faire l'exercice avec une Table BDE, InterBase, ou tout autre composant d'accès
Puis limitez le nombre de lignes et posez les tIwButton pour naviguer dans la grille, comme il a été présenté dans le paragraphe précédent.



Maintenant occupons nous de la modification d'une tIwDbGrid. Apparemment ce n'est pas prévu de façon automatique. Plusieurs solutions sont possibles

  • utiliser un tIwDbGrid uniquement pour l'affichage, et employer un tIwNavigator pour synchroniser l'affichage entre la tIwDbGrid et les tIwDbEdits. Ce n'est pas une solution totalement irréaliste: si vous regardez VOYAGES.SNCF.COM, il n'y a pas de DataGrid, mais des pages avec des liens clicables, ou des boîtes d'édition pour entrer vos coordonnées et payement
  • utiliser un tIwData, le peupler et synchroniser l'affichage et la mise à jour avec la Table
  • gérer en parallèle des structures qui mémorisent où nous sommes et lancent les UPDATE en fonction de cette position
C'est cette dernière solution que nous avons retenue. Elle s'inspire en fait de ASP.NET, ou, lorsque nous souhaitons modifier une grille. Démontrons d'abord schématiquement ce que nous souhaitons faire:
  • prenons une grille contenant 3 colonnes utiles:

    editable_iwdbgrid_start

  • nous lui adjoignons 3 colonnes pour gérer la modification.

  • en mode présentation, la grille comporte une colonne de boutons permettant de mettre une ligne en mode modification:

    editable_iwdbgrid_display

  • lorsque l'utilisateur a sélectionné une ligne en cliquant sur le bouton de cette ligne, une nouvelle grille lui est présenté comportant cette fois-ci
    • des Edit qui permettent de modifier le contenu d'un champ
    • deux boutons permettant de confirmer ou annuler
    Voici notre grille en mode modification

    editable_iwdbgrid_modify



An niveau IntraWeb:
  • nous commençons par ajouter 3 colonnes pour nos boutons. Cela se fait en créant les colonnes de tIwDbGrid manuellement, en utilisant la propriété tIwDbGrid.Columns
  • l'incrustation de tIwButtons et tIwEdits se fait en gérant l'affichage de chaque cellule. Pour cela la tIwDbGrid comporte un événement tIwDbGrid.OnRenderCell (similaire aux événement OwnerDraw d'une tDbGrid usuelle):

    procedure OnIWDBGridRenderCell(ACellTIWGridCell
        const ARowAColumnInteger);

    Cet événement nous fournit

    • la ligne et la colonne que nous devons dessiner
    • la cellule courante, qui a un paramètres tIwGridCell.Control, que nous utilisons pour incruster les boutons ou edits
  • nous créons un événement modify_button_clic qui nous permet de mettre la tIwDbGrid en mode édition (et récupérer les informations sur le numéro de la ligne, la clé etc).
  • nous créons les événements cancel_button_clic pour annuler tout changement, et réafficher la grille en mode "affichage"
  • et finalement un événement post_button_clic, qui
    • ira récupérer les informations sur la ligne courante et les nouvelles valeurs dans les tIwEdit pour construire une requête SQL UPDATE
    • exécutera cette requête
    • remettra la tIwDbGrid en mode affichage


Voici donc notre version
   sélectionnez IwDbGrid1, sélectionnez sa propriété Columns et cliquez sur l'ellipse ...
   un Editeur de colonnes est affiché
   cliquez sur l'icône d'ajout (ou "clic droit | add") et ceci 5 fois (pour la colonne de modification, 2 colonnes de données et 1 colonne pour Post, une pour Cancel)
   affichez le "Code" et déclarez dans la partie PUBLIC de tIwForm1 les boutons et les edits qui seront nécessaires, ainsi que les données de suivi de la ligne sélectionnée:

type TIWForm1=
  class(TIWAppForm)
      DataSource1TDataSource;
      IWDBGrid1TIWDBGrid;
      next1TIWButton;
      previous1TIWButton;
      // -- ...ooo...
    public
      m_c_do_modify_button_listarray of tIwButton;
      m_c_do_post_buttonm_c_do_cancel_buttontIwButton;

      m_c_edit_listarray of tIwEdit;

      m_do_modifyBoolean;
      m_selected_rowInteger;
      m_selected_keyString;

      procedure handle_do_modify_click(SendertObject);
      procedure handle_do_cancel_click(SenderTObject);
      procedure handle_do_post_click(SenderTObject);
    end// TIWAppForm

et:

  • m_c_do_modify_button_list: la liste verticale des boutons pour sélectionner une ligne
  • m_c_do_post_button, m_c_do_cancel_button: les boutons qui exécutent Post ou Cancel
  • m_c_edit_list: la liste horizontale des tIwEdit permettant de modifier les champs de la ligne sélectionnée
  • m_do_modify: le booléen qui gère l'état affichage / modification de la grille
  • m_selected_row, m_selected_key: les paramètres permettant de construire la requête
   créez l'événement tIwForm.OnCreate, et créez les do_edit boutons verticaux, les edits horizontaux et les bouton Post et Cancel:

const k_table_column_count= 2;

procedure TIWForm1.IWAppFormCreate(SenderTObject);
  var l_row_indexInteger;
      l_c_do_modify_buttontIwButton;

      l_column_indexInteger;
      l_c_iwedittIwEdit;
  begin
    SetLength(m_c_do_modify_button_listIwDbGrid1.RowLimit);

    for l_row_index:= 0 to IwDbGrid1.RowLimit- 1 do
    begin
      l_c_do_modify_button:= tIwButton.Create(Self);
      with l_c_do_modify_button do
      begin
        Caption:= 'Modify_'IntToStr(l_row_index);
        // -- offset by 1 because of the row header
        Tag:= l_row_index+ 1;
        OnClick:= handle_do_modify_click;
      end// with l_iwbutton

      m_c_do_modify_button_list[l_row_index]:= l_c_do_modify_button;
    end// for l_row_index

    SetLength(m_c_edit_listk_table_column_count);
    for l_column_index:= 0 to k_table_column_count- 1 do
    begin
      l_c_iwedit:= tIwEdit.Create(Self);
      with l_c_iwedit do
        Text:= 'Edit_'IntToStr(l_column_index);
      m_c_edit_list[l_column_index]:= l_c_iwedit;
    end// for l_column_index

    m_c_do_post_button:= tIwButton.Create(Self);
    with m_c_do_post_button do
    begin
      Color:= clWebLime;
      Caption:= 'Post';
      OnClick:= handle_do_post_click;
      Visible:= False;
    end// with m_c_do_post_button

    m_c_do_cancel_button:= tIwButton.Create(Self);
    with m_c_do_cancel_button do
    begin
      Color:= clWebRed;
      Caption:= 'Cancel';
      OnClick:= handle_do_cancel_click;
      Visible:= False;
    end// with m_c_do_cancel_button
  end// IWAppFormCreate

Notez que chaque bouton de modification contient dans tIwButton.Tag le numéro de la ligne. Ceci sera utilisé pour retrouver la ligne courante à modifier lorsque le bouton sera cliqué.

   sélectionnez la tIwDbGrid, créez son événement OnRenderCell, et affichez, en fonction de l'état de la dbGrid, soit les boutons pour modifier, soit les Edit et les boutons pour Poster. Et ces dernier uniquement sur la ligne courante. En gros, il y a deux états: affichage et modification, et en fonction du Boolean m_do_modify, nous affichons soit les bouton de modification, soit les Edits et les boutons d'annulation/post

procedure TIWForm1.IWDBGrid1RenderCell(ACellTIWGridCellconst ARow,
    AColumnInteger);

  procedure draw_in_display_mode;
    var l_field_valueString;
    begin
      if ARow= 0
        then // column header
        else
          case AColumn of
            0 : begin
                  // -- the button column
                  ACell.Control:= m_c_do_modify_button_list[ARow- 1];
                  ACell.Control.Enabled:= True;
                end;
            1 : begin
                  l_field_value:= UserSession.AdoDataset1.Fields[0].AsString;
                  ACell.Text:= l_field_value;
                end;
            2 : begin
                  l_field_value:=
                      UserSession.AdoDataset1.FieldByName('Population').AsString;
                  ACell.Text:= l_field_value;
                end;
          end// case AColumn
    end// draw_in_display_mode

  procedure draw_in_edit_mode;

    procedure display_selected_row;
      var l_field_valueString;
      begin
        case AColumn of
          1 : begin
                l_field_value:= UserSession.AdoDataset1.Fields[0].AsString;
                ACell.Control:= m_c_edit_list[0];
                m_c_edit_list[0].Text:= l_field_value;
                m_selected_key:= l_field_value;
              end;
          2 : begin
                l_field_value:= UserSession.AdoDataset1.FieldByName('Population').AsString;
                ACell.Control:= m_c_edit_list[1];
                m_c_edit_list[1].Text:= l_field_value;
              end;
          3 : begin
                ACell.Control:= m_c_do_post_button;
              end;
          4 : begin
                ACell.Control:= m_c_do_cancel_button;
              end;
        end// case AColumn
      end// display_selected_row

    procedure display_other_row;
      var l_field_valueString;
      begin
        case AColumn of
          1 : begin
                l_field_value:= UserSession.AdoDataset1.Fields[0].AsString;
                ACell.Text:= l_field_value;
              end;
          2 : begin
                l_field_value:=
                    UserSession.AdoDataset1.FieldByName('Population').AsString;
                ACell.Text:= l_field_value;
              end;
        end// case AColumn
      end// display_other_row

    begin // draw_in_edit_mode
      if ARow= 0
        then // column header
        else
          if aColumn= 0
            then begin
                // -- the modify column
                ACell.Control:= m_c_do_modify_button_list[ARow- 1];
                ACell.Control.Enabled:= False;
              end
            else
              if ARowm_selected_row
                then display_selected_row
                else display_other_row;
    end// draw_in_edit_mode

  begin // IWDBGrid1RenderCell
    if m_do_modify
      then draw_in_edit_mode
      else draw_in_display_mode;
  end// IWDBGrid1RenderCell

   créez l'événement qui traitera la mise en mode edition:

procedure TIWForm1.handle_do_modify_click(SendertObject);
  begin
    with (Sender as tIwButtondo
    begin
      m_do_modify:= True;
      m_selected_row:= Tag;

      m_c_do_post_button.Visible:= True;
      m_c_do_cancel_button.Visible:= True;
    end// with Sender as tIwButton
  end// handle_do_modify_click

et les événements qui traitent Cancel:

procedure TIWForm1.handle_do_cancel_click(SenderTObject);
  begin
    // -- simply revert to display mode
    m_do_modify:= False;

    // -- reset the browse mode
    m_c_do_post_button.Visible:= False;
    m_c_do_cancel_button.Visible:= False;
  end// handle_do_cancel_click

et finalement la mise à jour (à modifier si vous n'utilisez pas ADO):

procedure TIWForm1.handle_do_post_click(SenderTObject);
  var l_populationString;
  begin
    clear_display;
    display('post 'm_selected_key);

    // -- use the data access controls to update the Table
    l_population:= m_c_edit_list[1].Text;

    with UserSession.AdoCommand1 do
    begin
      CommandText:=
          'UPDATE country '
        + '  SET population= 'l_population
        + '  WHERE Name= '''m_selected_key'''';
      // display('cmd '+ CommandText);
      Execute;
    end// with UserSession.AdoCommand1

(*
    with UserSession.AdoDataset2 do
    begin
      Open;

      if Locate('Name', m_selected_key, [])
        then begin
            Edit;
            FieldByName('Population').AsString:= l_population;
            Post;
          end;
      Close;
    end; // with UserSession.AdoDataset2
*)

    // -- refresh AdoDataset1
    UserSession.AdoDataset1.Close;
    UserSession.AdoDataset1.Open;

    // -- reset the browse mode
    m_do_modify:= False;
    m_c_do_post_button.Visible:= False;
    m_c_do_cancel_button.Visible:= False;
  end// handle_do_post_click

Nous avons laissé en commentaire la modification via AdoDataset2

   compilez et exécutez
   voici la grille en mode affichage:

editable_iwdbgrid

   cliquez sur le second tButton:

   voici la grille en mode modification:

iwdbgrid_edit



Notez
  • tout d'abord nous nous sommes entêtés à vouloir utiliser ADO. Lorsque nous avons essayé de mettre à jour, nous avons eu une exception "OleException, missing required parameter". Après quelques heures d'essai, nous avons décidé d'utiliser un tAdoDataSet, et Locate n'a pas fonctionné, car la colonne COUNTRY n'existait pas. Nous avions confondu EMPLOYEE_GDB.COUNTRY et DBDEMOS_MDB.COUNTRY, et le nom correct pour la colonne contenant le nom du pays est ici NAME. "OleException, missing parameter" était naturellement le message le plus approprié pour nous mettre sur la voie. Pas aussi inutile que "Syntax Error", mais pas loin, voire pire ...
  • revenons à notre sujet. Nous aurions pu, comme ASP.NET utiliser la même colonne pour les boutons de modification et ceux de confirmation ou annulation. Nous avons tout laissé pour mieux montrer ce qui se passait
  • nous avons créé des listes de boutons. Il faudrait naturellement les libérer, et ceci dans tIwForm.OnDestroy
  • nous avons utilisé une grille de taille fixe pour pouvoir plus facilement allouer nos tables de boutons. Il serait possible de parcourir la Table pour allouer un nombre variable en fonction de la taille de la table
  • en plus des dbGrid, il existe aussi une grille tIwGrid (non liée à une base de données) que nous pouvons remplir, modifier etc
  • il arrive que lorsque nous créons des tIwButton ou autre contrôle par code, nous ne connaissions pas l'UNITé Intraweb à importer. Nous pouvons naturellement recherche cette unité en utilisant l'aide. Une solution bien connue est de déposer un exemplaire de ce type de contrôle via la Palette, de compiler (ce qui force Delphi à ajouter le bon USES, puis à retirer ce composant
  • SELF est impératif dans tIwButton.Create(SELF) (sinon le clic ne sera pas pris en compte)
  • peut-être les nouvelles versions d'Intraweb faciliteront la modification d'une grille, mais les messages trouvés sur les forums n'en parlent pas
  • la stratégie utilisée pour modifier une grille est similaire à celle que nous avons utilisée pour présenter la navigation dans une grille en utilisant CGI, et est la même que celle utilisée, nous l'avons déjà indiqué, par ASP.NET
  • nous pourrions utiliser la même technique pour nous positionner sur une ligne en utilisant la grille
  • il faudrait aussi gérer l'inhibition de previous et next pendant la modification
  • la dernière image ci-dessus présente aussi un tIwMemo. Naturellement, nous n'avons pu nous empêcher d'afficher différents message de mise au point, comme sous Windows. Ici le memo affiche la requête qui va être exécutée. Les méthodes pour afficher et effacer le memo sont dans les sources du .ZIP
  • en ce qui concerne la tIwDbGrid:
    • UseFrame permet de supprimer le titre de la tIwDbGrid. UseSize affiche un cadre autour de la grille
    • tIwDbGrid.Colums[0] n'est pas accepté. Il faut utiliser tIwDbGrid.Colums[0].Items[0]
    • apparemment, le titre des colonnes est compté comme une ligne de la tIwDbGrid
    • les tIwDbGridColumn ont aussi un événement OnClick que nous aurions peut être pu utiliser au lieu de mettre en place des boutons Modify
    • CellPadding est le gras dans une cellule, CellSpacing la taille de la bordure (comme pour les <TABLE>s .HTML, naturellement
    • BgColor et la couleur de la zone dessinée
    • Options.dgShowTitles permet de supprimer les titres des colonnes


4.5 - Gestion des Sessions

Par définition, le protocole .HTTP est sans état: lorsqu'un Client demande une page, le Serveur la lui envoie, et oublie tout de cette requête. Ceci évite d'avoir à gérer au niveau du Serveur l'état de chaque Client.

Certaines applications nécessitent toutefois une gestion de la session. Si nous souhaitons afficher les lignes d'une Table par groupe de 10 lignes, il faut bien mémoriser quelque part que nous avons affiché les lignes 09, et lorsque nous cliquons "Next", nous souhaitons les lignes 1011. Il faut donc que notre application (et non pas le Serveur) se charge de gérer l'état du dialogue entre le Serveur et le Client.



Les sessions sont gérées automatiquement par Intraweb. En fait, c'est la tIwApplication qui gère la session:
   nous lançons le Serveur Intraweb
   un nouvel utilisateur se connecte
   un objet tIwApplication est automatiquement créé. Cet objet
  • contient la pile des tIwForm créées (les pages)
  • il contient un attribut tIwApplication.Data qui, par défaut, pointe vers un tIwUserSession qui est un descendant de tDataModule
et chaque tIwForm contient une référence tIwForm.WebApplication, vers l'application.



5 - Commentaires sur IntraWeb



5.1 - Remarques

  • beaucoup d'articles d'initiation Intraweb exagèrent sur le miracle de la conception visuelle de pages Web avec Intraweb. Certes c'est beaucoup plus agréable que la technique de construction par NotePad, mais ce n'est toujours, appliqué aux pages .HTML, que ce que fait Delphi pour Windows depuis 1995 !
  • la documentation est assez succinte, et les articles IntraWeb sont un peu emphatiques et ampoulés, en un mot, "marketing". Il y a aussi différents documents, mais certains ne semblent pas indiquer la version IntraWeb qu'ils sont censés documenter
  • comme Indy, Intraweb a une "granularité" très fine. Un nombre impressionnant de composants, et de pages sur la Palette.
  • ce morcellement entraîne aussi de fréquents changements d'architecture. Comme mentionné plus haut, nos diagrammes de classe ont utilisé la version Intraweb fournie avec Delphi 6. Et les composants de la version 8 (fournis avec Delphi 2006) n'ont pas tout à fait la même organisation.
    Mentionnons toutefois que
    • ces réorganisations correspondent à de nouvelles fonctionalités, et à ce titre sont bienvenues
    • les modifications touchent essentiellement l'organisation des classes internes, et concernent un peu moins les application que nous développons.
    • l'aide comporte aussi des informations sur la migration entre les versions IntraWeb

    • parmi quelques problèmes de migration rencontrés en utilisant certains exemples écrits avec d'autres versions, mentionnons
      • des propriétés qui n'existent plus ou pas encore (Font.BackColor, Netscape, IwImage.JpegOptions, IwLabel.Color)
      • vous pouvez aussi avoir, en fonction de la version Delphi et Intraweb, des messages du style "Dynamic Grids are not available in this edition".
  • certains exemples trouvés sur le Web placent le Serveur Intraweb dans le TrayIcon (la partie en bas à droite de la barre de tâche Windows contenant des icônes, telles que l'heure etc). De ce fait, si le Serveur est encore chargé, vous ne pourrez pas recompiler l'application. Nous ne pouvons pas non plus la compiler si le Serveur est visible sur la barre de tâche, mais au mois là nous le voyons de façon évidente. Il arrive d'ailleurs que le TrayIcon XP contienne plusieurs icônes de Serveurs Intraweb, ou même que la barre de tâches contienne plusieurs Serveurs. Fermez-les les uns après les autres, et passez simplement la souris sur les icônes du TrayIcon
  • l'exécution du Serveur Intraweb Standalone supprime toute page ouverte dans Internet Explorer. Cela peut devenir pénible, surtout si vous étiez à la recherche d'informations pour résoudre un problème Intraweb, ou en train de vérifier le tutorial Interbase en cours de frappe ...


5.2 - Autre possibilités

Intraweb permet de créer des applications Web, et le Web est censé remplacer un jour toutes les applications locales. Il faut donc qu'Intraweb soit aussi riche que tous les composants Windows locaux. Vaste programme.

Notre tutoriel n'a donc pu tout présenter, et parmi les domaines non présentés:

  • le développement en mode "page". Ce type de pages nécessite l'utilisation d'un Serveur de type IIS, et fonctionne en conjonction avec WebBroker, et WebSnap
  • les techniques côté client
    • la validation utilisant Javascript
    • l'ajout de Javascript aux pages générées
    • les composants de données IwClientSideDataset, l'utilisation de fichiers .XML (XmlBroker)
  • l'authentification des utilisateurs
  • l'utilisation de tFrame, en particulier pour armer des menus
  • les composants divers (TreeView, menus, composants Flash, vidéos etc)
  • la génération de code à partir de templates
  • la gestion des exceptions
  • la génération de pages pour la téléphonie (WAP) ou les PDA
  • l'utilisation de communications sécurisées (SSL)
  • les versions .NET d'Intraweb, les outils externes utilisables en conjonction avec Intraweb (Rave Reports ou DevExpress)



6 - Télécharger le code source Delphi

Vous pouvez télécharger:

Ce .ZIP qui comprend:
  • le .DPR, la forme principale, les formes annexes eventuelles
  • les fichiers de paramètres (le schéma et le batch de création)
  • dans chaque .ZIP, toutes les librairies nécessaires à chaque projet (chaque .ZIP est autonome)
Ces .ZIP, pour les projets en Delphi 6, contiennent des chemins RELATIFS. Par conséquent:
  • créez un répertoire n'importe où sur votre machine
  • placez le .ZIP dans ce répertoire
  • dézippez et les sous-répertoires nécessaires seront créés
  • compilez et exécutez
Ces .ZIP ne modifient pas votre PC (pas de changement de la Base de Registre, de DLL ou autre). Pour supprimer le projet, effacez le répertoire.

La notation utilisée est la notation alsacienne qui consiste à préfixer les identificateurs par la zone de compilation: K_onstant, T_ype, G_lobal, L_ocal, P_arametre, F_unction, C_lasse. Elle est présentée plus en détail dans l'article La Notation Alsacienne



Comme d'habitude:

  • nous vous remercions de nous signaler toute erreur, inexactitude ou problème de téléchargement en envoyant un e-mail à jcolibri@jcolibri.com. Les corrections qui en résulteront pourront aider les prochains lecteurs
  • tous vos commentaires, remarques, questions, critiques, suggestion d'article, ou mentions d'autres sources sur le même sujet seront de même les bienvenus à jcolibri@jcolibri.com.
  • plus simplement, vous pouvez taper (anonymement ou en fournissant votre e-mail pour une réponse) vos commentaires ci-dessus et nous les envoyer en cliquant "envoyer" :
    Nom :
    E-mail :
    Commentaires * :
     

  • et si vous avez apprécié cet article, faites connaître notre site, ajoutez un lien dans vos listes de liens ou citez-nous dans vos blogs ou réponses sur les messageries. C'est très simple: plus nous aurons de visiteurs et de références Google, plus nous écrirons d'articles.



7 - Références

Intraweb est fourni en version BE avec les nouvelles versions de Delphi. Vous pouvez récupérer les mises à jour, ou les versions plus complètes auprès de AtoZed



Nous organisons aussi régulièrement des Formations IntraWeb qui entrent en détail dans la construction, la mise au point et le dépoloiement d'applications IntraWeb.


8 - L'auteur

John COLIBRI est passionné par le développement Delphi et les applications de Bases de Données. Il a écrit de nombreux livres et articles, et partage son temps entre le développement de projets (nouveaux projets, maintenance, audit, migration BDE, migration Xe_n, refactoring) pour ses clients, le conseil (composants, architecture, test) et la formation. Son site contient des articles avec code source, ainsi que le programme et le calendrier des stages de formation Delphi, base de données, programmation objet, Services Web, Tcp/Ip et UML qu'il anime personellement tous les mois, à Paris, en province ou sur site client.
Created: jan-04. Last updated: mar-2020 - 250 articles, 620 .ZIP sources, 3303 figures
Contact : John COLIBRI - Tel: 01.42.83.69.36 / 06.87.88.23.91 - email:jcolibri@jcolibri.com
Copyright © J.Colibri   http://www.jcolibri.com - 2001 - 2020
Retour:  Home  Articles  Formations  Développement Delphi  Livres  Pascalissime  Liens  Download
l'Institut Pascal

John COLIBRI

+ Home
  + articles_avec_sources
    + bases_de_donnees
    + web_internet_sockets
      – http_client
      – moteur_de_recherche
      – javascript_debugger
      + asp_net
      – client_serveur_tcp
      – site_editor
      – pascal_to_html
      – cgi_form
      + les_logs_http_bruts
      + les_blogs
      – intraweb_tutorial
      + services_web
      – serveur_web_iis
      – client_serveur_pop3
      – lecteur_mails_free
    + services_web_
    + prog_objet_composants
    + office_com_automation
    + colibri_utilities
    + uml_design_patterns
    + graphique
    + delphi
    + outils
    + firemonkey
    + vcl_rtl
    + colibri_helpers
    + colibri_skelettons
    + admin
  + formations
  + developpement_delphi
  + présentations
  + pascalissime
  + livres
  + entre_nous
  – télécharger

contacts
plan_du_site
– chercher :

RSS feed  
Blog

Formation Ado Gestion de bases de données avec Ado : connexion, accès aux tables, édition d'états - 3 jours
Formation Bases de Données Multi Tiers Delphi Gestion de bases de données Mulit Tiers : architecture, le serveur d'application : dbExorss et DataSnap, les clients légers, édition d'états - 3 jours