Developpez.com - 4D
X

Choisissez d'abord la catégorieensuite la rubrique :


Taille optimale d'objets

Date de publication : Février 2003

Par Kent D. WILBUR (Manager of Information System, 4D Inc.)
 

Cette Note Technique explore TAILLE OBJET OPTIMALE, une commande apparue avec 4D 2003. Celle-ci vous retourne les dimensions « optimales » requises pour qu’un objet puisse afficher son contenu que ce soit à l’écran ou sur un document papier. Vous utiliserez ces informations pour mieux ajuster vos formulaires ou optimiser le remplissage de vos imprimés.

I. Introduction
II. Syntaxe de la fonction :
III. Utilisation de TAILLE OBJET OPTIMALE dans un formulaire entrée
IV. Utilisation de TAILLE OBJET OPTIMALE dans une impression « côte à côte » d’un état
V. Utilisation de TAILLE OBJET OPTIMALE pour créer un état style « catalogue »
VI. Conclusion
VI. Base exemple


I. Introduction

Cette Note Technique explore TAILLE OBJET OPTIMALE, une commande apparue avec 4D 2003. Celle-ci vous retourne les dimensions « optimales » requises pour qu'un objet puisse afficher son contenu que ce soit à l'écran ou sur un document papier. Vous utiliserez ces informations pour mieux ajuster vos formulaires ou optimiser le remplissage de vos imprimés.


II. Syntaxe de la fonction :

TAILLE OBJET OPTIMALE ({*;}objet; largeurOpti;hauteurOpti{;largeurMax})

La fonction retourne une hauteur et une largeur « optimale » de n'importe quel objet contenant un texte, et ceci quels que soient la plateforme utilisée, la police, la taille ou le style de la police. La fonction gère les césures et les retours de chariot.

TAILLE OBJET OPTIMALE fonctionne pour :

      - Les alphas
      - Les numériques
      - Les booléens
      - Les dates
      - Les heures
      - Les textes statiques
      - Les boutons.

Dans ce document nous n'approfondirons que le cas des objets de type texte mais ce que vous aurez appris pourra aisément être appliqué aux autres types d'objets.

Souvenez-vous que TAILLE OBJET OPTIMALE ne fait que retourner les meilleures dimensions pour l'objet lui-même sans prendre en compte ses éventuelles « décorations ». Supposons que votre objet soit en relief inversé, ait un ascenseur ou, si c'est un bouton, un cadre, vous devrez calculer par vous-même les dimensions de ces « apparences ». TAILLE OBJET OPTIMALE ne fait que retourner des dimensions brutes auxquelles vous ajouterez celles des décorations.

Lors de la manipulation d'objets de type texte, le paramètre optionnel « largeur fixe » est un paramètre quasiment obligatoire. En ne le précisant pas, vous risquez d'obtenir des objets si larges qu'ils pourraient ne pas tenir dans l'écran ou sur votre imprimé.

TAILLE OBJET OPTIMALE fonctionne également avec d'autres objets de formulaire : onglets, rectangles, lignes, etc. Dans ces cas là TAILLE OBJET OPTIMALE retourne tout simplement des dimensions comme vous auriez pu les déduire avec la fonction LIRE RECT OBJET.


III. Utilisation de TAILLE OBJET OPTIMALE dans un formulaire entrée

La base exemple contient le formulaire ci-dessous. (Note : pour bien voir ce formulaire la résolution de votre écran devra être au moins de 1024x768).

Pictures 0322x0262

Le formulaire contient trois objets à la taille variable : Acteurs, Image et Synopsis. Bien que vous puissiez utiliser TAILLE OBJET OPTIMALE sur pratiquement n'importe quel objet, l'exemple fourni se limitera au champ Synopsis.

En principe les acteurs devraient tenir dans la zone allouée et s'il devait y en avoir plus, l'utilisateur pourra alors jouer des ascenseurs pour voir l'excédent de texte.

Quant à l'image, elle peut varier énormément en taille, aussi, notre seule préoccupation est de la représenter de manière proportionnelle à l'original. La méthode formulaire utilise PROPRIETE IMAGE pour redimensionner le champ tout en gardant à l'esprit certaines limites physiques.

Venons-en à notre champ Synopsis : la méthode formulaire se termine en redimensionnant la fenêtre de manière à montrer le maximum de texte du champ Synopsis mais dans la limite des dimensions de l'écran. De plus, le code replacera correctement toute portion de la fenêtre qui aurait pu déborder de l'écran.

La méthode formulaire de la base fournie est, vue dans son intégralité, plus complexe. Aussi vous ne l'étudierez que si vous souhaitez en connaître le moindre détail des fonctionnalités. Voici simplement la portion de code qui redimensionne le champ synopsis et son libellé.


      ` manipulation sur le champ synopsis
   LIRE RECT OBJET([Produits]Synopsis;$LSynopsisLeft;$LSynopsisTop;$LSynopsisRight;$LSynopsisBottom)

      ` calcul de la taille avec l'ascenceur
   $LSynopsisFixedWidth:=$LPictureLeft+$LPictureWidth-$LSynopsisLeft-16
   TAILLE OBJET OPTIMALE([Produits]Synopsis;$LWidth;$LSynopsisIdealHeight;$LSynopsisFixedWidth)

      `Autorise de l'espace supplémentaire pour la saisie
   $LSynopsisIdealHeight:=$LSynopsisIdealHeight+16
   $LDescriptionTop:=$LSynopsisIdealHeight-($LSynopsisBottom-$LSynopsisTop)
   $LMove:=$LPictureHeight+$LPictureTop+10-$LSynopsisTop
   DEPLACER OBJET(*;"SynopsisLabel";0;$LMove)

   Si (($LSynopsisIdealHeight+$LSynopsisTop+120)>$LMaxScreenHeight)
      $LSynopsisIdealHeight:=$LMaxScreenHeight-$LSynopsisTop-120
   Fin de si

   Si ($LSynopsisIdealHeight<32) ` Set minimum height / fixer la hauteur mini
      $LSynopsisIdealHeight:=32
   Fin de si

      ` déplacer le champ
   DEPLACER OBJET(*;"SynopsisField";0;$LMove;$LSynopsisFixedWidth-($LSynopsisRight-$LSynopsisLeft);
         $LSynopsisIdealHeight-($LSynopsisBottom-$LSynopsisTop)+7)


Ce code récupère la hauteur optimale du champ Synopsis et la compare à celle de la fenêtre : est-elle trop grande ou nécessite-t-elle une hauteur minimum ? Ensuite l'objet est déplacé. Quant au libellé, il n'est déplacé que si la taille de l'image est trop grande en hauteur.


IV. Utilisation de TAILLE OBJET OPTIMALE dans une impression « côte à côte » d’un état

Une question qui revient régulièrement :
« comment puis-je imprimer un état avec des colonnes contigües alors que le texte varie d'une colonne à l'autre et d'un état à l'autre ? ».

Utilisons le formulaire ci-dessous :

Pictures 0554x0129

Il est très facile de boucler sur les trois champs Titre, Acteurs et Synopsis pour découvrir à l'aide de TAILLE OBJET OPTIMALE quel sera le champ le plus grand puis d'ajuster les taquets au plus grand des trois objets. Vous obtenez le résultat qui suit :

Pictures 0366x0374


La méthode formulaire est très simple :


   Si (Faux)
      ` Form Method: PrintSideBySide
        ` 4D Technical Note
        ` Making the most of Best Object Size
        ` Created by: Kent Wilbur
        ` Date: 1/21/03
    ◊f_Version2003:= Vrai
    ◊fK_Wilbur:= Vrai
   Fin de si

   C_ENTIER LONG($i)
   C_ENTIER LONG($LBottom)
   C_ENTIER LONG($LFixedWidth)
   C_ENTIER LONG($LFormEvent)
   C_ENTIER LONG($LFormHeight)
   C_ENTIER LONG($LHeight)
   C_ENTIER LONG($LLeft)
   C_ENTIER LONG($LMarkerPosition)
   C_ENTIER LONG($LMoveMarker)
   C_ENTIER LONG($LOriginalHeight)
   C_ENTIER LONG($LPrintedHeight)
   C_ENTIER LONG($LResize)
   C_ENTIER LONG($LRight)
   C_ENTIER LONG($LTop)
   C_ENTIER LONG($LWidth)

   $LFormEvent:=Evenement formulaire

   Au cas ou

      : ($LFormEvent=Sur impression corps )

      LIRE ZONE IMPRESSION($LFormHeight)
      $LPrintedHeight:=Lire hauteur imprimee+5 ` pour les pieds
      $LMoveMarker:=0
      $LMarkerPosition:=Lire taquet impression(Corps formulaire )

      TABLEAU POINTEUR($apFields;3)
      $apFields{1}:=->[Produits]Titre
      $apFields{2}:=->[Produits]Acteurs
      $apFields{3}:=->[Produits]Synopsis

      Boucle ($i;1;3)
         LIRE RECT OBJET($apFields{$i}->;$LLeft;$LTop;$LRight;$LBottom)
         $LFixedWidth:=$LRight-$LLeft
         $LOriginalHeight:=$LBottom-$LTop
         TAILLE OBJET OPTIMALE($apFields{$i}->;$LWidth;$LHeight;$LFixedWidth)
         $LResize:=$LHeight-$LOriginalHeight
         Si ($LResize>0)
            DEPLACER OBJET($apFields{$i}->;$LLeft;$LTop;$LRight;$LHeight+$LTop;*)
               Si ($LResize>$LMoveMarker)
                  $LMoveMarker:=$LResize
               Fin de si
         Fin de si
      Fin de boucle

      Si ($LFormHeight>($LPrintedHeight+$LMoveMarker+$LOriginalHeight))
         Si ($LMoveMarker>0)
            FIXER TAQUET IMPRESSION(Corps formulaire ;$LMarkerPosition+$LMoveMarker;*)
         Fin de si
      Sinon
         NE PAS VALIDER
      Fin de si

   Fin de cas


Ce code utilise plusieurs nouvelles fonctionnalités propres à la 2003. Tout d'abord vous pouvez récupérer et fixer les taquets lors de l'événement formulaire Sur impression corps. C'est nouveau. Ensuite, mais tout aussi important, vous pouvez à présent ANNULER une impression au cours d'un Imprimer ligne pour que ce formulaire ne soit pas enregistré. De plus, la méthode qui appelle Imprimer ligne n'est pas stoppée. En revenant dans cette méthode vous n'aurez qu'à tester l'annulation et agir en conséquence.

Voici donc la méthode qui imprime l'état en appelant Imprimer ligne.

info Note : une meilleure solution consiste à créer un tableau de pointeurs (tableau process) en dehors de la méthode formulaire : ainsi le tableau n'aura pas a être recrée à chaque enregistrement. Dans notre exemple, nous créons un tableau local afin de mieux vous faire saisir le déroulement des opérations.

   Si (Faux)
           ` Method: M_PrintSideBySide
           ` 4D Technical Note
           ` Making the most of Best Object Size
           ` Created by: Kent Wilbur
           ` Date: 1/21/03

      ◊f_Version2003:=Vrai
      ◊fK_Wilbur:=Vrai
   Fin de si

   C_ENTIER LONG($i)
   C_ENTIER LONG($LHeight)
   PARAMETRES IMPRESSION

   Si (OK=1)

         `Sauvegarder la sélection original et la trier
      COPIER SELECTION([Produits];"OriginalSelection")
      TRIER([Produits];[Produits]Titre)
      $LHeight:=Imprimer ligne([Produits];"PrintSideBySide";Entête formulaire )

      Boucle ($i;1;Enregistrements trouves([Produits]))
         $LHeight:=Imprimer ligne([Produits];"PrintSideBySide";Corps formulaire )
         Si (OK=0) `ANNULER a été demandé dans la méthode formulaire
            SAUT DE PAGE
            $LHeight:=Imprimer ligne([Produits];"PrintSideBySide";Entête formulaire )
            $LHeight:=Imprimer ligne([Produits];"PrintSideBySide";Corps formulaire )
         Fin de si
         ENREGISTREMENT SUIVANT([Produits])
      Fin de boucle

      SAUT DE PAGE ` on n'oublie pas la dernière page !

         ` revenir à la sélection d'origine
      UTILISER SELECTION("OriginalSelection")
      EFFACER SELECTION("OriginalSelection")

   Fin de si


Le code de cette méthode projet est simple : nous bouclons sur la sélection d'enregistrements à imprimer. Si au cours de l'opération une annulation est détectée, nous éjectons la page, imprimons un entête et réimprimons le même formulaire.

Comme vous le constatez, avec quelques lignes de code et un formulaire, imprimer un rapport « side by side » est relativement indolore.


V. Utilisation de TAILLE OBJET OPTIMALE pour créer un état style « catalogue »

Par le passé, imprimer un « catalogue » avec 4D était virtuellement impossible. Par « catalogue » nous entendons un état qui soit comparable à un produit réaliser en PAO. Ce type de rapport a classiquement un ou plusieurs champs qui fluctuent en taille alors qu'ils ont besoin de suivre une maquette prédéfinie. Par nature, ce format n'est pas linéaire.

Pour l'exemple nous avons préparé les formulaires suivants :

Pictures 0423x0220

Dans la série « pourquoi faire compliqué quand on peut faire simple », ce formulaire ne se préoccupera que des deux champs qui changent le plus fréquemment : Acteurs et Synopsis. Cependant rien n'empêcherait d'utiliser TAILLE OBJET OPTIMALE pour les autres champs.

De par la proximité du libellé Genre avec le bas de l'image, le champ Acteurs sera de trois lignes sans à avoir à être modifié. Il ne le serait que si l'espace requis dépasse ces trois lignes.

Quant au champ synopsis, il changera à chaque enregistrement. La distance entre de ce champ et le taquet du corps est là pour créer une séparation entre chaque produit. Nous aurions pu ajouter une ligne ou tout autre objet mais gardons le code au plus simple.

Voici le résultat que nous escomptons :

Pictures 0377x0359

Quelques évidences :
Mission Impossible a cinq lignes d'acteurs alors que Mission pour Mars n'en comporte que deux. Mais il y a un peu plus d'espace entre Mission pour Mars et le haut du synopsis. Au premier coup d'œil il n'est pas facile de déterminer le nombre de lignes qui auraient pu être ajoutées.

La seule façon d'être certain à 100 % que tous les objets ont été redimensionnés sera de jeter un œil à l'alignement des libellés Genre et Synopsis qui est différent d'un enregistrement à l'autre : dans le cas de Mission Impossible le libellé Synopsis est deux lignes plus bas.

Afin d'obtenir ces déplacements, nous avons utilisé la même technique que précédemment lors de l'impression « côte à côte ». Voici la méthode formulaire de notre listing de films :


   Si (Faux)
         ` Méthode formulaire : PrintFormCatalog
         ` 4D Technical Note
         ` Taille optimale d'objet
         ` Créée par : : Kent Wilbur
         ` Date : 11/20/02

      ◊f_Version2003:=Vrai
      ◊fK_Wilbur:=Vrai
   Fin de si

   C_ENTIER LONG($LBottom)
   C_ENTIER LONG($LFixedWidth)
   C_ENTIER LONG($LFormEvent)
   C_ENTIER LONG($LFormHeight)
   C_ENTIER LONG($LHeight)
   C_ENTIER LONG($LLeft)
   C_ENTIER LONG($LMarkerPosition)
   C_ENTIER LONG($LMoveMarker)
   C_ENTIER LONG($LOriginalHeight)
   C_ENTIER LONG($LPrintedHeight)
   C_ENTIER LONG($LResize)
   C_ENTIER LONG($LRight)
   C_ENTIER LONG($LTop)
   C_ENTIER LONG($LWidth)
   C_REEL($rRatio)

   $LFormEvent:=Evenement formulaire

   Au cas ou

      : ($LFormEvent=Sur impression corps )

         LIRE ZONE IMPRESSION($LFormHeight)
            ` Add the needed pixels for a footer / ajouter des pixels pour le pied
         $LPrintedHeight:=Lire hauteur imprimee+20

         $LMoveMarker:=0
         $LMarkerPosition:=Lire taquet impression(Corps formulaire )

            ` retravailler l'image proportionnellement
         LIRE RECT OBJET([Products]Picture;$LLeft;$LTop;$LRight;$LBottom)
         PROPRIETES IMAGE([Products]Picture;$LWidth;$LHeight)

         Au cas ou

            : ($LHeight>$LWidth)

               $rRatio:=($LBottom-$LTop)/$LHeight
               DEPLACER OBJET([Products]Picture;$LLeft;$LTop;$LLeft+($LWidth*$rRatio);$LBottom;*)

            : ($LHeight<$LWidth)

               $rRatio:=($LRight-$LLeft)/$LWidth
               DEPLACER OBJET([Products]Picture;$LLeft;$LTop;$LRight;$LTop+($LHeight*$rRatio);*) 

         Fin de cas

            ` tester si la zone Acteurs est suffisamment grande
         LIRE RECT OBJET([Products]Actors;$LLeft;$LTop;$LRight;$LBottom)
         $LFixedWidth:=$LRight-$LLeft
         $LOriginalHeight:=$LBottom-$LTop
         TAILLE OBJET OPTIMALE([Products]Actors;$LWidth;$LHeight;$LFixedWidth)
         $LResize:=$LHeight-$LOriginalHeight

         Si ($LResize>0) ` We need more size for the Actors text area / on veut de la place
            FIXER TAQUET IMPRESSION(Corps formulaire ;$LMarkerPosition+$LResize;*)
            DEPLACER OBJET([Products]Actors;$LLeft;$LTop;$LRight;$LHeight+$LTop;*)
            LIRE RECT OBJET([Products]Synopsis;$LLeft;$LTop;$LRight;$LBottom)
            DEPLACER OBJET([Products]Synopsis;$LLeft;$LTop+$LResize;$LRight;$LBottom+$LResize;*)
            LIRE RECT OBJET(*;"SynopsisLabel";$LLeft;$LTop;$LRight;$LBottom)
            DEPLACER OBJET(*;"SynopsisLabel";$LLeft;$LTop+$LResize;$LRight;$LBottom+$LResize;*)
         Fin de si

            ` test de la taille synopsis
         LIRE RECT OBJET([Products]Synopsis;$LLeft;$LTop;$LRight;$LBottom)
         $LFixedWidth:=$LRight-$LLeft
         $LOriginalHeight:=$LBottom-$LTop
         TAILLE OBJET OPTIMALE([Products]Synopsis;$LWidth;$LHeight;$LFixedWidth)
         $LResize:=$LHeight-$LOriginalHeight

         Si ($LResize>0) ` on veut de la place
            FIXER TAQUET IMPRESSION(Corps formulaire ;$LMarkerPosition+$LResize;*)
            DEPLACER OBJET([Products]Synopsis;$LLeft;$LTop;$LRight;$LHeight+$LTop;*)
         Fin de si

         Si ($LPrintedHeight+$LHeight+$LTop>$LFormHeight) ` l'enregistrement ne tiendra pas dans la fenêtre
            NE PAS VALIDER ` annulle l'impression de CET enregistrement
         Fin de si

   Fin de cas


Ce code diffère de celui du « côte à côte » précédent parce que les objets sont « empilés » : il manipule deux objets séparément au lieu de le faire en même temps.

La méthode projet d'impression est également un brin plus compliquée car utilisant la méthode PRINT_PrintForm, que nous ne détaillerons car discutée dans une note différente.

   Si (Faux)
         ` Method: M_PrintFormCatalog
         ` 4D Technical Note
         ` Making the most of Best Object Size
         ` Created by: Kent Wilbur
         ` Date: 11/20/02
         ` Objectif : Montrer l'utilisation de la méthode PRINT FORM pour l'impression d'un
         ` listing genre catalogue
      ◊f_Version2003:=Vrai
      ◊fK_Wilbur:=Vrai
   Fin de si

   C_ENTIER LONG($i)
   C_ALPHA(2;$sFirstCharacter)

      ` Utilisé par la méthode PRINT_PrintForm mais pas dans cette base
   fPrintPage2ColumnHeaders:=Faux
   PARAMETRES IMPRESSION

   Si (OK=1)
         `sauver la sélection et la TRIER
      COPIER SELECTION([Products];"OriginalSelection")
      TRIER([Products]Title)
         ` on récupère le 1er caractère pour le mettre en entête
      $sFirstCharacter:=[Products]Title≤1≥
      PRINT_PrintForm (->[Products];"PrintFormCatalog";"MainHeader")
      PRINT_PrintForm (->[Products];"PrintFormCatalog";"Header1")

      Boucle ($i;1;Enregistrements trouves([Products]))

            ` en haut de la page on met la lettre
         Si ($sFirstCharacter#[Products]Title≤1≥)
            SAUT DE PAGE
            PRINT_PrintForm (->[Products];"PrintFormCatalog";"MainHeader")
            PRINT_PrintForm (->[Products];"PrintFormCatalog";"Header1")
            $sFirstCharacter:=[Products]Title≤1≥
         Fin de si

         PRINT_PrintForm (->[Products];"PrintFormCatalog";"Detail")

         Si (OK=0) ` impression annulée à cause du bas de la page
            SAUT DE PAGE
            PRINT_PrintForm (->[Products];"PrintFormCatalog";"MainHeader")
            PRINT_PrintForm (->[Products];"PrintFormCatalog";"Header1")
            PRINT_PrintForm (->[Products];"PrintFormCatalog";"Detail")
         Fin de si

         ENREGISTREMENT SUIVANT([Products])

      Fin de boucle

      SAUT DE PAGE `Make sure that the last page is printed / on n'oublie pas la dernière page

         ` Restore the original selection/on récupére la sélection originale
      UTILISER SELECTION("OriginalSelection")
      EFFACER SELECTION("OriginalSelection")

   Fin de si


VI. Conclusion

TAILLE OBJET OPTIMALE est probablement l'ajout le plus important à 4e Dimension depuis Créer fenêtre formulaire. Le plus grand bénéfice de cette fonction est de pouvoir influer sur les capacités d'impression de 4D. Combinée avec les ajouts et les modifications apportés à l'impression dès la 6.8.1 et sans cesse améliorés en 2003, vous comblez des demandes que vos utilisateurs finaux faisaient depuis fort longtemps.


VI. Base exemple

Téléchargez la base exemple :

Base pour Windows

Base pour Mac OS



Valid XHTML 1.1!Valid CSS!

Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.
Contacter le responsable de la rubrique 4D