Developpez.com

Télécharger gratuitement le magazine des développeurs, le bimestriel des développeurs avec une sélection des meilleurs tutoriels

Developpez.com - 4D
X

Choisissez d'abord la catégorieensuite la rubrique :


Création et maintenance des barres de menus par programmation

Date de publication : Avril 2004

Par Jim DORRANCE
 

Cette note technique vous propose de créer et maintenir vos barres de menus et menus par programmation. En créant des méthodes projet spécifiques pour gérer des menus specifiques, puis en recomposant les menus, vous limitez ainsi les problèmes liés à la maintenance des barres de menu dans une base de données complexe et évolutive.

I. Introduction
II. Objectifs
III. La Base Demo: Preview
IV. La Base Demo: Constants
V. La Base Demo: Sur Ouverture
VI. Le Process SplashScreen_
VII. The Process Demo
VIII. Les Méthodes Init_Menus
IX. La Base Demo: Barre de menus - Utilisation d'une référence à une ressource pour un libellé
X. La Base Demo: Barre de menus - Création des ressources STR#
XI. Mise a Jour des MenuBars et la methode Menus_Draw
XII. La Base Demo
XIII. Conclusion
XIV. Bases exemples


I. Introduction

Plus une base de données devient complexe, plus il devient difficile de maintenir certaines de ses fonctionnalités.

L'un des domaines pouvant alors poser problème est la création et l'entretien des barres de menus et des menus. Pendant que de nouveaux modules sont créés dans la base de données, des barres de menus additionnelles sont ajoutées, recréant souvent des lignes ou des menus déjà existants dans une autre barre de menus. 

L'Editeur de barres de menu finit souvent par ressembler à ceci :

Pictures 0565x0151



Dans un environnement multi-développeur, les problémes potentiels surgissent quand des développeurs d'expérience différente accèdent à l'éditeur de barres de menu.

Cette note technique explique comment combiner les appels de bas niveau AJOUTER LIGNE MENU avec un ensemble de barres de menus générique. 


II. Objectifs

Plutôt que de créer des menus spécifiques avec des lignes de  menu spécifiques, nous approchons le problème avec une perspective différente. Traditionnellement nous raisonnons de façon à déterminer à l'avance pour chaque barre les menus dont on peut avoir besoin: Fichier, Edition, et peut-être des menus Mode, Configuration, Outils et d'autres. On pourrait plutôt généraliser et se dire qu'une fenêtre peut avoir de 1 à 10 (et peut-être plus) menus dans la barre de menus associée.

Notre base de demo contient 10 barres de menus, la première barre de menus a 1 menu, la deuxième barre de menus a 2 menus, etc. jusqu'à la dixième barre de menus avec 10 menus.

Pictures 0580x0285
Pictures 0593x0312



Il n'y a aucun libellé associé aux menus, seulement des variables interprocess, variables qui contiendront la ressource STR# et les éléments de références.

Il n'y a aucune ligne de menu liée au barre de menus, excepté pour le menu Edition qui sera gérer par 4D.


III. La Base Demo: Preview

Nous voudrions associer une barre de menus simple à une fenêtre de bienvenue :

Pictures 0491x0031



et une barre de menus différente à la fenêtre de demo.

Pictures 0608x0016
  • Quand la fenêtre de bienvenue est la fenêtre de premier plan, la barre de menus simple devrait être affichée.

  • Quand la fenêtre de demo est la fenêtre de premier plan, un autre barre de menus devrait être montrée. La barre de menus devrait être sensible au contexte et facilement modifiable.

  • Les menus devraient être localisables dans la langue de l'utilisateur.

IV. La Base Demo: Constants

Dans une Note Technique précédente, j'ai montré comment créer des constantes prédéfinies par programmation. La base demo utilise des constantes créées par la méthode projet Ks_.

Ces constantes sont :

      `
      `LES LANGUES IMPLEMENTEES
      `

   kL_French
   kL_English
   kL_German
      `
      `BARRE DES MENUS: INDICES POUR LES RESSOURCES STR# (TEXTE DES MENUS)
      `

   kMBResID_File
   kMBResID_Edit
   kMBResID_Find
   kMBResID_FONT
   kMBResID_Size
   kMBResID_Style
   kMBResID_Alignment
   kMBResID_Window
      `
   kMBResID_theCount
      `
      ` NOMBRE DE SEQUENCE SIMPLE: DONNE UN ID UNIQUE À CHAQUE ÉLÉMENT DE `MENU  `
      `
      `MENU FILE
      `

   kMenuFile_
      `
   kMenuFile_New
   kMenuFile_Open
   kMenuFile_Close
   kMenuFile_Save
   kMenuFile_SaveAs
   kMenuFile_Revert
   kMenuFile_PageSetup
   kMenuFile_Print
   kMenuFile_Quit
      `
      ` MENU FIND/CHANGE
      `

   kMenuFind_
      `
   kMenuFind_Find
   kMenuFind_FindNext
   kMenuFind_Replace
      `
      `MENU FONT
      `

   kMenuFont_
      `
      `MENU SIZE
      `

   kMenuSize_
      `
   kMenuSize_9
   kMenuSize_10
   kMenuSize_12
   kMenuSize_14
   kMenuSize_18
   kMenuSize_24
   kMenuSize_36
   kMenuSize_48
   kMenuSize_72
   kMenuSize_Other
      `
      `MENU STYLE
      `

   kMenuStyle_
      `
   kMenuStyle_PlainText
   kMenuStyle_Bold
   kMenuStyle_Italic
   kMenuStyle_Underline
   kMenuStyle_DoubleUnderline
   kMenuStyle_StrikeThru
   kMenuStyle_Outline
   kMenuStyle_Shadow
   kMenuStyle_Condense
   kMenuStyle_Extend
      `
      `MENU ALIGNMENT
      `

   kMenuAlign_
      `
   kMenuAlign_Left
   kMenuAlign_Center
   kMenuAlign_Right
   kMenuAlign_Justify
      `
      `MENU WINDOW
      `

   kMenuWindow_
      `
   kMenuWindow_Close
   kMenuWindow_CloseAll
   kMenuWindow_Next
   kMenuWindow_Previous
   kMenuWindow_TileWindows
   kMenuWindow_StackWindows 
      `
      `SELECTEURS POUR Alert_
      `

   kAlert_BadParamCount


V. La Base Demo: Sur Ouverture

La base Demo initialise des variables interprocess et crée 2 process au démarrage. Une variable interprocess (<>theLanguage) sera initialisée avec la constante kL_French, la langue par défaut.

   Compiler_InterProcess

      `
   <>theLanguage:=kL_French
      `
   <>Process_SplashScreen:=Nouveau process("SplashScreen_";32*1024;"$SplashScreen")

   <>Process_Demo:=Nouveau process("Demo_";32*1024;"$Demo")


VI. Le Process SplashScreen_

Le process SplashScreen_ récupère son ID et l'affecte à la variable interprocess <>Process_SplashScreen.
Le process SplashScreen_ initialise alors des variables process.

La barre des menu est initialisée dans la méthode projet SplashScreen_Init_Menus .

Un dialogue de bienvenue simple est alors affiché.

   <>Process_SplashScreen:=Numero du process courant

      `
   Compiler_Process
      `
   SplashScreen_Init_Menus
      `
   C_ENTIER LONG($W;$H)
   LIRE PROPRIETES FORMULAIRE([Table 1];"SplashScreen";$W;$H)
      `
   C_ENTIER LONG($L;$T;$R;$B)
   $L:=((Largeur ecran-$W)/2)
   $T:=((Hauteur ecran-$H)/3)
   $R:=$L+$W
   $B:=$T+$H
      `
   Creer fenetre($L;$T;$R;$B;3)
   DIALOGUE([Table 1];"SplashScreen")

   FERMER FENETRE


VII. The Process Demo

Le process Demo récupère son ID et l'affecte à la variable interprocess <>Process_ Demo.
Le process Demo alors initialise des variables process.

La barre des menu est initialisée dans la méthode projet Demo_Init_Menus.

Un dialogue est alors dessiné, quoique caché.

   <>Process_Demo:=Numero du process courant

   CACHER PROCESS (?Process_Demo)
      `
   Compiler_Process
      `
   Demo_Init
   Demo_Init_Menus
      `
   C_ENTIER LONG($width;$height;$l;$t;$r;$b)
   LIRE PROPRIETES FORMULAIRE([Table 1];"Demo";$width;$height)
      `
   $l:=((Largeur ecran-$width)/2)
   $t:=((Hauteur ecran-$height)/3)
   $r:=$l+$width
   $b:=$t+$height
      `
   <>Window_Demo:=Creer fenetre($l;$t;$r;$b;Fenêtre normale ;"Demo")
   DIALOGUE([Table 1];"Demo")

   FERMER FENETRE


VIII. Les Méthodes Init_Menus

Les méthodes Init_Menus définissent les menus et les lignes de menu qui doivent être utilisés par le process.

Le tableau entier long arMenus contient les indices de la ressource STR# qui elle-même contient les textes des menus à afficher.

Le tableau booléen arMenuLignes est employé, avec les constantes prédéfinies 'kMenu... ' comme drapeaux indiquant si une ligne est activée ou neutralisée.

Le process SplashScreen utilise seulement le menu Fichier et la ligne Quitter :

   SplashScreen_Init_Menus

      `
      `ON UTILISE SEULEMENT LE MENU FILE
      `

   TABLEAU ENTIER LONG(arMenus;1)
   arMenus{1}:=kMBResID_File
      `
      `ON DESACTIVE TOUTES LES LIGNES DE MENUS
      `

   TABLEAU BOOLEEN(arMenuLines;kMenu_theCount )
   Boucle ($i;1;kMenu_theCount )
      arMenuLines{$i}:=Faux
   Fin de boucle
      `
      `ON ACTIVE LE MENU FILE
      `

   arMenuLines{kMenuFile_ }:=Vrai
      `
      `ON ACTIVE LA LIGNE DE MENU QUIT DU MENU FILE
      `

   arMenuLines{kMenuFile_Quit }:=Vrai
      `
      `ON CACHE LES LIGNES DE MENUS NON UTILISEES
      `


   MenuLines_DisableUnused:=Faux



Le process Demo utilise tous les menus et dans l'ordre dans lequel ils apparaissent dans le tableau arMenus

   Demo_Init_Menus

      `
      `ON UTILISE TOUS LES MENUS
      `

   TABLEAU ENTIER LONG(arMenus;kMBResID_theCount )
      `
   arMenus{1}:=kMBResID_File
   arMenus{2}:=kMBResID_Edit
   arMenus{3}:=kMBResID_Find
   arMenus{4}:=kMBResID_FONT
   arMenus{5}:=kMBResID_Size
   arMenus{6}:=kMBResID_Style
   arMenus{7}:=kMBResID_Alignment
   arMenus{8}:=kMBResID_Window
      `
      `ON REND TOUTES LES LIGNES DE MENUS ACTIVES
      `

   TABLEAU BOOLEEN(arMenuLines;kMenu_theCount )
   Boucle ($i;1;kMenu_theCount )
      arMenuLines{$i}:=Vrai
   Fin de boucle
      `
      `ON INACTIVE LES LIGNES DE MENU NON UTILISEES
      `


   MenuLines_DisableUnused:=Vrai


IX. La Base Demo: Barre de menus - Utilisation d'une référence à une ressource pour un libellé

Vous pouvez employer une ressource STR# au lieu du texte pour fixer un libellé de menu et ainsi faciliter la traduction dans différentes langues.

Cependant, plutôt que de mettre “:2000,3” pour montrer le texte contenu dans la troisième ligne de la ressource STR# 2000, nous mettrons des références à des variables interprocess.

Ainsi, changer les valeurs contenues dans ces variables en référence aux différentes ressources STR#,  changera le nom du menu en conséquence à l'affichage suivant.

La variable interprocess <>MRes contiendra la référence à la ressource STR# contenant elle-même les textes localisés des menus.

Et les variables interprocess <>MElem1...<>MElem10 indiqueront l'élément de la ressource STR# à utiliser comme texte pour le menu.


X. La Base Demo: Barre de menus - Création des ressources STR#

La méthode projet Menus_Strs_MenuBars crée les ressources STR# pour la base de Demo. Des ressources sont créées pour l'anglais, le Français et l'Allemand.

Les menus français sont dans la STR# 30001

Pictures 0303x0264



Les menus anglais sont dans la STR# 30002

Pictures 0295x0257

XI. Mise a Jour des MenuBars et la methode Menus_Draw

Quand la fenêtre du process SplashScreen ou Demo est amenée au premier plan, l'événement formulaire "Sur activation" est reçu.

La méthode projet Menus_Draw est alors appelée.

Au début de la méthode Menus_Draw, les références des ressources STR# sont affectées aux variables interprocess <>MRes  selon le langage courant.

   <>MRes:=30000+<>theLanguage


et, ensuite, toutes les références d'élément de ressource précédemment utilisées  sont remises à zéro en appelant la méthode projet Menus_MBResID_RaZ:

   <>MElem1:=0

   <>MElem2:=0
   <>MElem3:=0
   <>MElem4:=0
   <>MElem5:=0
   <>MElem6:=0
   <>MElem7:=0
   <>MElem8:=0
   <>MElem9:=0

   <>MElem10:=0


Le nombre de menus employés par le process est calculé à partir de la taille du tableau définie dans la phase d'Init_Menu du process :

   C_ENTIER LONG($Size)

   $Size:=Taille tableau(arMenus)


Et les tailles des 5 tableaux sont alors fixées en conséquence :

   TBox_Arrays_SizeSet ($Size;->arMenuLines_Str;->arMenuActive;->arMenuHandle;

   ->arMenuEvents2D;->arMenuProcess2D)


ArMenuLines contient le texte à employer avec AJOUTER LIGNE MENU.

ArMenuActive indique si le menu est activé.

ArMenuHandle contient la constante prédéfinie indiquant le menu logique correspondant au menu.

arMenuEvents2D contient la constante d'événement prédefinie pour le menu/ligne.

arMenuProcess2D contient le process à appeler avec l'événement.  Le process courant sera appelé si 0.


Ensuite 2 compteurs sont initialisés à 0 :

   theMenuCounter:=0

   theMenuLineCounter:=0


Et la méthode Menus_Draw fait une boucle pour la taille du tableau arMenus. Si le type de menu est inclus dans arMenus, et si le menu est activé, la variable contenant le compteur de menu sera augmentée de 1 et lancera une méthode projet qui construira le texte de la ligne de menu pour ce menu.

   C_ENTIER LONG($i)

   Boucle ($i;1;$Size)
         `
      Au cas ou
            `
         : (arMenus{$i}=kMBResID_File )   `CONSTRUCTION DU MENU FILE
            Si (arMenuLines{kMenuFile_ } | MenuLines_DisableUnused)
               theMenuCounter:=theMenuCounter+1
               Menus_Draw_Menu_File (theMenuCounter)
            Fin de si
               `
         : (arMenus{$i}=kMBResID_Edit )   `MENU EDIT
            theMenuCounter:=theMenuCounter+1
               `
         : (arMenus{$i}=kMBResID_Find )   `MENU FIND/CHANGE
            Si (arMenuLines{kMenuFind_ } | MenuLines_DisableUnused)
               theMenuCounter:=theMenuCounter+1
               Menus_Draw_Menu_FindChange (theMenuCounter)
            Fin de si
               `
         : (arMenus{$i}=kMBResID_FONT )   `MENU FONT
            Si (arMenuLines{kMenuFont_ } | MenuLines_DisableUnused)
               theMenuCounter:=theMenuCounter+1
               Menus_Draw_Menu_Font (theMenuCounter)
            Fin de si
               `
         : (arMenus{$i}=kMBResID_Size )   `MENU SIZE
               `
            Si (arMenuLines{kMenuSize_ } | MenuLines_DisableUnused)
               theMenuCounter:=theMenuCounter+1
               Menus_Draw_Menu_Size (theMenuCounter)
            Fin de si
               `
         : (arMenus{$i}=kMBResID_Style )   `MENU STYLE
               `
            Si (arMenuLines{kMenuStyle_ } | MenuLines_DisableUnused)
               theMenuCounter:=theMenuCounter+1
               Menus_Draw_Menu_Style (theMenuCounter)
            Fin de si
               `
         : (arMenus{$i}=kMBResID_Alignment )   `MENU ALIGNMENT
               `
            Si (arMenuLines{kMenuAlign_ } | MenuLines_DisableUnused)
               theMenuCounter:=theMenuCounter+1
               Menus_Draw_Menu_Alignment (theMenuCounter)
            Fin de si
               `
         : (arMenus{$i}=kMBResID_Window )   `MENU WINDOW
               `
            Si (arMenuLines{kMenuWindow_ } | MenuLines_DisableUnused)
               theMenuCounter:=theMenuCounter+1
               Menus_Draw_Menu_Window (theMenuCounter)
            Fin de si
               `
      Fin de cas
         `

   Fin de boucle



Examinons une des méthodes de construction des lignes de menu, Menus_Draw_Menu_FindChange :

   C_ENTIER LONG($1)   `LA BARRE DE MENU A DESSINER

   C_ENTIER LONG($Menu)

   $Menu:=$1


Le type de menu est sauvé dans arMenuHandle,

   arMenuHandle{$Menu}:=kMenuFind_

   Menus_Set_MBResID ($Menu;kMBResID_Find )


Le texte contenant les libellés est initialisé et le compteur de lignes est remis à zéro.

   arMenuLines_Str{$Menu}:=""

   theMenuLineCounter:=0
   arMenuActive{theMenuCounter}:=Faux
   `
   TBox_Arrays_SizeSet ($Menu;->arMenuEvents2D)

   TBox_Arrays_SizeSet ($Menu;->arMenuProcess2D)


Si le menu est actif, une méthode générique est appelée pour ajouter chaque ligne du menu

      `

   Si (arMenuLines{arMenuHandle{$Menu}})
         `
      TBox_Arrays_SizeSet (3;->arMenuEvents2D{$Menu})
      TBox_Arrays_SizeSet (3;->arMenuProcess2D{$Menu})
         `
      Menus_Draw_Get1Line (arMenuLines{kMenuFind_Find };kMenuFind_Find ;0)
      Menus_Draw_Get1Line (arMenuLines{kMenuFind_FindNext };kMenuFind_FindNext ;0)
      Menus_Draw_Get1Line (arMenuLines{kMenuFind_Replace };kMenuFind_Replace ;0)
         `
      TBox_Arrays_SizeSet (theMenuLineCounter;->arMenuEvents2D{$Menu})
      TBox_Arrays_SizeSet (theMenuLineCounter;->arMenuProcess2D{$Menu})
         `

   Fin de si


La méthode projet Menus_Draw_Get1Line vérifie si la ligne est activeet si oui Menus_Strs_MenuItems est appelé pour obtenir le texte à ajouter à l'élément d'arMenuLines pour le menu. La réference de la ligne est mise dans l'élément d'arMenuEvents2D pour le menu. Le numero de process appelant la ligne est mis dans l'élément d'arMenuProcess2D pour le menu.

Si la ligne n'est pas activée, et que nous souhaitons montrer une ligne grisé dans le menu, "(" est mis avant le texte et les éléments d'événement et numero de process sont mis à 0.

   C_BOOLEEN($1)   ` ACTIVE

   C_ENTIER LONG($2)   `EVENEMENT A ENVOYER
   C_ENTIER LONG($3)   `PROCESS A ENVOYER
      `
      `
   Si ($2>0)
      Si ($1)
         theMenuLineCounter:=theMenuLineCounter+1
         arMenuLines_Str{theMenuCounter}:=arMenuLines_Str{theMenuCounter}+Menus_Strs_MenuItems ($2)+";"
         arMenuActive{theMenuCounter}:=Vrai
         arMenuEvents2D{theMenuCounter}{theMenuLineCounter}:=$2
         arMenuProcess2D{theMenuCounter}{theMenuLineCounter}:=$3
      Sinon
         Si (MenuLines_DisableUnused)
            theMenuLineCounter:=theMenuLineCounter+1
            arMenuLines_Str{theMenuCounter}:=arMenuLines_Str{theMenuCounter}+"("+Menus_Strs_MenuItems ($2)+";"
            arMenuEvents2D{theMenuCounter}{theMenuLineCounter}:=0
            arMenuProcess2D{theMenuCounter}{theMenuLineCounter}:=0
         Fin de si
      Fin de si

   Fin de si


Nos tableaux une fois renseignés, il est temps de dessiner la barre de menus :

   Menus_Clear (($theProcess)

   Menus_Put_MenuBar (theMenuCounter;$theProcess)

   Menus_Append ($theProcess)


D'abord, les lignes existantes sont "dégagées" : Menus_Clear (($theProcess)

   C_ENTIER LONG($1)   `MENU PROCESS

      `
      `
   C_ENTIER LONG($i;$j;$theProcess)
   Si (Nombre de parametres=1)
      $theProcess:=$1
   Sinon
      $theProcess:=Numero du process courant
   Fin de si
      `
   Boucle ($i;1;Nombre de menus($theProcess))
      Si ($i#2)   `ON SAUTE LE MENU EDIT
         Boucle ($j;Nombre de lignes de menu($i;$theProcess);1;-1)
            SUPPRIMER LIGNE MENU($i;$j;$theProcess)
         Fin de boucle
      Fin de si

   Fin de boucle


La variable theMenuCounter contient le nombre des menus requis dans la barre des menus.
Une nouvelle barre de menus est alors installée :

   Menus_Put_MenuBar (theMenuCounter;$theProcess)



   C_ENTIER LONG($1)   `MENU COUNT

   C_ENTIER LONG($2)   `LE PROCESS
      `
      `
   Si (Nombre de parametres=2)
         `
      C_TEXTE($t)
      $t:="Shell1."+Chaine($1)
      CHANGER BARRE($t;$2)
         `
   Sinon
      Alert_ (Nom methode courante;kAlert_BadParamCount )

   Fin de si


Et enfin, les lignes de menu sont ajoutées à chaque menu : Menus_Append ($theProcess)

   C_ENTIER LONG($1)

      `
      `
   C_ENTIER LONG($i)
   Boucle ($i;1;Taille tableau(arMenuLines_Str))
      Si ($i#2)   `MENU EDIT
            `
         AJOUTER LIGNE MENU($i;arMenuLines_Str{$i};$1)
         Si (Non(arMenuActive{$i}))
            INACTIVER LIGNE MENU($i;0;$1)
         Sinon
            ACTIVER LIGNE MENU($i;0;$1)
         Fin de si
            `
      Fin de si

   Fin de boucle


XII. La Base Demo

La base Demo vous permet d'examiner les avantages de la création des menus par programmation.

  • Un clic sur une ligne dans le tableau "Enabled state" inverse le drapeau Enabled/Disabled pour la ligne de menu.

  • Commande-clic inverse tous les drapeaux Enabled/Disable.

  • Si le bouton radio "Hide Unused Menus Lines" est coché, les lignes de menu désactivées ne seront pas dessinées.

  • Si le bouton radio "Disable Unused Menus Lines" est coché, les lignes de menu désactivées seront grisées.
Pictures 0412x0292



Sur l'onglet "Display Order", un glissé/déposé vous permet de charger l'ordre dans lequel les menus sont dessinés. Le menu Fichier et le menu Edition apparaîtront toujours en 1ère et 2ème positions.

Pictures 0576x0408

XIII. Conclusion

L'utilisation de ce "rédacteur" de barres de menus de barre est très pratique. En créant des méthodes projet spécifiques pour gérer des menus specifiques, puis en recomposant les menus par programmation, vous limitez ainsi les problèmes liés à  la maintenance des barres de menu dans une base de données complexe et évolutive.


XIV. Bases exemples

Téléchargez les bases exemples :

base exemple Mac

base exemple Windows

__________________________________________________
Copyright © 1985-2009 4D SA - Tous droits réservés
Tous les efforts ont été faits pour que le contenu de cette note technique présente le maximum de fiabilité possible.
Néanmoins, les différents éléments composant cette note technique, et le cas échéant, le code, sont fournis sans garantie d'aucune sorte. L'auteur et 4D S.A. déclinent donc toute responsabilité quant à l'utilisation qui pourrait être faite de ces éléments, tant à l'égard de leurs utilisateurs que des tiers.
Les informations contenues dans ce document peuvent faire l'objet de modifications sans préavis et ne sauraient en aucune manière engager 4D SA. La fourniture du logiciel décrit dans ce document est régie par un octroi de licence dont les termes sont précisés par ailleurs dans la licence électronique figurant sur le support du Logiciel et de la Documentation afférente. Le logiciel et sa documentation ne peuvent être utilisés, copiés ou reproduits sur quelque support que ce soit et de quelque manière que ce soit, que conformément aux termes de cette licence.
Aucune partie de ce document ne peut être reproduite ou recopiée de quelque manière que ce soit, électronique ou mécanique, y compris par photocopie, enregistrement, archivage ou tout autre procédé de stockage, de traitement et de récupération d'informations, pour d'autres buts que l'usage personnel de l'acheteur, et ce exclusivement aux conditions contractuelles, sans la permission explicite de 4D SA.
4D, 4D Calc, 4D Draw, 4D Write, 4D Insider, 4ème Dimension ®, 4D Server, 4D Compiler ainsi que les logos 4e Dimension, sont des marques enregistrées de 4D SA.
Windows,Windows NT,Win 32s et Microsoft sont des marques enregistrées de Microsoft Corporation.
Apple, Macintosh, Power Macintosh, LaserWriter, ImageWriter, QuickTime sont des marques enregistrées ou des noms commerciaux de Apple Computer,Inc.
Mac2Win Software Copyright © 1990-2002 est un produit de Altura Software,Inc.
4D Write contient des éléments de "MacLink Plus file translation", un produit de DataViz, Inc,55 Corporate drive,Trumbull,CT,USA.
XTND Copyright 1992-2002 © 4D SA. Tous droits réservés.
XTND Technology Copyright 1989-2002 © Claris Corporation.. Tous droits réservés ACROBAT © Copyright 1987-2002, Secret Commercial Adobe Systems Inc.Tous droits réservés. ACROBAT est une marque enregistrée d'Adobe Systems Inc.
Tous les autres noms de produits ou appellations sont des marques déposées ou des noms commerciaux appartenant à leurs propriétaires respectifs.
__________________________________________________
 



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