Taille optimale d'objets

Kent D. WILBUR

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. ♪

- Titre : Taille optimale d'objets

- Auteur : Kent D. WILBUR

- Parution : 1 février 2003

- Licence : Ce document est issu de https://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.

Sommaire

- 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

- VII. 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).

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é.

1. ` manipulation sur le champ synopsis

2. LIRE RECT OBJET([Produits]Synopsis;$LSynopsisLeft;$LSynopsisTop;$LSynopsisRight;$LSynopsisBottom)

4. ` calcul de la taille avec l'ascenceur

5. $LSynopsisFixedWidth:=$LPictureLeft+$LPictureWidth-$LSynopsisLeft-16

6. TAILLE OBJET OPTIMALE([Produits]Synopsis;$LWidth;$LSynopsisIdealHeight;$LSynopsisFixedWidth)

8. `Autorise de l'espace supplémentaire pour la saisie

9. $LSynopsisIdealHeight:=$LSynopsisIdealHeight+16

10. $LDescriptionTop:=$LSynopsisIdealHeight-($LSynopsisBottom-$LSynopsisTop)

11. $LMove:=$LPictureHeight+$LPictureTop+10-$LSynopsisTop

12. DEPLACER OBJET(*;"SynopsisLabel";0;$LMove)

14. Si (($LSynopsisIdealHeight+$LSynopsisTop+120)>$LMaxScreenHeight)

15. $LSynopsisIdealHeight:=$LMaxScreenHeight-$LSynopsisTop-120

16. Fin de si

18. Si ($LSynopsisIdealHeight<32) ` Set minimum height / fixer la hauteur mini

19. $LSynopsisIdealHeight:=32

20. Fin de si

22. ` déplacer le champ

23. DEPLACER OBJET(*;"SynopsisField";0;$LMove;$LSynopsisFixedWidth-($LSynopsisRight-$LSynopsisLeft);

24. $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 :

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 :

La méthode formulaire est très simple :

1. Si (Faux)

2. ` Form Method: PrintSideBySide

3. ` 4D Technical Note

4. ` Making the most of Best Object Size

5. ` Created by: Kent Wilbur

6. ` Date: 1/21/03

7. ◊f_Version2003:= Vrai

8. ◊fK_Wilbur:= Vrai

9. Fin de si

11. C_ENTIER LONG($i)

12. C_ENTIER LONG($LBottom)

13. C_ENTIER LONG($LFixedWidth)

14. C_ENTIER LONG($LFormEvent)

15. C_ENTIER LONG($LFormHeight)

16. C_ENTIER LONG($LHeight)

17. C_ENTIER LONG($LLeft)

18. C_ENTIER LONG($LMarkerPosition)

19. C_ENTIER LONG($LMoveMarker)

20. C_ENTIER LONG($LOriginalHeight)

21. C_ENTIER LONG($LPrintedHeight)

22. C_ENTIER LONG($LResize)

23. C_ENTIER LONG($LRight)

24. C_ENTIER LONG($LTop)

25. C_ENTIER LONG($LWidth)

27. $LFormEvent:=Evenement formulaire

29. Au cas ou

31. : ($LFormEvent=Sur impression corps )

33. LIRE ZONE IMPRESSION($LFormHeight)

34. $LPrintedHeight:=Lire hauteur imprimee+5 ` pour les pieds

35. $LMoveMarker:=0

36. $LMarkerPosition:=Lire taquet impression(Corps formulaire )

38. TABLEAU POINTEUR($apFields;3)

39. $apFields{1}:=->[Produits]Titre

40. $apFields{2}:=->[Produits]Acteurs

41. $apFields{3}:=->[Produits]Synopsis

43. Boucle ($i;1;3)

44. LIRE RECT OBJET($apFields{$i}->;$LLeft;$LTop;$LRight;$LBottom)

45. $LFixedWidth:=$LRight-$LLeft

46. $LOriginalHeight:=$LBottom-$LTop

47. TAILLE OBJET OPTIMALE($apFields{$i}->;$LWidth;$LHeight;$LFixedWidth)

48. $LResize:=$LHeight-$LOriginalHeight

49. Si ($LResize>0)

50. DEPLACER OBJET($apFields{$i}->;$LLeft;$LTop;$LRight;$LHeight+$LTop;*)

51. Si ($LResize>$LMoveMarker)

52. $LMoveMarker:=$LResize

53. Fin de si

54. Fin de si

55. Fin de boucle

57. Si ($LFormHeight>($LPrintedHeight+$LMoveMarker+$LOriginalHeight))

58. Si ($LMoveMarker>0)

59. FIXER TAQUET IMPRESSION(Corps formulaire ;$LMarkerPosition+$LMoveMarker;*)

60. Fin de si

61. Sinon

62. NE PAS VALIDER

63. Fin de si

65. 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.

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.

1. Si (Faux)

2. ` Method: M_PrintSideBySide

3. ` 4D Technical Note

4. ` Making the most of Best Object Size

5. ` Created by: Kent Wilbur

6. ` Date: 1/21/03

7. ◊f_Version2003:=Vrai

8. ◊fK_Wilbur:=Vrai

9. Fin de si

11. C_ENTIER LONG($i)

12. C_ENTIER LONG($LHeight)

13. PARAMETRES IMPRESSION

15. Si (OK=1)

17. `Sauvegarder la sélection originale et la trier

18. COPIER SELECTION([Produits];"OriginalSelection")

19. TRIER([Produits];[Produits]Titre)

20. $LHeight:=Imprimer ligne([Produits];"PrintSideBySide";Entête formulaire )

22. Boucle ($i;1;Enregistrements trouves([Produits]))

23. $LHeight:=Imprimer ligne([Produits];"PrintSideBySide";Corps formulaire )

24. Si (OK=0) `ANNULER a été demandé dans la méthode formulaire

25. SAUT DE PAGE

26. $LHeight:=Imprimer ligne([Produits];"PrintSideBySide";Entête formulaire )

27. $LHeight:=Imprimer ligne([Produits];"PrintSideBySide";Corps formulaire )

28. Fin de si

29. ENREGISTREMENT SUIVANT([Produits])

30. Fin de boucle

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

34. ` revenir à la sélection d'origine

35. UTILISER SELECTION("OriginalSelection")

36. EFFACER SELECTION("OriginalSelection")

38. 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 :

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 :

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 :

1. Si (Faux)

2. ` Méthode formulaire : PrintFormCatalog

3. ` 4D Technical Note

4. ` Taille optimale d'objet

5. ` Créée par : : Kent Wilbur

6. ` Date : 11/20/02

7. ◊f_Version2003:=Vrai

8. ◊fK_Wilbur:=Vrai

9. Fin de si

11. C_ENTIER LONG($LBottom)

12. C_ENTIER LONG($LFixedWidth)

13. C_ENTIER LONG($LFormEvent)

14. C_ENTIER LONG($LFormHeight)

15. C_ENTIER LONG($LHeight)

16. C_ENTIER LONG($LLeft)

17. C_ENTIER LONG($LMarkerPosition)

18. C_ENTIER LONG($LMoveMarker)

19. C_ENTIER LONG($LOriginalHeight)

20. C_ENTIER LONG($LPrintedHeight)

21. C_ENTIER LONG($LResize)

22. C_ENTIER LONG($LRight)

23. C_ENTIER LONG($LTop)

24. C_ENTIER LONG($LWidth)

25. C_REEL($rRatio)

27. $LFormEvent:=Evenement formulaire

29. Au cas ou

31. : ($LFormEvent=Sur impression corps )

33. LIRE ZONE IMPRESSION($LFormHeight)

34. ` Add the needed pixels for a footer / ajouter des pixels pour le pied

35. $LPrintedHeight:=Lire hauteur imprimee+20

37. $LMoveMarker:=0

38. $LMarkerPosition:=Lire taquet impression(Corps formulaire )

40. ` retravailler l'image proportionnellement

41. LIRE RECT OBJET([Products]Picture;$LLeft;$LTop;$LRight;$LBottom)

42. PROPRIETES IMAGE([Products]Picture;$LWidth;$LHeight)

44. Au cas ou

46. : ($LHeight>$LWidth)

48. $rRatio:=($LBottom-$LTop)/$LHeight

49. DEPLACER OBJET([Products]Picture;$LLeft;$LTop;$LLeft+($LWidth*$rRatio);$LBottom;*)

51. : ($LHeight<$LWidth)

53. $rRatio:=($LRight-$LLeft)/$LWidth

54. DEPLACER OBJET([Products]Picture;$LLeft;$LTop;$LRight;$LTop+($LHeight*$rRatio);*)

56. Fin de cas

58. ` tester si la zone Acteurs est suffisamment grande

59. LIRE RECT OBJET([Products]Actors;$LLeft;$LTop;$LRight;$LBottom)

60. $LFixedWidth:=$LRight-$LLeft

61. $LOriginalHeight:=$LBottom-$LTop

62. TAILLE OBJET OPTIMALE([Products]Actors;$LWidth;$LHeight;$LFixedWidth)

63. $LResize:=$LHeight-$LOriginalHeight

65. Si ($LResize>0) ` We need more size for the Actors text area / on veut de la place

66. FIXER TAQUET IMPRESSION(Corps formulaire ;$LMarkerPosition+$LResize;*)

67. DEPLACER OBJET([Products]Actors;$LLeft;$LTop;$LRight;$LHeight+$LTop;*)

68. LIRE RECT OBJET([Products]Synopsis;$LLeft;$LTop;$LRight;$LBottom)

69. DEPLACER OBJET([Products]Synopsis;$LLeft;$LTop+$LResize;$LRight;$LBottom+$LResize;*)

70. LIRE RECT OBJET(*;"SynopsisLabel";$LLeft;$LTop;$LRight;$LBottom)

71. DEPLACER OBJET(*;"SynopsisLabel";$LLeft;$LTop+$LResize;$LRight;$LBottom+$LResize;*)

72. Fin de si

74. ` test de la taille synopsis

75. LIRE RECT OBJET([Products]Synopsis;$LLeft;$LTop;$LRight;$LBottom)

76. $LFixedWidth:=$LRight-$LLeft

77. $LOriginalHeight:=$LBottom-$LTop

78. TAILLE OBJET OPTIMALE([Products]Synopsis;$LWidth;$LHeight;$LFixedWidth)

79. $LResize:=$LHeight-$LOriginalHeight

81. Si ($LResize>0) ` on veut de la place

82. FIXER TAQUET IMPRESSION(Corps formulaire ;$LMarkerPosition+$LResize;*)

83. DEPLACER OBJET([Products]Synopsis;$LLeft;$LTop;$LRight;$LHeight+$LTop;*)

84. Fin de si

86. Si ($LPrintedHeight+$LHeight+$LTop>$LFormHeight) ` l'enregistrement ne tiendra pas dans la fenêtre

87. NE PAS VALIDER ` annule l'impression de CET enregistrement

88. Fin de si

90. 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.

1. Si (Faux)

2. ` Method: M_PrintFormCatalog

3. ` 4D Technical Note

4. ` Making the most of Best Object Size

5. ` Created by: Kent Wilbur

6. ` Date: 11/20/02

7. ` Objectif : Montrer l'utilisation de la méthode PRINT FORM pour l'impression d'un

8. ` listing genre catalogue

9. ◊f_Version2003:=Vrai

10. ◊fK_Wilbur:=Vrai

11. Fin de si

13. C_ENTIER LONG($i)

14. C_ALPHA(2;$sFirstCharacter)

16. ` Utilisé par la méthode PRINT_PrintForm, mais pas dans cette base

17. fPrintPage2ColumnHeaders:=Faux

18. PARAMETRES IMPRESSION

20. Si (OK=1)

21. `sauver la sélection et la TRIER

22. COPIER SELECTION([Products];"OriginalSelection")

23. TRIER([Products]Title)

24. ` on récupère le 1er caractère pour le mettre en entête

25. $sFirstCharacter:=[Products]Title≤1≥

26. PRINT_PrintForm (->[Products];"PrintFormCatalog";"MainHeader")

27. PRINT_PrintForm (->[Products];"PrintFormCatalog";"Header1")

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

31. ` en haut de la page on met la lettre

32. Si ($sFirstCharacter#[Products]Title≤1≥)

33. SAUT DE PAGE

34. PRINT_PrintForm (->[Products];"PrintFormCatalog";"MainHeader")

35. PRINT_PrintForm (->[Products];"PrintFormCatalog";"Header1")

36. $sFirstCharacter:=[Products]Title≤1≥

37. Fin de si

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

41. Si (OK=0) ` impression annulée à cause du bas de la page

42. SAUT DE PAGE

43. PRINT_PrintForm (->[Products];"PrintFormCatalog";"MainHeader")

44. PRINT_PrintForm (->[Products];"PrintFormCatalog";"Header1")

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

46. Fin de si

48. ENREGISTREMENT SUIVANT([Products])

50. Fin de boucle

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

54. ` Restore the original selection/on récupère la sélection originale

55. UTILISER SELECTION("OriginalSelection")

56. EFFACER SELECTION("OriginalSelection")

58. 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.

VII - Base exemple

Téléchargez la base exemple :

Base pour Windows

Base pour Mac OS