TDateTimePicker a gagné une propriété Format quelque part entre Delphi 5 et Delphi 6. La limite de version exacte est rarement documentée de façon fiable, et lorsque vous la rencontrez, le compilateur se contente de vous dire que l'identificateur n'existe pas. La ligne qui compile et fonctionne sur toutes les versions plus récentes de Delphi échoue silencieusement, ou carrément, sur l'ancienne, selon la structure du projet
Le contrôle sous-jacent est le contrôle commun Windows DATETIMEPICK_CLASS dans comctl32.dll, qui accepte toujours une chaîne de format via le message DTM_SETFORMAT. La VCL de Delphi, dans ses versions plus récentes, encapsule ce message dans la propriété Format. Sous Delphi 5, vous devez envoyer le message vous-même via l'encapsulateur de macro DateTime_SetFormat déclaré dans CommCtrl
Mode de compilation conditionnelle
La méthode standard repose sur des blocs conditionnels du compilateur basés sur les symboles de version. Delphi 5 définit VER130 ; vous pouvez le tester directement ou définir votre propre symbole D5 dans les options du projet pour rendre les étiquettes de branche plus lisibles dans la base de code. Quoi qu'il en soit, la branche Delphi 5 appelle DateTime_SetFormat avec le handle du contrôle ; les autres branches affectent directement la propriété :
{$IFDEF D5}
DateTime_SetFormat(DateTimePicker1.Handle, PChar('MM/dd/yyyy'));
{$ELSE}
DateTimePicker1.Format := 'MM/dd/yyyy';
{$ENDIF}
Ajoutez CommCtrl à la clause uses des unités contenant la branche Delphi 5. Il n'est pas nécessaire de l'ajouter inconditionnellement ; si vous souhaitez limiter la portée de la dépendance, vous pouvez envelopper l'entrée uses avec la même condition :
uses
...,
{$IFDEF D5}
CommCtrl,
{$ENDIF}
...;
Syntaxe de la chaîne de format
La chaîne de format transmise à DateTime_SetFormat suit le format du sélecteur de date-heure de Windows, pas les jetons FormatDateTime de Delphi. Les deux se ressemblent mais ne sont pas interchangeables. Windows utilise d pour le jour du mois (sans zéro initial), dd pour le jour avec zéro initial, M pour le numéro du mois, MM pour le mois avec zéro initial, yy pour l'année sur deux chiffres, et yyyy pour l'année sur quatre chiffres. Les champs d'heure utilisent h/hh pour l'heure au format 12 heures, H/HH pour le format 24 heures, m/mm pour les minutes, s/ss pour les secondes. Le texte littéral se place entre guillemets simples dans la chaîne de format, donc 'dd/MM/yyyy' est déjà correct, mais 'dd '<literal>' MM' nécessiterait des paires de guillemets simples imbriquées
En comparaison, FormatDateTime de Delphi utilise d/dd/ddd/dddd pour les formes du jour, avec une sémantique différente, et m pour le mois (pas M). Si vous copiez une chaîne de format issue d'un appel à FormatDateTime et que vous la transmettez directement à DateTime_SetFormat, les champs du mois et des minutes seront probablement inversés dans le résultat. Écrivez la chaîne de format du contrôle à partir de zéro en vous basant sur la documentation Windows, plutôt que de la convertir à partir d'un format Delphi
Paramètres régionaux et ShortDateFormat global
Modifier la variable globale ShortDateFormat de Delphi n'affecte pas un TDateTimePicker déjà créé. Le sélecteur lit les paramètres régionaux de Windows lors de sa création et effectue le rendu en fonction des messages qu'il reçoit par la suite, et non des variables globales de la RTL Delphi. Cela signifie que configurer ShortDateFormat dans FormCreate ne modifiera pas l'affichage du contrôle. Vous devez utiliser DateTime_SetFormat (ou la propriété Format sur les versions récentes de Delphi) pour remplacer la chaîne de format du contrôle une fois le handle existant
Pour les applications déployées à l'international, testez les chaînes de format sur des machines ayant des paramètres régionaux non américains. Windows peut remplacer une chaîne de format vide ou nil par les valeurs par défaut de la région, mais une chaîne officielle non nil remplace entièrement les paramètres régionaux. C'est généralement ce que vous souhaitez, mais cela signifie qu'un modèle centré sur les États-Unis comme 'MM/dd/yyyy' s'affichera tel quel pour les utilisateurs habitués à dd/MM/yyyy. Si le sélecteur de date est destiné à l'utilisateur et n'est pas un simple champ de saisie de données, envisagez de laisser le contrôle utiliser la valeur par défaut (en passant nil à DateTime_SetFormat) afin qu'il suive automatiquement les paramètres régionaux de l'utilisateur
Reconstruction de descripteur
La configuration du format appartient au handle de la fenêtre, et non à un champ d'objet VCL. Si le handle du contrôle est détruit et reconstruit (ce que la VCL peut faire lorsque vous changez le parent du contrôle ou modifiez certaines propriétés de style au runtime), le format revient aux valeurs par défaut de Windows. L'emplacement sûr pour appliquer DateTime_SetFormat est le gestionnaire s'exécutant après la création du handle : remplacez CreateWnd dans les classes descendantes et appelez-y la fonction, ou appliquez-la dans l'événement OnEnter ou OnShow après avoir confirmé que le handle est actif. Pour les formulaires simples, le configurer une fois dans FormCreate suffit généralement, mais cela s'avère peu fiable si le formulaire effectue des changements de style dynamiques ou des changements de parents de contrôles
La même contrainte s'applique à la propriété Format de la VCL sur les versions plus récentes de Delphi ; elle appelle la même clé de message Windows en interne et fait face aux mêmes problèmes de cycle de vie du handle. La différence est que le configurateur de propriété VCL vérifie si le handle est alloué avant l'appel et réapplique automatiquement le format lors de CreateWnd. L'appel d'origine DateTime_SetFormat ne dispose pas d'une telle protection, de sorte que la branche Delphi 5 nécessite une sélection plus prudente du moment d'exécution
Supprimer la solution de contournement
Lorsque le projet ne prend plus en charge Delphi 5, les blocs conditionnels deviennent un fardeau. Supprimez la branche {$IFDEF D5} et l'importation limitée de CommCtrl, en ne conservant que l'affectation directe de la propriété Format. Réalisez cette suppression dans un commit dédié pour faciliter l'identification en cas de problème inattendu sur un compilateur non testé. La chaîne de format elle-même reste inchangée ; seul le mécanisme de transmission est modifié