Component skriving, del 2

Denne artikkelen vil dekke hvordan du skriver avanserte egenskaper, hvordan å skrive tilpasset streaming for disse egenskapene, og sub-egenskaper.
Denne artikkelen opprinnelig dukket opp i Delphi DeveloperCopyright Pinnacle Publishing, Inc. Alle rettigheter reservert.
Denne artikkelen er del to av en tre del artikkelen på komponenter. Del én dekket grunnleggende oppretting av komponenter, vil del to dekke hvordan å skrive avanserte egenskaper, hvordan å skrive tilpasset streaming for disse egenskapene, og sub-egenskaper. Den siste delen vil dekke eiendom /komponent redaktører, hvordan å skrive egne redaktører for komponenten /eiendom, og hvordan du skal skrive "skjulte" komponenter.
Ganske ofte er det nødvendig å skrive komponenter som utfører mer avanserte funksjoner. Disse komponentene må ofte enten referansen andre komponenter, har tilpasset eiendom dataformater, eller har en eiendom som eier en liste med verdier i stedet for en enkelt verdi. I denne delen vil vi utforske ulike eksempler som dekker nettopp disse fagene, som starter med flest simple.Component referencesSome komponenter må referere til andre komponenter. TLabel for eksempel har en "FocusControl" eiendom. Når du tar med en tegnet i "Caption" eiendom det understreker neste bokstav (& Hei blir Hallo), trykke på hurtigtasten ALT-H på tastaturet vil utløse en hendelse i etiketten. Hvis "FocusControl" eiendom har vært satt fokus vil bli sendt til kontroll specified.To ha en slik eiendom i din egen komponent er ganske enkel. Alt du gjør er å erklære en ny eiendom, og sette egenskapstypen til den laveste base klassen at det kan akseptere (TWinControl vil tillate noen etterkommer av TWinControl skal brukes), men det er implikasjoner. skriv
TSimpleExample = class product: (TComponent) privat
FFocusControl: TWinControl; beskyttet
prosedyre
SetFocusControl ( konst
Verdi: TWinControl); virtuell
; offentlig
publisert
eiendom
FocusControl: TWinControl lese FFocusControl skrive SetFocusControl; end
; prosedyre
TSimpleExample.SetFocusControl ( konst
Verdi: TWinControl); begynne
FFocusControl: = Verdi; end
; Ta eksempelet ovenfor. Dette er ganske enkelt eksempel (derav komponent navnet) på hvordan du skriver en komponent som henviser til en annen komponent. Hvis du har en slik eiendom i komponenten Object Inspector vil vise en kombinasjonsboks med en liste over komponenter som oppfyller kriteriene (alle komponentene stammer fra TWinControl) .Våre komponent kan gjøre noe sånt prosedyre
TSimpleExample.DoSomething; begynne
hvis plakater (Assigned (FocusControl)) og plakater (FocusControl.Enabled)
FocusControl.Setfocus; end
; Først sjekker vi om eiendommen har blitt tildelt, hvis så vi setter fokus på det, men det finnes situasjoner når eiendommen er ikke Nil ennå komponenten den peker til er ikke lenger gyldig. Dette skjer ofte når en eiendom refererer til en komponent som har vært destroyed.Luckily Delphi gir oss en løsning. Når en komponent er ødelagt den varsler sin eier (vår form) at det blir ødelagt. På dette punktet hver komponent som eies av den samme formen er varslet om dette arrangementet også. For å felle denne hendelsen må vi overstyre en standard metode for TComponent kalt "Meldinger". skriv
TSimpleExample = class product: (TComponent) privat
FFocusControl: TWinControl; beskyttet
prosedyre
Notification (AComponent: TComponent; Operation: TOperation); styre
; prosedyre
SetFocusControl ( konst
Verdi: TWinControl); virtuell
; offentlig
publisert
eiendom
FocusControl: TWinControl lese FFocusControl skrive SetFocusControl; end
; prosedyre
TSimpleExample.SetFocusControl ( konst
Verdi: TWinControl); begynne
FFocusControl: = Verdi; end
; prosedyre
TSimpleExample.Notification (AComponent: TComponent; Operation: TOperation); begynne
arvet;
//glem aldri å kalle dette
< B> hvis plakater (Operation = opRemove) og plakater (AComponent = FocusControl)
FFocusControl: = nil
; end
; Nå når vår refererte komponenten er ødelagt vi blir varslet, og da kan vi sette vår referanse til Nil. Vær imidlertid oppmerksom på at jeg sa "hver komponent som eies av den samme formen er varslet om dette arrangementet også"
Dette introduserer oss med et annet problem. Vi er bare varslet at komponenten blir ødelagt hvis det er eid av samme form. Det er mulig å ha vår eiendom punkt til komponenter på andre former (eller selv uten en eier i det hele tatt), og når disse komponentene er ødelagt vi ikke blir varslet. Nok en gang er det en solution.TComponent introduserer en metode som kalles "FreeNotification". Formålet med FreeNotification er å fortelle komponenten (FocusControl) for å holde oss i tankene når det er destroyed.An gjennomføringen ville se slik ut skriv
TSimpleExample = class product: (TComponent) privat
FFocusControl: TWinControl; beskyttet
prosedyre
Notification (AComponent: TComponent; Operation: TOperation); styre
; prosedyre
SetFocusControl ( konst
Verdi: TWinControl); virtuell
; offentlig
publisert
eiendom
FocusControl: TWinControl lese FFocusControl skrive SetFocusControl; end
; prosedyre
TSimpleExample.SetFocusControl ( konst
Verdi: TWinControl); begynne
hvis
Value < > FFocusControl da
begynne
hvis
Assigned (FFocusControl)
FFocusControl.RemoveFreeNotification (Selv); FFocusControl: = verdi; hvis
Assigned (FFocusControl)
FFocusControl.FreeNotification (Selv); end; end
; prosedyre
TSimpleExample.Notification (AComponent: TComponent; Operation: TOperation); begynne
hvis plakater (Operation = opRemove) < B> og plakater (AComponent = FocusControl)
FFocusControl: = nil
; end
; Når du setter vår FocusControl eiendom vi først sjekke om det allerede er satt til en komponent. Hvis det allerede er satt må vi fortelle den opprinnelige komponenten som vi ikke lenger trenger å vite når det er ødelagt. Når vår eiendom er satt til den nye verdien vi informere den nye komponenten som vi trenger et varsel når det er frigjort. Resten av koden vår er den samme som den refererte komponent fortsatt kaller vår Varslings method.SetsThis delen er egentlig ganske enkel, og vil ikke ta lang tid å dekke. Jeg tviler ikke på at du allerede er kjent med å lage egne ordens typer. skriv
TComponentOption = (coDrawLines, coDrawSolid, coDrawBackground); Egenskaper av denne typen vil vise en kombinasjonsboks med en liste over alle mulige verdier, men noen ganger må du angi en kombinasjon av mange (eller alle) av disse verdiene. Dette var sett kommer i å spille skriv
TComponentOption = (coDrawLines, coDrawSolid, coDrawBackground); TComponentOptions = set of
TComponentOption; Publisering en egenskap av typen TComponentOptions ville resultere i en [+] vises ved siden av vår eiendom navn. Når du klikker for å utvide eiendommen vil du se en liste over alternativer. For hvert element i TComponentOption vil du se en boolsk egenskap, kan du inkludere /ekskludere elementer fra settet ved å sette verdien til True /False.It er enkelt å sjekke /endre elementer i et sett innenfra vår komponent som så. hvis
coDrawLines i
OurComponentOptions deretter
DrawTheLines; eller prosedyre
TSomeComponent.SetOurComponentOptions ( konst
Verdi: TComponentOptions); begynne
hvis plakater (coDrawSolid i verdi) og Selge (coDrawBackground i verdi) så product: {heve et unntak} FOurComponentOptions: = verdi; Ugyldig; end
; Binære propertiesSometimes er det nødvendig å skrive dine egne streaming rutiner for å lese og skrive tilpassede typer eiendom (Dette er hvordan Delphi leser /skriver øvre og venstre egenskaper for ikke synlige komponenter uten egentlig å publisere disse egenskapene i objekt inspektør) .For eksempel, jeg skrev en gang en komponent til å forme et skjema basert på et punktgrafikkbilde. Koden min på den tiden til å konvertere punktgrafikk til et vindu-regionen var ekstremt treg og ikke ville muligens være til nytte under kjøring. Min løsning var å konvertere data på design tid, og streame den binære data som resulterte fra konverteringen. For å lage binære egenskaper er en tretrinns process.1. Skriv en metode for å skrive data.2. Skriv en metode for å lese data.3. Fortell Delphi at vi har en binær egenskap, og passerer våre lese- /skrivemetoder. skriv
TBinaryComponent = class product: (TComponent) privat
FBinaryData: Pointer; FBinaryDataSize: DWORD; prosedyre
WriteData (S: TStream); prosedyre
ReadData (S: TStream); beskyttet
prosedyre
DefineProperties (Filer: TFiler); styre
; offentlig
konstruktør
Lag (AOwner: TComponent); styre
; end
; DefineProperties kalles av Delphi når det er behov for å streame vår komponent. Alt vi trenger å gjøre er å overstyre denne metoden, og legge en eiendom ved hjelp av enten TFiler.DefineProperty eller TFiler.DefineBinaryProperty. prosedyre
TFiler.DefineBinaryProperty ( konst
Navn: string
; ReadData, WriteData: TStreamProc; HasData: Boolean); konstruktør
TBinaryComponent.Create ( AOwner: TComponent); begynne
arvet
; FBinaryDataSize: = 0; end
; prosedyre
TBinaryComponent.DefineProperties (Filer: TFiler); Var
HasData: Boolean; begynne
arvet
; HasData: = FBinaryDataSize < > 0; Filer.DefineBinaryProperty ( 'BinaryData', ReadData, WriteData, HasData); end
; prosedyre
TBinaryComponent.ReadData (S: TStream); begynne
S.Read ( FBinaryDataSize, sizeof (DWORD)); hvis
FBinaryDataSize > 0
begynne
GetMem (FBinaryData, FBinaryDataSize); S.Read (FBinaryData ^, FBinaryDataSize); end
; end
; prosedyre
TBinaryComponent.WriteData (S: TStream); begynne
//Dette vil ikke bli kalt hvis FBinaryDataSize = 0
S.Write (FBinaryDataSize, sizeof (DWORD)); S.Write (FBinaryData ^, FBinaryDataSize); end
; For det første overstyre vi DefineProperties. Når vi har gjort dette vi definere en binær egenskap med verdier - -BinaryData: Den usynlige Eiendommen navn som skal brukes. -ReadData: Fremgangsmåten er ansvarlig for å lese dataene. -WriteData: Prosedyren ansvarlig for å skrive dataene. -HasData: Hvis dette er falsk, er WriteData prosedyren ikke engang called.PersistencyA rask forklaring av utholdenhet er i orden som vi skal vise til den i de neste avsnittene. Utholdenhet er det som gjør det mulig for Delphi å lese og skrive egenskapene til alle komponentene. TComponent stammer fra en klasse kalt TPersistent. TPersistent er rett og slett en Delphi klasse i stand til å ha sine egenskaper lest og skrevet av Delphi, noe som betyr at eventuelle etterkommere av TPersistent har også denne samme capability.CollectionsAs vi fremgang gjennom denne artikkelen vil vi dekke komponentegenskapene til mer kompleksitet. Samlinger er en av de mest komplekse "standard" Delphi typer eiendom. Hvis du slipper en TDBGrid på et skjema og se på dens egenskaper i Object Inspector, vil du se en eiendom som heter "Kolonner" .Columns er en samling eiendom, når du klikker på [..] -knappen vil du se et lite vindu dukke opp. Dette vinduet er standard eiendom redaktør for TCollection egenskaper (og etterkommere av TCollection) .Når du klikker på "Ny" knappen du ser et nytt element lagt til (en TColumn element), klikke på den aktuelle gjenstanden vil velge den inn i Object Inspector slik at du kan endre sine eiendommer /hendelser. Hvordan er dette gjort? Kolonner eiendommen stammer fra TCollection. TCollection ligner på en matrise, som inneholder en liste over TCollectionItem s. Fordi TCollection stammer fra TPersistent er det i stand til å streame denne listen over elementer, på samme måte, er TCollectionItem også nedstammet fra TPersistent og kan også streame sine egenskaper. Så det vi har er en matrise-lignende element i stand til streaming alle sine elementer og deres properties.The første du må gjøre når du oppretter vår egen struktur basert på TCollection /TCollectionItem er å definere vår CollectionItem. (Se OurCollection.pas )
skriv
TOurCollectionItem = class product: (TCollectionItem) privat
FSomeValue: String
; beskyttet
funksjon
GetDisplayName: String
; styre
; offentlig
prosedyre
tildele (