Gi dine kunder Kontroll av GUI

Denne artikkelen viser hvordan brukere kan endre sin GUI under kjøring. Delphi Developer februar 1999
Copyright Pinnacle Publishing, Inc. Alle rettigheter reserved.Give kundene Kontroll av GUI Steve Zimmelman
Hvor mange ganger har du levert det du trodde var en utfylt søknadsskjema, bare for å høre din klienten sier, "Jøss, dette er hyggelig, men jeg vil veldig gjerne navnet til venstre, og feltet Status bør være rød, ikke svart, og..." Ville det ikke vært fint hvis alle brukerne måtte gjøre var å høyreklikke på musen over kontrollen, og opp kommer en popup-meny som tillater dem å endre kontroll attributter? Eller hvis de trykker Ctrl-ArrowKey eller Shift-ArrowKey å endre posisjon eller størrelsen på kontrollen? Å gi brukerne kontroll over GUI er en to-trinns prosess. Først må du opprette kontroller med egenskaper brukere kan endre under kjøring, og da må du ha en måte å lagre og gjenopprette endringene. Vanligvis kontrollen som får mest bruk er DBEdit. Så dette eksempelet vil fokusere på å skape en DBEdit som bruker en tilpasset PopupMenu som er aktivert på høyre museklikk. Menyen vil tillate brukeren å endre farge, font, Tab Order, og tekst sak. I tillegg vil tastekombinasjonen Ctrl-Pil og Shift-Arrow endre plasseringen og størrelsen på kontrollen, respectively.Before jeg begynne, jeg ønsker å introdusere deg til en ny tekst-case eiendom: ProperCase. De fleste skikkelig-case konverter vanligvis kapitalisere bare den første bokstaven, deretter en bokstav som følger en plass. Men dette etterlater en rekke navn og forkortede titler ser litt vanskelig, som McDonald, O'Hara, M.D., og så videre. Så i mitt forsøk på å skape en bedre musefelle, inkludert jeg en skikkelig-case konvertering som har intelligens til å håndtere disse spesielle navn. Jeg har lagt inn funksjoner som brukes for riktig-saken konvertering i en enhet kalt StrFunc.pas og da inkludert enheten StrFunc i bruk uttalelse av komponenten. Opprette skiftende DBEdit
Det første jeg gjorde var å lage en ny komponent med TDBEdit som den overordnede klassen. Jeg ringte den nye klassen TPSIDBEdit fordi navnet på firmaet jeg jobber for er PSI, og det var en enkel måte å skille komponenten. Neste jeg opprettet en ny CharCase type som inneholder ProperCase. Den vil bli brukt til å overstyre DBEdit sin TCharCase. Jeg har også endret CharCase annonsen til en ny type, TPSICharCase. I tillegg til å overstyre CharCase eiendom, jeg introdusert to nye egenskaper: AllowUserChange og PopupChangeMenu. Eiendommen AllowUserChange er en enkel boolsk bryter som legger inn eller ut brukerens mulighet til å endre noe av komponent eiendommer under kjøring, og PopupChangeMenu er en peker til PopupMenu som er i kraft når AllowUserChange er satt til Sann. En bulk av komponentens endring som faktisk blir gjort av PopupChangeMenu, men jeg vil diskutere det litt senere. Oppføring en presenterer den PSIDBEdit unit.Listing 1. PSIDBEdit unit.unit PSIDBEdit; interfaceuses Windows, SysUtils, klasser, Kontroller, Skjemaer, Dialoger, DBCtrls, Menyer, db, StrFunc, skriver TPSICharCase = (ecNormal, ecUpperCase, ecLowerCase, ecProperCase); TPSIDBEdit = klasse (TDBEdit) private fCharCase: TPSICharCase; fIsChanging: Boolean; fAllowUserChange: Boolean; fStartMove: Boolean; ftop: Integer; fLeft: Integer; fChangeMenu: TpopupMenu; fPopupSave: TPopupMenu; Prosedyre SetAllowUserChange (verdi: Boolean); Prosedyre SetChangeMenu (Verdi: TpopupMenu); Prosedyre SetPopUpMenu; Prosedyre SetCharCase (Verdi: TPSICharCase); Prosedyre SetTextCase (Const bCheckState: Boolean); beskyttet offentlig Prosedyre Lastet; Styre; Prosedyre Change; Styre; Prosedyren KeyDown (var Key: Word, Shift: TShiftState); styre; Prosedyre mousedown (Button: TMouseButton; Shift: TShiftState, X, Y: Integer); Styre; Prosedyren mousemove (Shift: TShiftState, X, Y: Integer); Styre; Prosedyren mouseup (Button: TMouseButton; Shift: TShiftState, X, Y: Integer); Styre; publisert Eiendom AllowUserChange: Boolean Les fAllowUserChange Skriv SetAllowUserChange; Eiendom CharCase: TPSICharCase Les fCharCase Skriv SetCharCase; Eiendom PopupChangeMenu: TPopupMenu Les fChangeMenu Skriv SetChangeMenu; ende, jeg ønsket komponent for å ha to stater: en standardtilstanden, som ville oppføre seg som sin stamfar, og et design statlige, som ville tillate brukeren å endre sine egenskaper under kjøring. Den boolske egenskapen AllowUserChange skiller disse to statene. Når AllowUserChange er sant, er komponenten PopupMenu endret til punkt til verdien lagret i PopupChangeMenu eiendom. Hvis det er False, deretter PopupMenu eiendom går tilbake til sin tidligere design tid oppdraget. Det gir også den komponenten som skal flyttes eller endre størrelse. Jeg trodde det ville være fint for brukeren å kunne se en forskjell mellom de to statene, så jeg forandret markøren til crHandPoint (-21) i SetAllowUserChange method.The PopupMenu oppdraget endres via SetPopupMenu metoden når AllowUserChange eiendom er changed.In for å bytte PopupMenu pekere, standard PopupMenu lagres i fPopupSave i Loaded metoden (se Listing 2). Den SetPopupMenu metoden kalles da for å sikre at den riktige hurtigmenyen er tildelt basert på verdien av AllowUserChange.Listing 2. Loaded method.Procedure TPSIDBEdit.Loaded; Begynn Prøv Hvis (csDesigning i ComponentState) Then Exit; //Capture PopupMenu Assignment fPopupSave: = PopupMenu; SetPopupMenu; Endelig arvet Loaded; Enden, enden, med bruk av den nye teksten saken ProperCase og den nye typen TPSICharCase, måtte jeg helt overstyre og re-implementere alle de andre standard tekst-case-konverteringer i Change metoden av komponenten (se Listing 3). Oppføring 3. Endre method.Procedure TPSIDBEdit.Change; Var iSelStart: Integer; Begynn Prøv Hvis (csDesigning i ComponentState) Eller fIsChanging Then Exit; //Capture Markørposisjon iSelStart: = SelStart; SetTextCase (usann); //Gjenopprett Markørposisjon SelStart: = iSelStart; Endelig Arvet; Ende, End, og den faktiske endring av tekst var litt vanskelig. Hvis du endrer teksten programmatisk når objektet har fokus, og DataSet ikke er i redigerings eller Sett modus, da unntaket "Dataset ikke i redigerings eller Sett modus" genereres. Så før du endrer teksten, må komponentens DataSet.State bli avhørt og endres hvis nødvendig. Vi må også håndtere eventuelle flerbrukerkonflikter som måtte oppstå. Parameteren bCheckState brukes til å avgjøre om DataSet.State må plasseres i redigerings eller innsettingsmodus før du endrer teksten. Hvis den gjør det, så metoden må også legge inn endringene. The Post metoden kalles bare hvis minne variable bPost er satt til Sann. Oppføring 4 viser hvor alt dette skjer i SetTextCase method.Listing 4. SetTextCase method.Procedure TPSIDBEdit.SetTextCase (Const bCheckState: boolske); Var bPost: boolske; Funksjon CanChange: Boolean; Begynn Prøv Hvis ikke bCheckState Så begynner Resultat: = true; Exit; Slutt; If (Datasource < > Nil) Deretter begynner Hvis ikke (DataSource.DataSet.State I [dsEdit, dsInsert]) Så begynner Hvis DataSource.DataSet.Active deretter begynne DataSource.DataSet.Edit; bPost: = true; Slutt; Slutt; Slutt; Resultat: = true; Unntatt Resultat: = False; Slutt; Slutten; Begynn //Hvis teksten endringer og DataSet //er ikke i EditState, deretter en Unntaks //genereres. Sørg for at datasettet er //i EditState før du endrer tekst. fIsChanging: = true; Prøv bPost: = False; Hvis CanChange deretter begynne sak CharCase Of ecNormal: {gjør noe}; ecUpperCase: Tekst: = store bokstaver (tekst); ecLowerCase: Tekst: = små bokstaver (tekst); ecProperCase: Tekst: = ToProper (tekst); Slutt; Hvis bPost Så DataSource.DataSet.Post; Slutt Else MessageDlg ('. Record' 'En annen bruker kan bruke denne "+ + # 13 + # 13 +' TextCase endringer kan ikke være" +, mtWarning, [mbOK], 0 'synlig på denne posten.'); Endelig fIsChanging: = False; Enden, enden, Endre CharCase eiendommen utfører SetCharCase metoden (se Listing 5), som i sin tur utfører SetTextCase method.Listing 5. SetCharCase method.Procedure TPSIDBEdit.SetCharCase (Verdi: TPSICharCase); begynner Hvis fCharCase < > Verdi deretter begynne fCharCase: = verdi; SetTextCase (sann); End; end; For at styre å ha bevegelsesmuligheter, rode I den KeyDown metoden (Se tabell 6). Låne Delphi IDE tastetrykk for komponent flytting og dimensjonering, jeg pleide Ctrl-arrowkeys for bevegelse og Shift-arrowkeys for dimensjonering. Ved å trykke disse tastene fører kontroll for å endre størrelse eller posisjon av en pixel.Listing 6. KeyDown method.Procedure TPSIDBEdit.KeyDown (var Key: Word, Shift: TShiftState), begynner Hvis (Tast inn [vk_up, vk_down, vk_left, vk_right]) Og AllowUserChange Deretter begynner Hvis (Shift = [ssCtrl]) Så Begynn //Endre posisjon sak Key Of vk_Up: Top: = topp - 1; vk_Down: Top: = Top + 1; vk_Left: Venstre: = Venstre - 1; vk_Right: Venstre: = Venstre + 1; Slutt; Slutt Else Hvis (Shift = [ssShift]) Så Begynn //Endre format sak Key Of vk_Up: Høyde: = høyde - 1; vk_Down: Høyde: = Høyde + 1; vk_Left: Bredde: = Bredde - 1; vk_Right: Bredde: = Bredde + 1; Slutt; Slutt; Nøkkel: = 0; Avslutt Else Begynn arvet KeyDown (Key, Shift); Slutt, slutt, jeg ønsket også at brukeren skal kunne flytte komponenten med musa, så jeg overvurdere metodene mousedown, mouseup, og MouseMove.So langt, det du har er en DBEdit som lar brukeren til å endre sin posisjon og størrelse, men lite annet. Skrift, Farge, Tab Order, 3D-effekt, og Border vil bli gjort med tillegg av komponenten ChangeMenu.The grunnlaget for denne komponenten er funnet i enhets TypInfo.pas, som tillater deg å ha tilgang til et objekts RTTI (runtime skriver informasjon). TypInfo.pas inneholder funksjoner og prosedyrer som kan få eller sette et objekts eiendomsverdier under gjennomføringen av programmet. Noen enkle metoder for Stille eller får et objekts eiendomsverdi under kjøring kan se noe sånt Oppføring 7.Listing 7. Få og sette et objekt eiendom på runtime.Function GetProperty (Sender: TComponent; sPropName: String): VariantVar PropInfo: PPropinfo; Begin //Fra klassen informasjon, få eiendommen PropInfo: = GetPropInfo (Sender.ClassInfo, sPropName); //Eksisterer eiendommen? If (PropInfo < > Nil) Deretter Begynn sak propinfo ^ .PropType ^ .Kind Of tkEnumeration, tkInteger: Begynn Resultat: = GetOrdProp (Sender, PropInfo) End; tkString, tkLString, tkWString: Begynn Resultat: = GetStrProp (Sender, PropInfo) End; Slutt; Avslutt Else Resultat: = null; End, Prosedyre SetProperty (Sender: TComponent; sPropName: String; vValue: Variant) Var PropInfo: PPropinfo; Begynn //Fra klassen informasjon, få eiendommen PropInfo: = GetPropInfo (Sender.ClassInfo, sPropName ); //Eksisterer eiendommen? If (PropInfo < > Nil) Deretter Begynn sak propinfo ^ .PropType ^ .Kind Of tkEnumeration, tkInteger: Begynn SetOrdProp (Sender, PropInfo, vValue); Slutt; tkString, tkLString, tkWString: Begynn SetStrProp (Sender, PropInfo, vValue); Slutt; Slutt; Enden, enden, bruk av disse to metodene kan se slik ut: SetProperty (DBEdit1, 'Ctl3D', False); DBEdit2.Ctrl3D: = GetProperty (DBEdit1.'Ctl3D '); Riktignok er dette eksempelet trolig over-forenklet, men prosedyrer som disse kan være ganske praktisk hvis du ikke vet komponentens navn, eller til og med sin class.The tre hovedområder metoder som brukes i ChangeMenu - GetProperty (), SetProperty (), og IsProperty () - finnes i enhets PropFunc.pas det er en del av dette biblioteket. IsProperty () er en boolsk funksjon som kontrollerer for eksistensen av en bestemt eiendom i et objekt og returnerer en verdi av True hvis eiendommen eksisterer. Den kan brukes omtrent som dette: Hvis IsProperty (Form1.Components [i], 'Ctl3D') Så komponenter [i] .Ctl3D: = False; TChangeMenu er en underklasse av TPopupMenu med ytterligere to eiendommer: FontDialog og ColorDialog, som er brukes til å endre komponentens Skrift og farge og kan vise til eventuelle samsvarklassetyper som er omfattet av komponenten. Metodene MenuClick og OnMenuPopup gjøre mesteparten av arbeidet og er tildelt onclick og OnPopup hendelsene i menyelementene når komponenten er opprettet. Alt dette skjer selvsagt i ChangeMenu enheten (se Listing 8) .Listing 8. ChangeMenu unit.unit ChangeMenu; interfaceuses Windows, Meldinger, SysUtils, klasser, Grafikk, Kontroller, Skjemaer, dialogbokser, menyer, comctrls, StdCtrls, dbctrls, db, extctrls -typen TChangeMenu = klasse (TPopupMenu) private {felleserklæringer} pm_Font: TMenuItem; pm_bgColor: TMenuItem; pm_TabOrder: TMenuItem; pm_Ctrl3D: TMenuItem; pm_BorderStyle: TMenuItem; pm_Columns: TMenuItem; pm_Caption: TMenuItem; pm_Divider1: TMenuItem; pm_UpperCase: TMenuItem; pm_LowerCase: TMenuItem; pm_MixedCase: TMenuItem; pm_ProperCase: TMenuItem; pm_Height: TMenuItem; pm_Width: TMenuItem; pm_Style: TMenuItem; fFontDialog: TFontDialog; fColorDialog: TColorDialog; Prosedyre SetColorDialog (Verdi: TColorDialog); Prosedyre SetFontDialog (Verdi: TFontDialog); Prosedyre MenuClick (Sender: TObject); Prosedyre OnMenuPopup (Sender: TObject); beskyttet {Beskyttede erklæringer} public {offentlige erklæringer} Prosedyre Lastet; Styre; Destructor ødelegge; styre; Constructor Opprette (AOwner: TComponent); styre; publiserte {Publisert erklæringer} Eiendom FontDialog: TFontDialog Les fFontDialog Skriv SetFontDialog; Eiendom ColorDialog: TColorDialog Les fColorDialog Skriv SetColorDialog; enden, prosedyre Registeret; implementationuses PropFunc, col_edit, på grunn av den spesialiserte bruk av denne menyen, er menyelementene opprettet kun under kjøring, ikke på design-time i IDE. Etter menyelementene er opprettet, er metoden MenuClick () tildelt onclick tilfelle av hvert menyvalg. Menyen vil se ut som figur 1. Den Lastet metode (se Listing 9) fanger pekeren til komponentens OnPopup metode, tildeler deretter OnPopup hendelsen til metoden OnMenuPoup (). Dette er gjort slik utviklerens OnPopup metoden vil utføre etter OnMenuPopup metoden har ferdigbehandlet sin egen meny items.Listing 9. Loaded method.Procedure TChangeMenu.Loaded; Begynn Prøv //Lagre pekeren til komponentens OnPopup Method FOtherOnPopup: = OnPopup; //Assign OnPopup Metode OnPopup: = OnMenuPopup; Endelig Arvet; Slutt, slutt; Når brukeren høyreklikker musen over komponent, er OnMenuPopup metoden utført (se Listing 10) og initialiserer menyelementene basert på menyens PopupComponent eiendom. PopupComponent er en peker til objektet som var ansvarlig for å aktivere menyen, og er type TComponent. Legg merke til bruken av metoden IsProperty å sette Synlig eiendom menyen items.Listing 10. OnMenuPopup method.Procedure TChangeMenu.OnMenuPopup (Sender: TObject); //Initialmenyelementer basert på //fokusert komponentens type og egenskaper. Var bAngi: Boolean; Begynn //Ikke vis Font element hvis Font //Dialog eiendom er Nil eller Font //Eiendoms ikke eksisterer i den fokuserte //komponent. pm_Font.Visible: = (Ikke (FontDialog = Null)) Og IsProperty (PopupComponent, 'Font'); //Ikke vis Color element hvis ColorDialog //Eiendom er Nil eller Color hotellet har ikke //eksisterer i den fokuserte komponent. pm_bgColor.Visible: = Ikke (ColorDialog = Null) Og IsProperty (PopupComponent, "Color '); //Initial Radio og sjekket menyelementer Hvis IsProperty (PopupComponent, "Border ') Så Begynn pm_BorderStyle.Checked: = (GetProperty (PopupComponent," Border') = bsSingle); pm_BorderStyle.Visible: = true; Avslutt Else Begynn pm_BorderStyle.Visible: = False; Slutt; Hvis IsProperty (PopupComponent, 'Ctl3D') Så Begynn pm_Ctrl3D.Checked: = GetProperty (PopupComponent, 'Ctl3D'); pm_Ctrl3D.Visible: = true; Avslutt Else Begynn pm_Ctrl3D.Visible: = False; Slutt; //Hvis TabOrder egenskapen finnes i komponenten, //vise menypunktet "Tab Order '. pm_TabOrder.Visible: = IsProperty (PopupComponent, 'TabOrder'); //Hvis Kolonner egenskapen finnes i komponenten //og komponenten er TListView, //vise menypunktet. If (PopupComponent Is TListView) Så pm_columns.Visible: = (IsProperty (PopupComponent, 'kolonner') og (TListView (PopupComponent) .Columns.Count > 0)) Else pm_columns.Visible: = False; //Du bør ha ideen nå ... pm_Caption.Visible: = IsProperty (PopupComponent, 'Caption'); //Hvis fokusert komponenten har CharCase og //AllowUser Endre egenskaper, deretter behandle flere //menyelementer. If (IsProperty (PopupComponent, 'CharCase') Og IsProperty (PopupComponent, 'AllowUserChange')) Så Begynn bAngi: = true; //Ikke vis CharCase elementer hvis //datatype er ikke streng. Hvis IsProperty (PopupComponent, 'Datasource') Så begynner Hvis (PopupComponent er TDBEdit) Deretter starter med TDBEdit (PopupComponent) Vet begynner Hvis (datafeltet < > '') Deretter begynner Hvis ikke (Field.DataType = ftString) Deretter Begynn bAngi : = False; Slutt; Avslutt Else bAngi: = False; Slutt; Slutt; Slutt; pm_UpperCase.Visible: = bAngi; pm_LowerCase.Visible: = bAngi; pm_MixedCase.Visible: = bAngi; pm_ProperCase.Visible: = bAngi; pm_Divider1.Visible: = bAngi; //Initial CharCase Radio elementer. Tilfellet GetProperty (PopupComponent, 'CharCase') Of //ecNormal 0: pm_MixedCase.Checked: = true; //ecUpperCase 1: pm_UpperCase.Checked: = true; //ecLowerCase 2: pm_LowerCase.Checked: = true; //ecProperCase 3: pm_ProperCase.Checked: = true; Slutt; Avslutt Else Begynn pm_UpperCase.Visible: = False; pm_LowerCase.Visible: = False; pm_MixedCase.Visible: = False; pm_ProperCase.Visible: = False; pm_Divider1.Visible: = False; Slutt; pm_Width.Visible: = (PopupComponent er TBevel); pm_Height.Visible: = (PopupComponent er TBevel); pm_Style.Visible: = (PopupComponent er TBevel); Hvis pm_Style.Visible Deretter begynner Hvis GetProperty (PopupComponent, 'Style') = 0 Then pm_Style.Caption: = 'Raised Bevel' Else pm_Style.Caption: = 'Senket Bevel'; Slutt; //Utføre komponentens OnPopup Event. Hvis Assigned (FOtherOnPopup) Deretter FOtherOnPopup (Sender); End; Når et element er valgt (se Listing 11) metoden SetProperty () brukes til å endre objektets eiendom values.Listing 11. MenuClick metoden. Prosedyre TChangeMenu.MenuClick (Sender: TObject); //Process menyvalget for fokusert //component.Var SStrengeminne: String; Jeg, iInt: Integer; b: Boolean, begynner Hvis (TMenuItem (Sender) = pm_Ctrl3D) Deretter Begynn //Process 3D - Hvis 3D er valgt //deretter Border må endres //til enkelt. b: = Ikke boolsk (GetProperty (PopupComponent, 'Ctl3D')); SetProperty (PopupComponent, 'Ctl3D', Ord (b)); Hvis b Og (GetProperty (PopupComponent, "Border ') = bsNone) Deretter SetProperty (PopupComponent," Border', bsSingle); End else if (TMenuItem (Sender) = pm_BorderStyle) Deretter Begynn //Process Border Hvis (GetProperty (PopupComponent, "Border ') = bsSingle) Deretter Begynn SetProperty (PopupComponent," Border', bsNone); //Hvis Border er satt til Ingen, deretter //slå 3D Off. SetProperty (PopupComponent, 'Ctl3D', False); Slutt Else SetProperty (PopupComponent, "Border ', bsSingle); Ende else if (TMenuItem (Sender) = pm_TabOrder) Deretter Begynn //Process TabOrder SStrengeminne: = IntToStr (GetProperty (PopupComponent, 'TabOrder')); Prøv SStrengeminne: = InputBox ("Set Tab Order ',' Skriv Tab Order ', SStrengeminne); iInt: = StrToInt (SStrengeminne); SetProperty (PopupComponent, 'TabOrder', iInt); Unntatt Raise Exception.Create ('Tab Order Må' + 'være et heltall'); Slutt; Ende else if (TMenuItem (Sender) = pm_Font) Deretter Begynn //Process Skriftvalg Hvis (FontDialog < > Nil) da begynne FontDialog.Font.Name: = GetProperty (PopupComponent, 'Font.Name'); FontDialog.Font.Size: = GetProperty (PopupComponent, 'Font.Size'); FontDialog.Font.Color: = GetProperty (PopupComponent, 'Font.Color'); FontDialog.Font.Style: = TFontStyles (TFontStyle (GetProperty (PopupComponent, 'Font.Style'))); Hvis FontDialog.Execute deretter begynne SetProperty (PopupComponent, 'Font.Name', FontDialog.Font.Name); SetProperty (PopupComponent, 'Font.Size', FontDialog.Font.Size); SetProperty (PopupComponent, 'Font.Color', FontDialog.Font.Color); SetProperty (PopupComponent, 'Font.Style', Ord (TFontStyle (FontDialog.Font.Style))); //Force Font Høyde for å oppdatere //komponenten i: = GetProperty (PopupComponent, 'Font.Height'); SetProperty (PopupComponent, 'Font.Height', i + (- 5)); SetProperty (PopupComponent, 'Font.Height', i); Slutt; Slutt; End else if (TMenuItem (Sender) = pm_BgColor) Deretter Begynn //Process Color Hvis ColorDialog < > Nil deretter begynne ColorDialog.Color: = GetProperty (PopupComponent, "Color '); Hvis ColorDialog.Execute deretter begynne SetProperty (PopupComponent, "Color", ColorDialog.Color); Slutt; Slutt; End else if (TMenuItem (Sender) = pm_Caption) Deretter Begynn //Process Caption SStrengeminne: = GetProperty (PopupComponent, 'Caption'); SStrengeminne: = InputBox ('Change Caption', 'Skriv inn Caption', SStrengeminne); SetProperty (PopupComponent, 'Caption', SStrengeminne); Ende else if (TMenuItem (Sender) = pm_columns) Deretter Begynn //Prosess Kolonner for TListView. Dette gjøres //med en ekstern form. Application.CreateForm (TfrmEditColumns, frmEditColumns); Prøv frmEditColumns.ColObject: = TListView (PopupComponent); frmEditColumns.ShowModal; Endelig frmEditColumns.Free; Slutt; Ende else if (TMenuItem (Sender) = pm_Width) Deretter Begynn //Process Bredde for TBevel SStrengeminne: = IntToStr (GetProperty (PopupComponent, 'Bredde')); Prøv SStrengeminne: = InputBox ("Set Bredde ',' Skriv inn Width ', SStrengeminne); iInt: = StrToInt (SStrengeminne); SetProperty (PopupComponent, "Bredde", iInt); Unntatt Raise Exception.Create ('Bredde må være' + 'An Integer'); Slutt; Ende else if (TMenuItem (Sender) = pm_Height) Deretter Begynn //Process Høyde for TBevel SStrengeminne: = IntToStr (GetProperty (PopupComponent, 'Høyde')); Prøv SStrengeminne: = InputBox ("Set Høyde ',' Skriv inn Height ', SStrengeminne); iInt: = StrToInt (SStrengeminne); SetProperty (PopupComponent, 'Høyde', iInt); Unntatt Raise Exception.Create ('Høyde må være' + 'An Integer'); Slutt; End else if (TMenuItem (Sender) = pm_Style) Deretter Begynn //Process Bevel stype for TBevel //heves eller senkes Hvis GetProperty (PopupComponent, 'Style') = 0 Then SetProperty (PopupComponent, 'Style', 1) Else SetProperty ( PopupComponent, "stil", 0) End Else Begynn TMenuItem (Sender) .checked: = Ikke TMenuItem (Sender) .checked; Hvis pm_MixedCase.Checked deretter begynne //Normal SetProperty (PopupComponent, 'CharCase', 0); Avslutt Else Hvis pm_UpperCase.Checked deretter begynne //CharCase: = ecUpperCase; SetProperty (PopupComponent, 'CharCase', 1); Avslutt Else Hvis pm_LowerCase.Checked deretter begynne //CharCase: = ecLowerCase; SetProperty (PopupComponent, 'CharCase', 2); Avslutt Else Hvis pm_ProperCase.Checked deretter begynne //CharCase: = ecProperCase; SetProperty (PopupComponent, 'CharCase', 3); Slutt; Enden, enden, TChangeMenu faktisk kan brukes på nesten alle standard komponent som har noen av de støttede egenskaper. Den støtter også TListView kolonneoverskrifter og bredder. Halvveis det
Opprette en komponent som tillater brukeren å endre sin størrelse, posisjon, font, farge og så videre er bra. Men det er ikke veldig nyttig uten evne så lagre og gjenopprette de endrede egenskaper. Du ønsker ikke at brukerne skal ha for å tilpasse programmet på nytt og på nytt hver gang de kjører programmet, gjør du? Det neste trinnet er å opprette en komponent som har evnen til å lagre og gjenopprette klasser og egenskaper som utbygger spesifiserer. TComponentStates
Ved utformingen av komponenten for å lagre komponenteiendomsverdiene, jeg ønsket å gjøre den fleksibel nok å redde bare de verdier som utbygger ønsket. Verdiene for å bli lagret på et sted som vil være lett tilgjengelig og transportable. Jeg ønsket også verdiene for å kunne få tilgang til mer enn en bruker eller arbeidsstasjon. Av disse grunner, valgte jeg å lagre eiendomsverdiene i en INI-filen i stedet for Windows Registry.TComponentStates fungerer mye på samme måte TChangeMenu gjør ved å gå inn rutinene i PropFunc.pas å lagre og gjenopprette komponentegenskaper under kjøring. Det er tre synlige metoder i denne komponenten: lagre, gjenopprette og SetProperties. Jeg tror de to første er selvforklarende. Den SetProperties metoden brukes til å angi en bestemt egenskap av alle objekter på skjemaet som er av samme klasse type. For eksempel, hvis jeg ønsket å endre skrift av alle TDBEdit objekter på Form1 til Arial 12, vil koden se slik ut: ComponentStates1.SetProperties (Form1, 'TDBEdit', 'Font.Name', 'Arial'); ComponentStates1 .SetProperties (Form1, 'TDBEdit', 'Font.Size', 12); Rutinen for å oppnå dette er faktisk ikke så komplisert. Den bruker SetProperty metoden i PropFunc.pas, som omtalt tidligere. Den spinner gjennom alle komponentene på skjemaet og sjekker klassenavn. Hvis klassenavn er en kamp, ​​utfører det den SetProperty () -metoden, endre komponentens eiendommen (se Listing 12) .Listing 12. SetProperties method.Procedure TComponentStates.SetProperties (Const FRM: TForm; Const sClassName: String; Const sPropertyName: String; Const vValue: Variant); //**************************************** ************ //Setter alle komponenter eiendommer på Form frm der //component.classname = sClassName med vValue .//*************** ************************************* Var i: Integer; Begynn med FRM Har Begynn For i: = 0 til (ComponentCount-1) Unngå begynner Hvis Components [i] .ClassNameIs (sClassName) Deretter Begynn SetProperty (komponenter [i], sPropertyName, vValue); Slutt; Slutt; Slutt; //med FrmEnd; Det viktigste eiendom i denne komponenten er ClassesToSave. Det er en TStrings type som inneholder en liste over klasser og egenskaper for å spare til INI-filen. For eksempel vil lagre all viktig informasjon om hver TPSIDBEdit som er på skjemaet, vil innholdet i ClassesToSave ligne this:TPSIDBEdit.LeftTPSIDBEdit.TopTPSIDBEdit.HeightTPSIDBEdit.WidthTPSIDBEdit.TabOrderTPSIDBEdit.Font.NameTPSIDBEdit.Font.SizeTPSIDBEdit.Font.StyleTPSIDBEdit.Font.ColorTPSIDBEdit.ColorTPSIDBEdit.Ctl3DTPSIDBEdit.BorderStyleTPSIDBEdit.CharCaseWhen Lagre metoden utføres, ville INI-filen se slik ut this:[Form1]PSIDBEdit1.Left=313PSIDBEdit1.Top=319PSIDBEdit1.Height=21PSIDBEdit1.Width=121PSIDBEdit1.TabOrder=5PSIDBEdit1.Font.Name=MS Sans SerifPSIDBEdit1.Font.Size=8PSIDBEdit1.Font.Style=0PSIDBEdit1.Font.Color=-2147483640PSIDBEdit1.Color=-2147483643PSIDBEdit1.Ctl3D=1PSIDBEdit1.BorderStyle=1PSIDBEdit1.CharCase=0The Lagre og gjenopprette metoder bruker samme prosedyre som kalles Process (se Listing 13). Boolsk parameter bSave er bryteren for å lagre eller gjenopprette values.Listing 13. Process method.Procedure TComponentStates.Process (bSave: Boolean); Var I, II: Integer; sPropertyName: String; sSection: String; sClassName: String; Sid: String; vValue: Variant; slPropList: TStrings; begynner Hvis Ikke aktiv Then Exit; slPropList: = TStringList.Create; fIniFile: = TIniFile.Create (FIniPath + SaveToINIFileName); Prøv //Bruk skjemaet navn for seksjonen ID i //INI-filen. sSection: = fOwner.Name; For i: = 0 til (fOwner.ComponentCount-1) Har Begynn slPropList.Clear; sClassName: = fOwner.Components [i] .ClassName; //Få Property List For klasse slPropList.Text: = ProcessClass (fOwner.Components [i]); If (slPropList.Text < > ''), og start //********************************** *********** //Process alle definerte egenskapene for denne klassen //**************************** ***************** For ii: = 0 til (slPropList.Count-1) Har Begynn sPropertyName: = slPropList.Strings [ii]; Sid: = fOwner.Components [i] .name + + sPropertyName; '.' Hvis bSave deretter begynne //Skriv eiendomsverdiene til INI fil vValue: = GetProperty (fOwner.Components [i], sPropertyName); If (vValue < > Null) Deretter Begynn sak VarType (vValue) Of varInteger: fIniFile.WriteInteger (sSection, Sid, vValue); varString: fIniFile.WriteString (sSection, Sid, vValue); Slutt; //Veske VarType (vValue) End; Avslutt Else Begynn //*********************************** //Les eiendommen fra INI-filen og sett //komponent eiendom. //*********************************** //Få Nåværende Eiendomsverdien som standard vValue: = GetProperty (fOwner.Components [i], sPropertyName); If (vValue < > Null) Deretter Begynn //Les eiendommens verdi fra INI fil sak VarType (vValue) Of varInteger: Begynn vValue: = fIniFile.ReadInteger (sSection, Sid, vValue); Slutt; varString: Begynn vValue: = fIniFile.ReadString (sSection, Sid, vValue); Slutt; Else vValue: = null; Slutt; Slutt; Slutt; Slutt; Slutt; Slutt;