Multi gjenget timers

Helt lagt en TTimer til søknaden din bare for å oppdage at det uansett ikke blir henrettet fordi de viktigste VCL tråden er opptatt? Delphi Developer september 2000
Copyright Pinnacle Publishing, Inc. Alle rettigheter reserved.Will Real Timer Vennligst Execute? Steve Zimmelman
Nød ofte mor til oppfinnelsen, og denne gangen var ikke noe unntak. Mens jeg jobbet på noen Microsoft Word /Excel integrasjon, et problem oppsto da jeg ble behandle dokumenter med Visible eiendommen er satt til False. Word vil vise en dialogboks (som brukeren ikke kunne se) og vente på svar. Vel, unødvendig å si dette gjorde programmet ser ut som om det ble hengt. Jeg trengte en måte å gang prosessen og håndtere ting, bør de ta for lang. Så jeg slo en TTimer komponent på skjemaet, angir du intervallet for 1000 (ett sekund), og telte antall ganger tidtakeren hendelse utført. Høres bra ut, ikke sant? Feil! Når Word dialogboksen viste seg, ble det ved hjelp av hoved VCL tråden, som i sin tur var ikke gi måte til andre prosesser, herunder TTimer. Så, igjen, programmet virket som om det var hung.The løsning var å lage en tråd som kunne spore den tid uansett hvor travelt hoved VCL tråden var. Men å lage en tråd hver gang jeg trengte denne funksjonaliteten ikke virke som den beste løsningen fra et objektorientert ståsted. Så jeg laget en ny Timer komponent som vil skape og bruke sin egen interne gjenger og gjennomføre et arrangement metode på et bestemt interval.The TThreadTimer komponent er resultatet. Det er en enkel underklasse av TComponent som forvalter en innvendig gjenge. Tråden er opprettet og ødelagt av den komponenten. Når aktivert eiendommen er sant, er tråden opprettet, og når False, er det ødelagt. Jeg ønsket også å sørge for at tråden ikke får opprettet mens i utformingsmodus. Så jeg sjekket ComponentState før du utfører noen metoder: Prosedyre TThreadTimer.SetEnabled (verdi: Boolean), begynner Hvis (verdi < > FEnabled), og start FEnabled: = verdi; //Ikke Opprett eller drepe tråden med mindre //programmet kjører. Hvis ikke (csDesigning I ComponentState) Deretter begynner Hvis FEnabled deretter begynne FTimerEventCount: = 0; FThread: = TTheThread.Create (Selv); Avslutt Else Begynn killthread; Slutt; Slutt; Slutt, slutt,
jeg brukte en metode som kalles killthread å stoppe tråden fra å kjøre og fri den. Før jeg kan faktisk ødelegge tråden, jeg trenger å være sikker på at den tilhørende hendelsen er ikke i midten av behandlingen. Hvis tråden ble frigjort mens arrangementet ble utførende, ville et unntak heves fordi hendelsen ville gå tilbake til en tråd som ikke lenger eksisterte. Jeg håndtert dette med en enkel boolsk variabel, FOnTimerEventInProgress, som ble initialisert til True før tiden hendelsen ble henrettet, og byttet til False like etter at det er ferdig: Prosedyre TThreadTimer.KillThread; Begin Prøv FEnabled: = False; Hvis (FThread < > Nil) da begynne //Vent til OnTimerInterval hendelse for å //ferdig før avslutte tråden. Mens FThread.FOnTimerEventInProgress Gjør Begynn Application.ProcessMessages; Slutt; FThread.Terminate; FThread.Free; Slutt; Endelig FThread: = Nil; FTimerEventCount: = 0; Slutt, slutt,
Fordi komponenten omfatter en tråd objekt, og tråden objektet trenger å referere noen av komponentens egenskaper og metoder, jeg brukte Opprett Constructor av tråden for å fange en referanse til sin eier: Konstruktør TTheThread.Create (AOwner: TThreadTimer); Begynn FOnTimerEventInProgress: = False; //Vi trenger å få tilgang til noen av eierens //eiendommer fra tråden. FOwner: = AOwner; Arvet Lag (usann), End,
tråden objekt i seg selv er ganske enkel. Den har en Lag Constructor, en kjøre, og en OnTimer metode. Execute metoden utfører like etter Opprett Constructor, og forblir aktiv til Execute metoden utganger. Jeg brukte Avsluttet eiendom for å holde tråden i live før det er eksplisitt beskjed om å avslutte. Avsluttet er satt til True når tråden er Terminate metoden kalles. I utføre loop, bruker jeg en enkel Sleep () for å stoppe tråden og vente på den angitte timer intervall. Jeg bruker Application.ProcessMessages å være sikker på at tråden har alt av dagens behandling informasjon før du utfører timer hendelsen. Jeg har tatt en eiendom i den viktigste komponenten kalles SynchronizeEvent. Dette gjør TThreadTimer oppføre seg som en standard TTimer komponent, ved å synkronisere hendelsen med hoved VCL tråden: Prosedyre TTheThread.Execute; Begynn Mens Ikke Self.Terminated Har Begynn Application.ProcessMessages; Sleep (FOwner.Interval); Application.ProcessMessages; Hvis FOwner.SynchronizeEvent deretter synkroniserer (OnTimer) Else OnTimer; Slutt, slutt, Prosedyre TTheThread.OnTimer; Begynn Prøv Hvis Assigned (FOwner.FOnTimerInterval) Deretter begynner Hvis FOwner.Enabled deretter begynne FOnTimerEventInProgress: = True; Inc (FOwner.FTimerEventCount); FOwner.FOnTimerInterval (FOwner); Slutt; Avslutt; Endelig FOnTimerEventInProgress: = False; Slutt, slutt,
Det er tre viktige brikker til TThreadTimer komponent: tråd, Interval, og Timerevent. Som nevnt tidligere, er tråden skapt og ødelagt av Enabled eiendom. Så snart tråden er opprettet, er timeren aktiv og utfører OnTimerInterval hendelsen etter den angitte intervallet perioden har elapsed.There er også en funksjon som heter TimerEventCount-det gjør akkurat det navnet tilsier. Det inkrementerer et heltall hver gang OnTimerInterval arrangementet er behandlet. Dette kan brukes til å se etter potensielle time-outs. For eksempel kan du ha intervallet satt for 1000 (ett sekund), og arrangementet felle for TimerEventCount > = 60. Så hvis hendelsen utfører 60 ganger, deretter et minutt har gått og du trenger for å håndtere noe i søknaden. Men husk, dette timeren er på en egen tråd, så forsøker å manipulere andre VCL objekter i hovedtråden kan resultere i exceptions.After skape ThreadTimer objekt, tok det ikke lang tid å innse at timer hendelsen ville være ute av stand til å oppdatere noen VCL objekter mens hovedtråden var opptatt. For eksempel, hvis du ønsket å se en oversikt peker på et bord mens tabellen ble behandlet og vise resultatene til en TLabel, vil du være ute av lykken. TLabel ville vente til hovedtråden tillot det å oppdatere. Så tilbake til den velkjente tegnebrettet gang igjen.Jeg oppdaget at TCanvas, for det meste, bruker ikke hovedtråden for oppdatering. Så jeg laget en ny etikett komponent kalt TCanvasLabel. TCanvasLabel er en underklasse av TGraphicControl, og bare bruker Canvas eiendommen for drawing.I designet TCanvasLabel slik at den kunne brukes som en etikett og en ProgressBar. Eiendommene Fyll, FillPercent, og FillColor brukes til å male en del av etiketten lerretet en annen farge. Paint metoden er brukt for å vise innholdet i etiketten: Prosedyre TCanvasLabel.Paint; Var Rect: TRect; fLeft, ftop: Integer; Begin //AutoSize bør settes til False når etiketten //brukes i en annen enn hoved //VCL tråd tråd. Hvis AutoSize Da SetSize; Rect: = ClientRect; //Paint etikett med primær bakgrunnsfarge. Canvas.Brush.Style: = bsSolid; Canvas.Brush.Color: = Self.Color; Canvas.FillRect (ClientRect); Hvis (FillPercent > 0) Og FFill Deretter Begynn //beregne fylle prosentandel. Rect.Right: = AVKORT ((Rect.Right * (FillPercent /100))); Canvas.Brush.Color: = FillColor; Canvas.FillRect (Rect); Avslutt; Canvas.Brush.Style: = bsClear; Sak justering av taLeftJustify: Begynn fLeft: = 0; Slutt; taRightJustify: Begynn fLeft: = ClientRect.Right - Canvas.TextWidth (Caption); Slutt; taCenter: Begynn fLeft: = AVKORT ((ClientRect.Right - Canvas.TextWidth (Caption)) /2); Slutt; Slutt; Sak Oppsett av tlTop: ftop: = 0; tlCenter: ftop: = AVKORT ((ClientRect.Bottom - Canvas.TextHeight (Caption)) /2); tlBottom: ftop: = (Self.Height - Canvas.TextHeight (Caption)); Slutt; Canvas.TextOut (fleft, ftop, Caption); //Tvinge lerret å oppdatere seg selv. Canvas.Refresh, End,
Det er et par advarsler du må se opp for når du bruker hendelser som bruker tråder:

The AutoSize eiendom TCanvasLabel bør settes til False når du kjører programmet. Endre størrelsen på etiketten bruker hoved VCL tråden, slik at etiketten vil ikke oppdatere.

  • Vær sikker på å ikke inkludere noen standard VCL objekter i tråd hendelsen uten grundig å teste dem, eller spesielt opprette dem i kode inne i tråden.
    En enkel bruk av begge disse komponentene kan bli funnet i demoen inkludert i den medfølgende filen. Den enkle program demonstratesthe forskjellen mellom en standard TTimer og timeren funnet i TThreadTimer component.The TTimer tilfelle oppdaterer en TLabel med gjeldende klokkeslett hvert sekund. For å opprette en travel prosess, tilføyer programmet 10.000 poster i en For loop.You'll merke til at i løpet av append prosess, tidsdisplayet stopper for standard TTimer mens de andre etikettene er oppdatert deres utpekte intervaller.