La composante écriture, partie 2

La composante écriture, partie 2


Cet article portera sur la manière d'écrire les propriétés avancées, comment écrire personnalisé en streaming pour les propriétés, et les sous-propriétés.




Cet article est paru initialement dans les Développeur Delphi



le droit d'Auteur Pinnacle Publishing, Inc. Tous droits réservés.







Cet article fait partie de deux des trois parties de l'article sur les composants. La première partie couvert la base de la création de composants, partie deux abordera la façon d'écrire les propriétés avancées, comment écrire personnalisé en streaming pour les propriétés, et les sous-propriétés. La dernière partie couvrira propriété / éditeurs de composants, comment écrire dédié éditeurs pour votre composant de la propriété, et comment écrire 'caché' des composants.



Très souvent, il est nécessaire d'écrire des composants qui exécutent des fonctions plus avancées. Ces composants doivent souvent faire référence à d'autres composants, sont la propriété personnalisée formats de données, ou d'avoir une propriété qui possède une liste de valeurs plutôt qu'une valeur unique. Dans cette partie, nous allons explorer les différents exemples couvrant ces sujets, en commençant par le plus simple.



références Composant

Certains composants besoin de faire référence à d'autres composants. TLabel, par exemple, a un 'FocusControl de la propriété'. Lorsque vous incluez une esperluette dans la 'Légende' il souligne la lettre suivante ( & Bonjour devient Bonjour), en appuyant sur la touche de raccourci ALT-H sur votre clavier va déclencher un événement dans votre étiquette. Si le 'FocusControl' a été établi, l'accent sera transmis au contrôle spécifié.



Pour avoir une telle propriété dans votre propre composant est assez simple. Tout ce que vous faire est de déclarer une nouvelle propriété, et de définir le type de propriété à la plus basse classe de base qu'il peut accepter (twincontrol a permettra à tout descendant de twincontrol a à être utilisé), mais, il y a des conséquences.







& ! & ! & ! & nbsp



type

& nbsp & nbsp TSimpleExample = class(TComponent)

& nbsp & nbsp privé

& ! & ! & ! & nbsp FFocusControl: twincontrol a

& nbsp & nbsp protected

& ! & ! & ! & nbsp procédure SetFocusControl(const Valeur: twincontrol a) virtual

& nbsp & nbsp public

& nbsp & nbsp publié

& ! & ! & ! & nbsp propriétés FocusControl: Twincontrol a lire FFocusControl écrire SetFocusControl

& nbsp & nbsp fin



procédure TSimpleExample.SetFocusControl(const Valeur: twincontrol a)

démarrer

& nbsp & nbsp FFocusControl := Valeur

fin

& ! & ! & ! & nbsp




Prendre l'exemple ci-dessus. C'est tout à fait un exemple simple (d'où le nom du composant) de comment écrire un composant qui fait référence à un autre composant. Si vous avez une propriété de ce type dans votre composant l'Inspecteur d'Objet affichera une liste déroulante avec la liste des composants qui correspondent aux critères (tous les éléments descendants de twincontrol a).



Notre composant peut faire quelque chose comme







& ! & ! & ! & nbsp



procédure TSimpleExample.DoSomething

démarrer

& nbsp & nbsp si (Attribué(FocusControl)) et

& ! & ! & ! & ! & nbsp (FocusControl.Activé)

& ! & ! & ! & nbsp FocusControl.Setfocus

fin

& ! & ! & ! & nbsp




nous avons d'Abord vérifier si la propriété a été attribué, si donc nous avons mis l'accent, mais il existe des cas où la propriété n'est pas Nul, mais le composant, il est n'est plus valide. Cela arrive souvent lorsque les références des propriétés d'un composant qui a été détruit.



Heureusement, Delphi nous fournit une solution. Chaque fois qu'un composant est détruit, il en informe son propriétaire (notre formulaire) qu'il est en train d'être détruit. À ce stade, tous les composants appartenant à la même forme est informé de cet événement. Pour piéger cet événement, nous devons remplacer une méthode standard de TComponent appelée 'Notification'.







& ! & ! & ! & nbsp



type

& nbsp & nbsp TSimpleExample = class(TComponent)

& nbsp & nbsp privé

& ! & ! & ! & nbsp FFocusControl: twincontrol a

& nbsp & nbsp protected

& ! & ! & ! & nbsp procédure Notification(AComponent: TComponent

& ! & ! & ! & ! & ! & nbsp Opération: TOperation) remplacer

& ! & ! & ! & nbsp procédure SetFocusControl(const Valeur: twincontrol a) virtual

& nbsp & nbsp public

& nbsp & nbsp publié

& ! & ! & ! & nbsp propriétés FocusControl: Twincontrol a lire FFocusControl écrire SetFocusControl

& nbsp & nbsp fin



procédure TSimpleExample.SetFocusControl(const Valeur: twincontrol a)

démarrer

& nbsp & nbsp FFocusControl := Valeur

fin



procédure TSimpleExample.Notification(AComponent :TComponent

& nbsp & nbsp Opération : TOperation)

démarrer

& nbsp & nbsp hérité //ne pas oublier d'appeler ce

& nbsp & nbsp si (Operation = opRemove) et

& ! & ! & ! & ! & nbsp (AComponent = FocusControl)

& ! & ! & ! & nbsp FFocusControl := nul

fin

& ! & ! & ! & ! & ! & nbsp




Maintenant, quand notre composant référencé est détruite, nous sommes informés, à quel point nous pouvons mettre notre référence à Néant. Notez, cependant, que j'ai dit 'tous les composants appartenant à la même forme est informé de cet événement trop'



Ceci nous introduit à un autre problème. Nous sommes seulement informé que le composant est en train d'être détruite si elle est détenue par le même formulaire. Il est possible d'avoir la propriété du point de composants sur d'autres formes (ou même sans maître à tous), et lorsque ces composants sont détruites, nous ne sommes pas informés. Encore une fois il y a une solution.



TComponent introduit une méthode appelée 'FreeNotification'. Le but de FreeNotification est-à-dire le composant (FocusControl) pour nous maintenir dans l'esprit quand il est détruit.



Une mise en œuvre devrait ressembler à ceci







& ! & ! & ! & nbsp



type

& nbsp & nbsp TSimpleExample = class(TComponent)

& nbsp & nbsp privé

& ! & ! & ! & nbsp FFocusControl: twincontrol a

& nbsp & nbsp protected

& ! & ! & ! & nbsp procédure Notification(AComponent: TComponent

& ! & ! & ! & ! & ! & nbsp Opération: TOperation) remplacer

& ! & ! & ! & nbsp procédure SetFocusControl(const Valeur: twincontrol a) virtual

& nbsp & nbsp public

& nbsp & nbsp publié

& ! & ! & ! & nbsp propriétés FocusControl: Twincontrol a lire FFocusControl écrire SetFocusControl

& nbsp & nbsp fin



procédure TSimpleExample.SetFocusControl(const Valeur: twincontrol a)

démarrer

& nbsp & nbsp si Valeur <> FFocusControl

& nbsp & nbsp démarrer

& ! & ! & ! & nbsp si Assigné(FFocusControl)

& ! & ! & ! & ! & ! & nbsp FFocusControl.RemoveFreeNotification(Auto)



& ! & ! & ! & nbsp FFocusControl := Valeur



& ! & ! & ! & nbsp si Assigné(FFocusControl)

& ! & ! & ! & ! & ! & nbsp FFocusControl.FreeNotification(Auto)

& nbsp & nbsp fin

fin



procédure TSimpleExample.Notification(AComponent: TComponent

& nbsp & nbsp Opération : TOperation)

démarrer

& nbsp & nbsp si (Operation = opRemove) et

& ! & ! & ! & ! & nbsp (AComponent = FocusControl)

& ! & ! & ! & nbsp FFocusControl := nul

fin

& ! & ! & ! & nbsp




Lors de la configuration de notre FocusControl de la propriété, on vérifie d'abord si elle est déjà définie sur un composant. S'il est déjà défini, nous devons dire à l'origine de la composante que nous n'avons plus besoin de savoir quand il est détruit. Une fois notre propriété a été définie sur la nouvelle valeur de nous informer de la nouvelle composante que nous avons besoin d'une notification lorsqu'il est libéré. Le reste de notre code reste le même que le composant référencé appelle encore notre méthode de Notification.



Règle

Cette section est vraiment très simple et ne prendra pas longtemps pour couvrir. Je ne doute pas que vous êtes déjà familier avec la création de votre propre ordinale types.







& ! & ! & ! & nbsp



type

& nbsp & nbsp TComponentOption = (coDrawLines,

& ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & nbsp coDrawSolid,

& ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & nbsp coDrawBackground)

& ! & ! & ! & nbsp




les Propriétés de ce type pour afficher une liste déroulante avec la liste de toutes les valeurs possibles, mais parfois vous aurez besoin de définir une combinaison de plusieurs (ou toutes) de ces valeurs. C'est là que les ensembles de venir pour jouer







& ! & ! & ! & nbsp



Type

& nbsp & nbsp TComponentOption = (coDrawLines,

& ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & nbsp coDrawSolid,

& ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & nbsp coDrawBackground)

& nbsp & nbsp TComponentOptions = set TComponentOption

& ! & ! & ! & nbsp




la Publication d'une propriété de type TComponentOptions seraient le résultat d'un [ ] apparaissant à côté de notre nom de la propriété. Lorsque vous cliquez sur pour développer le bien, vous verrez une liste d'options. Pour chaque élément dans TComponentOption vous verrez une propriété Booléenne, vous pouvez inclure / exclure les éléments de votre ensemble en fixant sa valeur à True / False.



Il est simple de vérifier / modifier les éléments dans un ensemble à partir de l'intérieur de notre composant.







& ! & ! & ! & nbsp



si coDrawLines de OurComponentOptions

& nbsp & nbsp DrawTheLines

& ! & ! & ! & nbsp




ou







& ! & ! & ! & nbsp



procédure TSomeComponent.SetOurComponentOptions(const Valeur: TComponentOptions)

démarrer

& nbsp & nbsp si (coDrawSolid en Valeur) et

& nbsp & nbsp (coDrawBackground en valeur)

& ! & ! & ! & nbsp {soulever une exception}



& nbsp & nbsp FOurComponentOptions := Valeur

& nbsp & nbsp Invalider

fin

& ! & ! & ! & nbsp




les propriétés Binaires

Il est parfois nécessaire d'écrire vos propres streaming routines de lecture et d'écriture personnalisés types de propriété (c'est de Cette façon Delphi lectures / écritures les propriétés Top et Left pour les non visible composants sans la publication de ces propriétés dans l'inspecteur d'objet).



Par exemple, j'ai écrit un composant de la forme d'un formulaire basé sur une image bitmap. Mon code au moment de convertir une image bitmap dans une fenêtre-région est extrêmement lent et ne serait pas peut-être de toute utilisation au moment de l'exécution. Ma solution a été de convertir les données au moment de la conception, et le flux de données binaires résultant de la conversion. Pour créer les propriétés binaires est un processus en trois étapes.



1. Écrire une méthode pour écrire les données.

2. Écrire une méthode pour lire les données.

3. Dites à Delphes que nous avons une propriété binaire, et passer notre lecture / écriture des méthodes.







& ! & ! & ! & nbsp



type

& nbsp & nbsp TBinaryComponent = class(TComponent)

& nbsp & nbsp privé

& ! & ! & ! & nbsp FBinaryData : Pointeur

& ! & ! & ! & nbsp FBinaryDataSize : DWord

& ! & ! & ! & nbsp procédure WriteData(S : TStream)

& ! & ! & ! & nbsp procédure ReadData(S : TStream)

& nbsp & nbsp protected

& ! & ! & ! & nbsp procédure DefineProperties(Déclarant : TFiler) remplacer

& nbsp & nbsp public

& ! & ! & ! & nbsp constructeur Create(AOwner : TComponent) remplacer

& nbsp & nbsp fin

& ! & ! & ! & nbsp




DefineProperties est appelé par Delphi lorsqu'il a besoin de flux de notre composant. Tout ce que nous devons faire est de remplacer cette méthode, et d'ajouter une propriété en utilisant soit TFiler.DefineProperty ou TFiler.DefineBinaryProperty.







& ! & ! & ! & nbsp



procédure TFiler.DefineBinaryProperty(const Nom: string

& nbsp & nbsp ReadData, WriteData: TStreamProc HasData: Boolean)



constructeur TBinaryComponent.Create(AOwner: TComponent)

démarrer

& nbsp & nbsp hérité

& nbsp & nbsp FBinaryDataSize := 0

fin



procédure TBinaryComponent.DefineProperties(Déclarant: TFiler)

var

& nbsp & nbsp HasData : Boolean

démarrer

& nbsp & nbsp hérité

& nbsp & nbsp HasData := FBinaryDataSize <> 0

& nbsp & nbsp Filer.DefineBinaryProperty('BinaryData',ReadData,

& ! & ! & ! & nbsp WriteData, HasData )

fin



procédure TBinaryComponent.ReadData(S: TStream)

démarrer

& nbsp & nbsp S. Lire(FBinaryDataSize, SizeOf(DWord))

& nbsp & nbsp si FBinaryDataSize > 0 démarrer

& ! & ! & ! & nbsp GetMem(FBinaryData, FBinaryDataSize)

& ! & ! & ! & nbsp S. Lire(FBinaryData^, FBinaryDataSize)

& nbsp & nbsp fin

fin



procédure TBinaryComponent.WriteData(S: TStream)

démarrer

& nbsp & nbsp //Ce ne sera pas appelé si FBinaryDataSize = 0



& nbsp & nbsp S. Write(FBinaryDataSize, Sizeof(DWord))

& nbsp & nbsp S. Write(FBinaryData^, FBinaryDataSize)

fin

& ! & ! & ! & nbsp




tout d'Abord, nous remplacer DefineProperties. Une fois que nous aurons fait cela, nous définissons une propriété binaire avec les valeurs -



& nbsp & nbsp -BinaryData : L'invisible nom de la propriété à être utilisé.

& nbsp & nbsp -ReadData : La procédure responsables de la lecture des données.

& nbsp & nbsp -WriteData : La procédure responsable de l'écriture des données.

& nbsp & nbsp -HasData : Si c'est faux, la WriteData procédure n'est même pas appelé.



la Persistance

Une rapide explication de la persistance est dans l'ordre que nous appellerons dans les sections suivantes. La persistance est ce qui le rend possible pour Delphi pour lire et écrire les propriétés de l'ensemble de ses composants. TComponent dérive d'une classe appelée TPersistent. TPersistent est tout simplement un Delphi classe capable d'avoir ses propriétés lu et écrit en Delphi, ce qui signifie que tous les descendants de TPersistent aussi ont cette même capacité.



Collections

Comme nous progressons dans cet article, nous couvrons les propriétés du composant de plus de complexité. Les Collections sont l'un des plus complexes 'standard' Delphi types de propriété. Si vous déposez un TDBGrid sur un formulaire et de regarder ses propriétés dans l'Inspecteur d'Objet, vous verrez une propriété nommée 'Colonnes'.



Colonnes est une collection de propriété, lorsque vous cliquez sur le [..] bouton, vous verrez une petite fenêtre pop-up. Cette fenêtre est le standard de la propriété de l'éditeur pour TCollection propriétés (et de descendants de TCollection).



colonnes de l



Chaque fois que vous cliquez sur le bouton 'Nouveau' vous voyez un nouvel élément ajouté (un TColumn point), en cliquant sur cet élément, sélectionnez-la dans l'Inspecteur d'Objet, de sorte que vous pouvez modifier ses propriétés et de manifestations. Comment est-ce fait ?



Les Colonnes de la propriété descend de TCollection. TCollection est similaire à un tableau, qui contient une liste de TCollectionItem. Parce que TCollection est descendu de TPersistent il est capable de diffuser cette liste d'éléments, de la même façon, TCollectionItem est aussi descendue de TPersistent et peut également diffuser ses propriétés. Donc ce que nous avons est un tableau comme élément susceptible de streaming tous ses objets et de leurs propriétés.



La première chose à faire lors de la création de notre propre structure sur la base de TCollection / TCollectionItem est de définir notre CollectionItem.



(Voir OurCollection.pas)







& ! & ! & ! & nbsp



type

& nbsp & nbsp TOurCollectionItem = class(TCollectionItem)

& nbsp & nbsp privé

& ! & ! & ! & nbsp FSomeValue : String

& nbsp & nbsp protected

& ! & ! & ! & nbsp fonction GetDisplayName : String remplacer

& nbsp & nbsp public

& ! & ! & ! & nbsp procédure Assign(Source: TPersistent) remplacer

& nbsp & nbsp publié

& ! & ! & ! & nbsp propriétés SomeValue : String

& ! & ! & ! & ! & ! & nbsp lire FSomeValue

& ! & ! & ! & ! & ! & nbsp écrire FSomeValue

& nbsp & nbsp fin

& ! & ! & ! & nbsp




Ce que nous avons fait ici est de créer un descendant de TCollectionItem. Nous avons ajouté un jeton de propriété appelée 'SomeValue', l'emporte sur la GetDisplayName fonction (pour modifier le texte qui est affiché dans l'éditeur par défaut), et finalement remplacé la méthode d'assignation, afin de permettre TOurCollectionItem à être affecté à un autre TOurCollectionItem. Si nous omettons la dernière étape de la méthode d'assignation de notre Collection de classe ne fonctionnera pas !







& ! & ! & ! & nbsp



procédure TOurCollectionItem.Attribuer(Source: TPersistent)

démarrer

& nbsp & nbsp si Source TOurCollectionItem

& ! & ! & ! & nbsp SomeValue := TOurCollectionItem(Source).SomeValue

& nbsp & nbsp else

& ! & ! & ! & nbsp hérité //lève une exception

fin



fonction TOurCollectionItem.GetDisplayName: String

démarrer

& nbsp & nbsp Résultat := Format ('Item' %d', [Index])

fin

& ! & ! & ! & nbsp




La mise en œuvre de TOurCollection est beaucoup plus complexe, et nous oblige à faire un peu de travail.







& ! & ! & ! & nbsp



TOurCollection = class(TCollection)

& nbsp & nbsp privé

& ! & ! & ! & nbsp FOwner : TComponent

& nbsp & nbsp protected

& ! & ! & ! & nbsp fonction GetOwner : TPersistent remplacer

& ! & ! & ! & nbsp fonction GetItem(Index: Integer): TOurCollectionItem

& ! & ! & ! & nbsp procédure SetItem(Index: Integer Valeur:

& ! & ! & ! & ! & ! & nbsp TOurCollectionItem)

& ! & ! & ! & nbsp procédure la mise à Jour(Item: TOurCollectionItem)

& nbsp & nbsp public

& ! & ! & ! & nbsp constructeur Create(AOwner : TComponent)



& ! & ! & ! & nbsp fonction Ajouter : TOurCollectionItem

& ! & ! & ! & nbsp fonction Insert(Index: Integer): TOurCollectionItem



& ! & ! & ! & nbsp propriétés Items[Index: Integer]: TOurCollectionItem

& ! & ! & ! & ! & ! & nbsp lire GetItem

& ! & ! & ! & ! & ! & nbsp écrire SetItem

& nbsp & nbsp fin

& ! & ! & ! & nbsp




Il y a un certain nombre d'éléments de couverture en fonction d'une déclaration de classe, nous allons donc commencer par le haut et couvrir chacune à son tour.



GetOwner est une méthode virtuelle introduit dans TPersistent. Ce doit être substituée comme le code par défaut pour cette méthode retourne Nil. Dans notre implémentation, nous avons modifier le constructeur de recevoir un seul paramètre (AOwner : TComponent). Nous stockons ce paramètre dans FOwner, qui est ensuite transmis comme le résultat de GetOwner (TComponent descend de TPersistent, donc est donc valide type de résultat).







& ! & ! & ! & nbsp



constructeur TOurCollection.Create(AOwner: TComponent)

démarrer

& nbsp & nbsp hérité Créer(TOurCollectionItem)

& nbsp & nbsp FOwner := AOwner

fin



fonction TOurCollection.GetOwner: TPersistent

démarrer

& nbsp & nbsp Résultat := FOwner

fin

& ! & ! & ! & nbsp




Non seulement permet de Créer un magasin, le propriétaire (qui est nécessaire pour l'Inspecteur d'Objet fonctionne correctement), il indique également à Delphes, ce qui classe notre CollectionItem est en appelant 'hérité de Créer(TOurCollectionItem)'.



GetItem / SetItem sont déclarées de la même manière comme ils le sont dans TCollection, mais au lieu de travailler sur TCollectionItem de travailler sur notre nouvelle classe TOurCollectionItem. Ceux-ci sont utilisés dans notre rubrique 'Articles' bien plus tard.



mise à Jour comme ci-dessus est un simple remplacement de l'origine, de travailler sur notre nouveau CollectionItem classe à la place.



Ajouter / Insert sont tous les deux responsables de l'ajout d'éléments à la liste, ces instruments ont été remplacés afin de ramener des objets de la classe appropriée.



Enfin, une 'Éléments' de la propriété est introduit pour remplacer les Éléments d'origine de la propriété, de nouveau, de sorte que nous sommes retournés à la suite de TOurCollectionItem plutôt que TCollectionItem nous permet d'économiser de l'inutile problème de typecasting le résultat à chaque fois.



Enfin, un exemple de l'implantation de ce type de propriété dans un composant de notre propre.







& ! & ! & ! & nbsp



TCollectionComponent = class(TComponent)

& nbsp & nbsp privé

& ! & ! & ! & nbsp FOurCollection : TOurCollection

& ! & ! & ! & nbsp procédure SetOurCollection(const Valeur:

& ! & ! & ! & ! & ! & nbsp TOurCollection)

& nbsp & nbsp public

& ! & ! & ! & nbsp constructeur Create(AOwner : TComponent) remplacer

& ! & ! & ! & nbsp destructeur Détruire remplacer

& nbsp & nbsp publié

& ! & ! & ! & nbsp propriétés OurCollection : TOurCollection

& ! & ! & ! & ! & ! & nbsp lire FOurCollection

& ! & ! & ! & ! & ! & nbsp écrire SetOurCollection

& nbsp & nbsp fin

& ! & ! & ! & nbsp




C'est aussi simple que cela. Une fois notre TCollection classe est écrit que tout le travail est fait. Notre constructeur crée la classe de collection, le destructeur détruit, et SetOurCollection fait cela.







& ! & ! & ! & nbsp



constructeur TCollectionComponent.Create(AOwner: TComponent)

démarrer

& nbsp & nbsp hérité

& nbsp & nbsp FOurCollection := TOurCollection.Create(Self)

fin



destructeur TCollectionComponent.Détruire

démarrer

& nbsp & nbsp FOurCollection.Gratuit

& nbsp & nbsp hérité

fin



procédure TCollectionComponent.SetOurCollection(

& nbsp & nbsp const Valeur: TOurCollection)

démarrer

& nbsp & nbsp FOurCollection.Attribuer(Valeur)

fin

& ! & ! & ! & nbsp




Comme mentionné précédemment, l ' (Auto) passé à la TOurCollectionItem.Créer est stocké dans TOurCollection de FOwner variable, qui est passé comme le résultat de GetOwner. Un point à noter ici est que, dans SetOurCollection nous ne FOurCollection := valeur de remplacement de l'objet (les objets sont simplement des pointeurs), nous attribuons notre propriété à la valeur.



plus Tard, des versions de Delphi rendre cela encore plus simple. Plutôt que d'avoir à remplacer GetOwner dans notre Collection de classe, nous pouvons maintenant tirer notre Collection de TOwnedCollection à la place. TOwnedCollection est un wrapper pour TCollection avec ce travail fait pour nous.



les Sous-propriétés

plus Tôt dans cet article, nous avons vu comment il était possible de créer une propriété extensible. La limitation de la technique antérieure, à savoir que chaque sous-élément est apparu comme une propriété Booléenne. Cette section suivante montre comment créer extensible propriétés qui peuvent contenir n'importe quel type de propriété.



Si un composant requiert une propriété qui est un type d'enregistrement, ce qui pourrait très facilement être mis en œuvre par l'exposition de chacune des propriétés séparément. Cependant, si les besoins en composants de présenter deux ou plusieurs propriétés du même type complexe de notre Inspecteur d'Objet, la vue devient tout à coup très compliqué.



La réponse est de créer une structure complexe (comme pour un enregistrement ou d'un objet) et de publier cette structure comme une propriété chaque fois que nécessaire. Le problème évident est que Delphi ne sais pas comment faire pour afficher cette propriété, sauf si nous le dire. La création d'un entièrement soufflé à la propriété de l'éditeur (avec les dialogues etc) serait exagéré, donc, heureusement, Delphi a fourni une solution. Comme mentionné précédemment, Delphi interne de streaming est basé autour de la TPersistent classe. La première étape est donc de dériver notre structure complexe de cette classe.







& ! & ! & ! & nbsp
type

& nbsp & nbsp TExpandingRecord = class(TPersistent)

& nbsp & nbsp privé

& ! & ! & ! & nbsp FIntegerProp : Integer

& ! & ! & ! & nbsp FStringProp : String

& ! & ! & ! & nbsp FCollectionProp : TOurCollection

& ! & ! & ! & nbsp procédure SetCollectionProp(const Valeur:

& ! & ! & ! & ! & ! & nbsp TOurCollection)

& nbsp & nbsp public

& ! & ! & ! & nbsp constructeur Create(AOwner : TComponent)

& ! & ! & ! & nbsp destructeur Détruire remplacer



& ! & ! & ! & nbsp procédure Assign(Source : TPersistent) remplacer

& nbsp & nbsp publié

& ! & ! & ! & nbsp propriétés IntegerProp : Entier

& ! & ! & ! & ! & ! & nbsp lire FIntegerProp

& ! & ! & ! & ! & ! & nbsp écrire FIntegerProp

& ! & ! & ! & nbsp propriétés StringProp : String

& ! & ! & ! & ! & ! & nbsp lire FStringProp

& ! & ! & ! & ! & ! & nbsp écrire FStringProp

& nbsp & nbsp __






La composante ecriture, partie 2


La composante ecriture, partie 2 : Plusieurs milliers de conseils pour vous faciliter la vie.


Cet article portera sur la maniere d'ecrire les proprietes avancees, comment ecrire personnalise en streaming pour les proprietes, et les sous-proprietes.




Cet article est paru initialement dans les Developpeur Delphi



le droit d'Auteur Pinnacle Publishing, Inc. Tous droits reserves.







Cet article fait partie de deux des trois parties de l'article sur les composants. La premiere partie couvert la base de la creation de composants, partie deux abordera la façon d'ecrire les proprietes avancees, comment ecrire personnalise en streaming pour les proprietes, et les sous-proprietes. La derniere partie couvrira propriete / editeurs de composants, comment ecrire dedie editeurs pour votre composant de la propriete, et comment ecrire 'cache' des composants.



Tres souvent, il est necessaire d'ecrire des composants qui executent des fonctions plus avancees. Ces composants doivent souvent faire reference a d'autres composants, sont la propriete personnalisee formats de donnees, ou d'avoir une propriete qui possede une liste de valeurs plutot qu'une valeur unique. Dans cette partie, nous allons explorer les differents exemples couvrant ces sujets, en commençant par le plus simple.



references Composant

Certains composants besoin de faire reference a d'autres composants. TLabel, par exemple, a un 'FocusControl de la propriete'. Lorsque vous incluez une esperluette dans la 'Legende' il souligne la lettre suivante ( & Bonjour devient Bonjour), en appuyant sur la touche de raccourci ALT-H sur votre clavier va declencher un evenement dans votre etiquette. Si le 'FocusControl' a ete etabli, l'accent sera transmis au controle specifie.



Pour avoir une telle propriete dans votre propre composant est assez simple. Tout ce que vous faire est de declarer une nouvelle propriete, et de definir le type de propriete a la plus basse classe de base qu'il peut accepter (twincontrol a permettra a tout descendant de twincontrol a a etre utilise), mais, il y a des consequences.







& ! & ! & ! & nbsp



type

& nbsp & nbsp TSimpleExample = class(TComponent)

& nbsp & nbsp prive

& ! & ! & ! & nbsp FFocusControl: twincontrol a

& nbsp & nbsp protected

& ! & ! & ! & nbsp procedure SetFocusControl(const Valeur: twincontrol a) virtual

& nbsp & nbsp public

& nbsp & nbsp publie

& ! & ! & ! & nbsp proprietes FocusControl: Twincontrol a lire FFocusControl ecrire SetFocusControl

& nbsp & nbsp fin



procedure TSimpleExample.SetFocusControl(const Valeur: twincontrol a)

demarrer

& nbsp & nbsp FFocusControl := Valeur

fin

& ! & ! & ! & nbsp




Prendre l'exemple ci-dessus. C'est tout a fait un exemple simple (d'ou le nom du composant) de comment ecrire un composant qui fait reference a un autre composant. Si vous avez une propriete de ce type dans votre composant l'Inspecteur d'Objet affichera une liste deroulante avec la liste des composants qui correspondent aux criteres (tous les elements descendants de twincontrol a).



Notre composant peut faire quelque chose comme







& ! & ! & ! & nbsp



procedure TSimpleExample.DoSomething

demarrer

& nbsp & nbsp si (Attribue(FocusControl)) et

& ! & ! & ! & ! & nbsp (FocusControl.Active)

& ! & ! & ! & nbsp FocusControl.Setfocus

fin

& ! & ! & ! & nbsp




nous avons d'Abord verifier si la propriete a ete attribue, si donc nous avons mis l'accent, mais il existe des cas ou la propriete n'est pas Nul, mais le composant, il est n'est plus valide. Cela arrive souvent lorsque les references des proprietes d'un composant qui a ete detruit.



Heureusement, Delphi nous fournit une solution. Chaque fois qu'un composant est detruit, il en informe son proprietaire (notre formulaire) qu'il est en train d'etre detruit. A ce stade, tous les composants appartenant a la meme forme est informe de cet evenement. Pour pieger cet evenement, nous devons remplacer une methode standard de TComponent appelee 'Notification'.







& ! & ! & ! & nbsp



type

& nbsp & nbsp TSimpleExample = class(TComponent)

& nbsp & nbsp prive

& ! & ! & ! & nbsp FFocusControl: twincontrol a

& nbsp & nbsp protected

& ! & ! & ! & nbsp procedure Notification(AComponent: TComponent

& ! & ! & ! & ! & ! & nbsp Operation: TOperation) remplacer

& ! & ! & ! & nbsp procedure SetFocusControl(const Valeur: twincontrol a) virtual

& nbsp & nbsp public

& nbsp & nbsp publie

& ! & ! & ! & nbsp proprietes FocusControl: Twincontrol a lire FFocusControl ecrire SetFocusControl

& nbsp & nbsp fin



procedure TSimpleExample.SetFocusControl(const Valeur: twincontrol a)

demarrer

& nbsp & nbsp FFocusControl := Valeur

fin



procedure TSimpleExample.Notification(AComponent :TComponent

& nbsp & nbsp Operation : TOperation)

demarrer

& nbsp & nbsp herite //ne pas oublier d'appeler ce

& nbsp & nbsp si (Operation = opRemove) et

& ! & ! & ! & ! & nbsp (AComponent = FocusControl)

& ! & ! & ! & nbsp FFocusControl := nul

fin

& ! & ! & ! & ! & ! & nbsp




Maintenant, quand notre composant reference est detruite, nous sommes informes, a quel point nous pouvons mettre notre reference a Neant. Notez, cependant, que j'ai dit 'tous les composants appartenant a la meme forme est informe de cet evenement trop'



Ceci nous introduit a un autre probleme. Nous sommes seulement informe que le composant est en train d'etre detruite si elle est detenue par le meme formulaire. Il est possible d'avoir la propriete du point de composants sur d'autres formes (ou meme sans maître a tous), et lorsque ces composants sont detruites, nous ne sommes pas informes. Encore une fois il y a une solution.



TComponent introduit une methode appelee 'FreeNotification'. Le but de FreeNotification est-a-dire le composant (FocusControl) pour nous maintenir dans l'esprit quand il est detruit.



Une mise en œuvre devrait ressembler a ceci







& ! & ! & ! & nbsp



type

& nbsp & nbsp TSimpleExample = class(TComponent)

& nbsp & nbsp prive

& ! & ! & ! & nbsp FFocusControl: twincontrol a

& nbsp & nbsp protected

& ! & ! & ! & nbsp procedure Notification(AComponent: TComponent

& ! & ! & ! & ! & ! & nbsp Operation: TOperation) remplacer

& ! & ! & ! & nbsp procedure SetFocusControl(const Valeur: twincontrol a) virtual

& nbsp & nbsp public

& nbsp & nbsp publie

& ! & ! & ! & nbsp proprietes FocusControl: Twincontrol a lire FFocusControl ecrire SetFocusControl

& nbsp & nbsp fin



procedure TSimpleExample.SetFocusControl(const Valeur: twincontrol a)

demarrer

& nbsp & nbsp si Valeur <> FFocusControl

& nbsp & nbsp demarrer

& ! & ! & ! & nbsp si Assigne(FFocusControl)

& ! & ! & ! & ! & ! & nbsp FFocusControl.RemoveFreeNotification(Auto)



& ! & ! & ! & nbsp FFocusControl := Valeur



& ! & ! & ! & nbsp si Assigne(FFocusControl)

& ! & ! & ! & ! & ! & nbsp FFocusControl.FreeNotification(Auto)

& nbsp & nbsp fin

fin



procedure TSimpleExample.Notification(AComponent: TComponent

& nbsp & nbsp Operation : TOperation)

demarrer

& nbsp & nbsp si (Operation = opRemove) et

& ! & ! & ! & ! & nbsp (AComponent = FocusControl)

& ! & ! & ! & nbsp FFocusControl := nul

fin

& ! & ! & ! & nbsp




Lors de la configuration de notre FocusControl de la propriete, on verifie d'abord si elle est deja definie sur un composant. S'il est deja defini, nous devons dire a l'origine de la composante que nous n'avons plus besoin de savoir quand il est detruit. Une fois notre propriete a ete definie sur la nouvelle valeur de nous informer de la nouvelle composante que nous avons besoin d'une notification lorsqu'il est libere. Le reste de notre code reste le meme que le composant reference appelle encore notre methode de Notification.



Regle

Cette section est vraiment tres simple et ne prendra pas longtemps pour couvrir. Je ne doute pas que vous etes deja familier avec la creation de votre propre ordinale types.







& ! & ! & ! & nbsp



type

& nbsp & nbsp TComponentOption = (coDrawLines,

& ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & nbsp coDrawSolid,

& ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & nbsp coDrawBackground)

& ! & ! & ! & nbsp




les Proprietes de ce type pour afficher une liste deroulante avec la liste de toutes les valeurs possibles, mais parfois vous aurez besoin de definir une combinaison de plusieurs (ou toutes) de ces valeurs. C'est la que les ensembles de venir pour jouer







& ! & ! & ! & nbsp



Type

& nbsp & nbsp TComponentOption = (coDrawLines,

& ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & nbsp coDrawSolid,

& ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & ! & nbsp coDrawBackground)

& nbsp & nbsp TComponentOptions = set TComponentOption

& ! & ! & ! & nbsp




la Publication d'une propriete de type TComponentOptions seraient le resultat d'un [ ] apparaissant a cote de notre nom de la propriete. Lorsque vous cliquez sur pour developper le bien, vous verrez une liste d'options. Pour chaque element dans TComponentOption vous verrez une propriete Booleenne, vous pouvez inclure / exclure les elements de votre ensemble en fixant sa valeur a True / False.



Il est simple de verifier / modifier les elements dans un ensemble a partir de l'interieur de notre composant.







& ! & ! & ! & nbsp



si coDrawLines de OurComponentOptions

& nbsp & nbsp DrawTheLines

& ! & ! & ! & nbsp




ou







& ! & ! & ! & nbsp



procedure TSomeComponent.SetOurComponentOptions(const Valeur: TComponentOptions)

demarrer

& nbsp & nbsp si (coDrawSolid en Valeur) et

& nbsp & nbsp (coDrawBackground en valeur)

& ! & ! & ! & nbsp {soulever une exception}



& nbsp & nbsp FOurComponentOptions := Valeur

& nbsp & nbsp Invalider

fin

& ! & ! & ! & nbsp




les proprietes Binaires

Il est parfois necessaire d'ecrire vos propres streaming routines de lecture et d'ecriture personnalises types de propriete (c'est de Cette façon Delphi lectures / ecritures les proprietes Top et Left pour les non visible composants sans la publication de ces proprietes dans l'inspecteur d'objet).



Par exemple, j'ai ecrit un composant de la forme d'un formulaire base sur une image bitmap. Mon code au moment de convertir une image bitmap dans une fenetre-region est extremement lent et ne serait pas peut-etre de toute utilisation au moment de l'execution. Ma solution a ete de convertir les donnees au moment de la conception, et le flux de donnees binaires resultant de la conversion. Pour creer les proprietes binaires est un processus en trois etapes.



1. Ecrire une methode pour ecrire les donnees.

2. Ecrire une methode pour lire les donnees.

3. Dites a Delphes que nous avons une propriete binaire, et passer notre lecture / ecriture des methodes.







& ! & ! & ! & nbsp



type

& nbsp & nbsp TBinaryComponent = class(TComponent)

& nbsp & nbsp prive

& ! & ! & ! & nbsp FBinaryData : Pointeur

& ! & ! & ! & nbsp FBinaryDataSize : DWord

& ! & ! & ! & nbsp procedure WriteData(S : TStream)

& ! & ! & ! & nbsp procedure ReadData(S : TStream)

& nbsp & nbsp protected

& ! & ! & ! & nbsp procedure DefineProperties(Declarant : TFiler) remplacer

& nbsp & nbsp public

& ! & ! & ! & nbsp constructeur Create(AOwner : TComponent) remplacer

& nbsp & nbsp fin

& ! & ! & ! & nbsp




DefineProperties est appele par Delphi lorsqu'il a besoin de flux de notre composant. Tout ce que nous devons faire est de remplacer cette methode, et d'ajouter une propriete en utilisant soit TFiler.DefineProperty ou TFiler.DefineBinaryProperty.







& ! & ! & ! & nbsp



procedure TFiler.DefineBinaryProperty(const Nom: string

& nbsp & nbsp ReadData, WriteData: TStreamProc HasData: Boolean)



constructeur TBinaryComponent.Create(AOwner: TComponent)

demarrer

& nbsp & nbsp herite

& nbsp & nbsp FBinaryDataSize := 0

fin



procedure TBinaryComponent.DefineProperties(Declarant: TFiler)

var

& nbsp & nbsp HasData : Boolean

demarrer

& nbsp & nbsp herite

& nbsp & nbsp HasData := FBinaryDataSize <> 0

& nbsp & nbsp Filer.DefineBinaryProperty('BinaryData',ReadData,

& ! & ! & ! & nbsp WriteData, HasData )

fin



procedure TBinaryComponent.ReadData(S: TStream)

demarrer

& nbsp & nbsp S. Lire(FBinaryDataSize, SizeOf(DWord))

& nbsp & nbsp si FBinaryDataSize > 0 demarrer

& ! & ! & ! & nbsp GetMem(FBinaryData, FBinaryDataSize)

& ! & ! & ! & nbsp S. Lire(FBinaryData^, FBinaryDataSize)

& nbsp & nbsp fin

fin



procedure TBinaryComponent.WriteData(S: TStream)

demarrer

& nbsp & nbsp //Ce ne sera pas appele si FBinaryDataSize = 0



& nbsp & nbsp S. Write(FBinaryDataSize, Sizeof(DWord))

& nbsp & nbsp S. Write(FBinaryData^, FBinaryDataSize)

fin

& ! & ! & ! & nbsp




tout d'Abord, nous remplacer DefineProperties. Une fois que nous aurons fait cela, nous definissons une propriete binaire avec les valeurs -



& nbsp & nbsp -BinaryData : L'invisible nom de la propriete a etre utilise.

& nbsp & nbsp -ReadData : La procedure responsables de la lecture des donnees.

& nbsp & nbsp -WriteData : La procedure responsable de l'ecriture des donnees.

& nbsp & nbsp -HasData : Si c'est faux, la WriteData procedure n'est meme pas appele.



la Persistance

Une rapide explication de la persistance est dans l'ordre que nous appellerons dans les sections suivantes. La persistance est ce qui le rend possible pour Delphi pour lire et ecrire les proprietes de l'ensemble de ses composants. TComponent derive d'une classe appelee TPersistent. TPersistent est tout simplement un Delphi classe capable d'avoir ses proprietes lu et ecrit en Delphi, ce qui signifie que tous les descendants de TPersistent aussi ont cette meme capacite.



Collections

Comme nous progressons dans cet article, nous couvrons les proprietes du composant de plus de complexite. Les Collections sont l'un des plus complexes 'standard' Delphi types de propriete. Si vous deposez un TDBGrid sur un formulaire et de regarder ses proprietes dans l'Inspecteur d'Objet, vous verrez une propriete nommee 'Colonnes'.



Colonnes est une collection de propriete, lorsque vous cliquez sur le [..] bouton, vous verrez une petite fenetre pop-up. Cette fenetre est le standard de la propriete de l'editeur pour TCollection proprietes (et de descendants de TCollection).



colonnes de l



Chaque fois que vous cliquez sur le bouton 'Nouveau' vous voyez un nouvel element ajoute (un TColumn point), en cliquant sur cet element, selectionnez-la dans l'Inspecteur d'Objet, de sorte que vous pouvez modifier ses proprietes et de manifestations. Comment est-ce fait ?



Les Colonnes de la propriete descend de TCollection. TCollection est similaire a un tableau, qui contient une liste de TCollectionItem. Parce que TCollection est descendu de TPersistent il est capable de diffuser cette liste d'elements, de la meme façon, TCollectionItem est aussi descendue de TPersistent et peut egalement diffuser ses proprietes. Donc ce que nous avons est un tableau comme element susceptible de streaming tous ses objets et de leurs proprietes.



La premiere chose a faire lors de la creation de notre propre structure sur la base de TCollection / TCollectionItem est de definir notre CollectionItem.



(Voir OurCollection.pas)







& ! & ! & ! & nbsp



type

& nbsp & nbsp TOurCollectionItem = class(TCollectionItem)

& nbsp & nbsp prive

& ! & ! & ! & nbsp FSomeValue : String

& nbsp & nbsp protected

& ! & ! & ! & nbsp fonction GetDisplayName : String remplacer

& nbsp & nbsp public

& ! & ! & ! & nbsp procedure Assign(Source: TPersistent) remplacer

& nbsp & nbsp publie

& ! & ! & ! & nbsp proprietes SomeValue : String

& ! & ! & ! & ! & ! & nbsp lire FSomeValue

& ! & ! & ! & ! & ! & nbsp ecrire FSomeValue

& nbsp & nbsp fin

& ! & ! & ! & nbsp




Ce que nous avons fait ici est de creer un descendant de TCollectionItem. Nous avons ajoute un jeton de propriete appelee 'SomeValue', l'emporte sur la GetDisplayName fonction (pour modifier le texte qui est affiche dans l'editeur par defaut), et finalement remplace la methode d'assignation, afin de permettre TOurCollectionItem a etre affecte a un autre TOurCollectionItem. Si nous omettons la derniere etape de la methode d'assignation de notre Collection de classe ne fonctionnera pas !







& ! & ! & ! & nbsp



procedure TOurCollectionItem.Attribuer(Source: TPersistent)

demarrer

& nbsp & nbsp si Source TOurCollectionItem

& ! & ! & ! & nbsp SomeValue := TOurCollectionItem(Source).SomeValue

& nbsp & nbsp else

& ! & ! & ! & nbsp herite //leve une exception

fin



fonction TOurCollectionItem.GetDisplayName: String

demarrer

& nbsp & nbsp Resultat := Format ('Item' %d', [Index])

fin

& ! & ! & ! & nbsp




La mise en œuvre de TOurCollection est beaucoup plus complexe, et nous oblige a faire un peu de travail.







& ! & ! & ! & nbsp



TOurCollection = class(TCollection)

& nbsp & nbsp prive

& ! & ! & ! & nbsp FOwner : TComponent

& nbsp & nbsp protected

& ! & ! & ! & nbsp fonction GetOwner : TPersistent remplacer

& ! & ! & ! & nbsp fonction GetItem(Index: Integer): TOurCollectionItem

& ! & ! & ! & nbsp procedure SetItem(Index: Integer Valeur:

& ! & ! & ! & ! & ! & nbsp TOurCollectionItem)

& ! & ! & ! & nbsp procedure la mise a Jour(Item: TOurCollectionItem)

& nbsp & nbsp public

& ! & ! & ! & nbsp constructeur Create(AOwner : TComponent)



& ! & ! & ! & nbsp fonction Ajouter : TOurCollectionItem

& ! & ! & ! & nbsp fonction Insert(Index: Integer): TOurCollectionItem



& ! & ! & ! & nbsp proprietes Items[Index: Integer]: TOurCollectionItem

& ! & ! & ! & ! & ! & nbsp lire GetItem

& ! & ! & ! & ! & ! & nbsp ecrire SetItem

& nbsp & nbsp fin

& ! & ! & ! & nbsp




Il y a un certain nombre d'elements de couverture en fonction d'une declaration de classe, nous allons donc commencer par le haut et couvrir chacune a son tour.



GetOwner est une methode virtuelle introduit dans TPersistent. Ce doit etre substituee comme le code par defaut pour cette methode retourne Nil. Dans notre implementation, nous avons modifier le constructeur de recevoir un seul parametre (AOwner : TComponent). Nous stockons ce parametre dans FOwner, qui est ensuite transmis comme le resultat de GetOwner (TComponent descend de TPersistent, donc est donc valide type de resultat).







& ! & ! & ! & nbsp



constructeur TOurCollection.Create(AOwner: TComponent)

demarrer

& nbsp & nbsp herite Creer(TOurCollectionItem)

& nbsp & nbsp FOwner := AOwner

fin



fonction TOurCollection.GetOwner: TPersistent

demarrer

& nbsp & nbsp Resultat := FOwner

fin

& ! & ! & ! & nbsp




Non seulement permet de Creer un magasin, le proprietaire (qui est necessaire pour l'Inspecteur d'Objet fonctionne correctement), il indique egalement a Delphes, ce qui classe notre CollectionItem est en appelant 'herite de Creer(TOurCollectionItem)'.



GetItem / SetItem sont declarees de la meme maniere comme ils le sont dans TCollection, mais au lieu de travailler sur TCollectionItem de travailler sur notre nouvelle classe TOurCollectionItem. Ceux-ci sont utilises dans notre rubrique 'Articles' bien plus tard.



mise a Jour comme ci-dessus est un simple remplacement de l'origine, de travailler sur notre nouveau CollectionItem classe a la place.



Ajouter / Insert sont tous les deux responsables de l'ajout d'elements a la liste, ces instruments ont ete remplaces afin de ramener des objets de la classe appropriee.



Enfin, une 'Elements' de la propriete est introduit pour remplacer les Elements d'origine de la propriete, de nouveau, de sorte que nous sommes retournes a la suite de TOurCollectionItem plutot que TCollectionItem nous permet d'economiser de l'inutile probleme de typecasting le resultat a chaque fois.



Enfin, un exemple de l'implantation de ce type de propriete dans un composant de notre propre.







& ! & ! & ! & nbsp



TCollectionComponent = class(TComponent)

& nbsp & nbsp prive

& ! & ! & ! & nbsp FOurCollection : TOurCollection

& ! & ! & ! & nbsp procedure SetOurCollection(const Valeur:

& ! & ! & ! & ! & ! & nbsp TOurCollection)

& nbsp & nbsp public

& ! & ! & ! & nbsp constructeur Create(AOwner : TComponent) remplacer

& ! & ! & ! & nbsp destructeur Detruire remplacer

& nbsp & nbsp publie

& ! & ! & ! & nbsp proprietes OurCollection : TOurCollection

& ! & ! & ! & ! & ! & nbsp lire FOurCollection

& ! & ! & ! & ! & ! & nbsp ecrire SetOurCollection

& nbsp & nbsp fin

& ! & ! & ! & nbsp




C'est aussi simple que cela. Une fois notre TCollection classe est ecrit que tout le travail est fait. Notre constructeur cree la classe de collection, le destructeur detruit, et SetOurCollection fait cela.







& ! & ! & ! & nbsp



constructeur TCollectionComponent.Create(AOwner: TComponent)

demarrer

& nbsp & nbsp herite

& nbsp & nbsp FOurCollection := TOurCollection.Create(Self)

fin



destructeur TCollectionComponent.Detruire

demarrer

& nbsp & nbsp FOurCollection.Gratuit

& nbsp & nbsp herite

fin



procedure TCollectionComponent.SetOurCollection(

& nbsp & nbsp const Valeur: TOurCollection)

demarrer

& nbsp & nbsp FOurCollection.Attribuer(Valeur)

fin

& ! & ! & ! & nbsp




Comme mentionne precedemment, l ' (Auto) passe a la TOurCollectionItem.Creer est stocke dans TOurCollection de FOwner variable, qui est passe comme le resultat de GetOwner. Un point a noter ici est que, dans SetOurCollection nous ne FOurCollection := valeur de remplacement de l'objet (les objets sont simplement des pointeurs), nous attribuons notre propriete a la valeur.



plus Tard, des versions de Delphi rendre cela encore plus simple. Plutot que d'avoir a remplacer GetOwner dans notre Collection de classe, nous pouvons maintenant tirer notre Collection de TOwnedCollection a la place. TOwnedCollection est un wrapper pour TCollection avec ce travail fait pour nous.



les Sous-proprietes

plus Tot dans cet article, nous avons vu comment il etait possible de creer une propriete extensible. La limitation de la technique anterieure, a savoir que chaque sous-element est apparu comme une propriete Booleenne. Cette section suivante montre comment creer extensible proprietes qui peuvent contenir n'importe quel type de propriete.



Si un composant requiert une propriete qui est un type d'enregistrement, ce qui pourrait tres facilement etre mis en œuvre par l'exposition de chacune des proprietes separement. Cependant, si les besoins en composants de presenter deux ou plusieurs proprietes du meme type complexe de notre Inspecteur d'Objet, la vue devient tout a coup tres complique.



La reponse est de creer une structure complexe (comme pour un enregistrement ou d'un objet) et de publier cette structure comme une propriete chaque fois que necessaire. Le probleme evident est que Delphi ne sais pas comment faire pour afficher cette propriete, sauf si nous le dire. La creation d'un entierement souffle a la propriete de l'editeur (avec les dialogues etc) serait exagere, donc, heureusement, Delphi a fourni une solution. Comme mentionne precedemment, Delphi interne de streaming est base autour de la TPersistent classe. La premiere etape est donc de deriver notre structure complexe de cette classe.







& ! & ! & ! & nbsp
type

& nbsp & nbsp TExpandingRecord = class(TPersistent)

& nbsp & nbsp prive

& ! & ! & ! & nbsp FIntegerProp : Integer

& ! & ! & ! & nbsp FStringProp : String

& ! & ! & ! & nbsp FCollectionProp : TOurCollection

& ! & ! & ! & nbsp procedure SetCollectionProp(const Valeur:

& ! & ! & ! & ! & ! & nbsp TOurCollection)

& nbsp & nbsp public

& ! & ! & ! & nbsp constructeur Create(AOwner : TComponent)

& ! & ! & ! & nbsp destructeur Detruire remplacer



& ! & ! & ! & nbsp procedure Assign(Source : TPersistent) remplacer

& nbsp & nbsp publie

& ! & ! & ! & nbsp proprietes IntegerProp : Entier

& ! & ! & ! & ! & ! & nbsp lire FIntegerProp

& ! & ! & ! & ! & ! & nbsp ecrire FIntegerProp

& ! & ! & ! & nbsp proprietes StringProp : String

& ! & ! & ! & ! & ! & nbsp lire FStringProp

& ! & ! & ! & ! & ! & nbsp ecrire FStringProp

& nbsp & nbsp __

La composante écriture, partie 2

La composante écriture, partie 2 : Plusieurs milliers de conseils pour vous faciliter la vie.
Recommander aux amis
  • gplus
  • pinterest

Messages récents

Commentaire

Laisser un commentaire

évaluation

commentfaire www.commentfaire.net PARIS 6 Place de la Madeleine FR-75 75012 Île-de-France +33.01.23.45.67.89