Avatar billede sjensen Nybegynder
12. november 1999 - 09:49 Der er 9 kommentarer og
2 løsninger

Runtime - Form - Forrige komponent

I nogle funktioner har jeg brug for at vide hvilket komponent (felt) der var det forrige. Det gælder f.eks. når brugeren trykker på en knap hvorfra han kan hente nogle oplysninger der så efterfølgende skal ôverføres til det pågældende felt.

Når det f.eks. er et speedknap til et bestemt felt er det ikke noget problem, men er det en generel speedknap ville det være rart at vide hvilket felt der havde focus inden brugeren trykkede på speedknappen, og dermed overføre det indhold han vælger til det pågældende felt.

Jeg kan selvfølgelig selv, i hhv. OnEnter og OnExit holde styr på en variabel, men da mine applikationer består af rigtigt mange forms med mange felter i hver er dette en ordentlig mundfuld.

Jeg vil derfor gerne vide om der er nogen der har andre, lettere, metoder eller ideer, til at løse dette problem ?
Avatar billede delphi Nybegynder
24. november 1999 - 14:09 #1

Umiddelbart lyder det som en lidt tungt problem, idet en component, så vidt jeg ved, ikke kan få at vide hvem/havd der havde focus før den selv fik det - Jeg kender ihvertfald ikke lige det API kald, der giver denne funktionalitet.

Jeg har nu jeg tænker over det egentligt aldrig haft brug for den funktionalitet du efterlyser.  Hvis du lidt dybere beskriver formålet med dit ønske, så er det muligt der istedet dukker en op der har en alternativ løsning, der er lidt mere brugbar.

Den eneste metode jeg lige umiddelbart kan tænke mig, er at oprette en privat variabel i din form declearation.  Denne variabel skal indeholde idenditeten på den komponent der i øjeblikket har focus.  Variablen tilskrives i dine komponenters OnEnter metoder.  Det vil derfor være nødvendigt at lave en OnEnter for alle de aktuelle komponenter.

Har en komponent brug for at vide hvem der havde focus før den selv, vil den altså kunne aflæse denne værdi i variablen før den selv overskriver værdien.

NiP/Delphi
Avatar billede sjensen Nybegynder
25. november 1999 - 12:32 #2
Til Delphi:

Tak for dit svar, men det giver mig ikke løsningen. Som jeg selv skriver i mit spørgsmål er jeg opmærksom på hhv. Onenter og Onexit, men da jeg har mange komponenter på hver form og har mange forms, hvoraf mange af felterne allerede benytter en onenter og/eller en onexit event, er det ikke en holdbar løsning. Specielt set med vedligelses "øjne".

Jeg skal bruge funktionaliteten til at indsætte "klip" fra klippebordet i det felt man kom fra, når man klikker på f.eks. en speedbutton eller når man vender tilbage fra f.eks. et søgebillede hvor man har valgt en værdi.
Og fordi der er mange felter men kun en knap på formen, ved jeg ikke i hvilket felt jeg skal indsættet "klippet", hvis jeg ikke kan se i hvilket felt der havde focus da brugeren trykkede på knappen.

Kort sagt mangler der en general variabel der f.eks. kunne hedde "PreviousControl" og som på samme måde som "ActiveControl", indeholder en "peger" til det object der var aktivt sidst. For ikke at lave om på alle mine komponenter (typisk felter) med onenter/onexit efterlyser jeg et nedarvet komponent (igen f.eks. edit eller dbedit) der automatisk vedligeholder den variabel som du også foreslår. Spørgsmålet er bare om det ikke skulle være på et højere niveau end EDIT denne funktion skulle implementeres.

Så mit håb var selvfølgelig at der var nogen der enten kendte til et API-kald eller en message, alternativt et generelt komponent, der kunne håndtere det, og som fortælle navnet/typen på forrige aktive komponent.

Hilsen sjensen
Avatar billede delphi Nybegynder
25. november 1999 - 12:58 #3
Hvad så med en fusker løsning!

Du sætter en timer på din for, der trigger ofte, fx. hvert 10 mSek.
I timeres onTimer event sammenligner du current ActiveControl med den der var activ sidst eventen kørte (for 10 mSek siden).  Det siger sig selv, at onTimer eventen derfor hele tiden skal huske sidste active control i en form variabel.

Der er så to muligheder nu:

1: Hvis den nye active control er din speedbutton, så kan du nu skrive dit klip til den forrige component

2: Din speedbuttons onClick kan kigge i variablen for at se hvilken component der var aktiv sidst.  Metoden er måske lidt usikker, hvilket jeg ikke lige kan overse uden at se hvorledes events bliver kylet i stakken - Det der (måske?) kan ske er,
  a: Du trykker og active control sættes til din speed button
  b: onTimer eventen kommer og ændre forrige komponent til din speedbutton
  c: Din speedbuttons onClick blever serviceret, men nu er variablens indhold invalid.
  (Du kan se'følig osse bare gemme de sidste to active components i din(e) variabel(er)- hvis onClick ser at den forrige active er speedbutton'en selv, så kigger den bare et trin længere tilbage - Det SKAL så være den rigtige).

I stedet for en timer, er der måske en mulighed for at din form overtager alle mouse- og keyboard- events, hvilket jeg mener at huske man kan gøre, checkker om der sket et focus skifte, hvilket medføre ændring i ovennævnte form variabel.  Til slut skal den fangede event serviceres af den alm. components onclick event metode.

Håber at disse løse ideer kan hjælpe.

NiP/Delphi
Avatar billede sjensen Nybegynder
25. november 1999 - 14:12 #4
Hej Delphi,

Ideen med en timer er umiddelbart brugbar og den kræver kun et minimum af kodning. Jeg har lavet et lille testprogram der viser at den virker hvis hhv. timer og timerevent indsættes i alle relevante forms. Dog skal jeg bruge "if (ActiveControl is T...) then OldCont := ActiveControl; hvilket betyder at jeg skal have en linie for hver af de typer komponenter jeg kan anvende: Edit, Memo, Listbox o.s.v. (samt tilsvarende DB... komponenter) i hver timer afhængig af hvilke komponenter der kan forekomme på den pågældende form.

Det betyder selvfølgelig en global funktion der returnerer true hvis den skal gemmes a la: if Skal_Gemmes(activecontrol) then OldCont := AactiveControl; hvor OldCont oprettes som en global var, og således kan jeg nøjes med at vedligeholde den et sted. Funktionen Skal_Gemmes skal så selvfølgelig teste for alle muligheder.

Det betyder en timer der sættes true i formcreate og false i formdestroy på hver form, med en enkelt linie som beskrevet ovenstående. Og når brugeren så klikker på knappen sættes "OldCont.text := {returtekst};

Det bør kunne virke fornuftigt og med en rimelig enkel vedligeholdelse i forhold til funktionaliteten.

Jeg er derfor tilbøjelig til at acceptere dit svar, men dels vil jeg gerne lige teste det lidt mere, dels se om der kommer andre, ligeså gode forslag, og kommer der ikke et der er bedre, er de 30 point dine.

Hilsen
sjensen
Avatar billede delphi Nybegynder
25. november 1999 - 14:56 #5
Kan du ikke bare nøjes med en enkelt IF-linie i din Timer event:

  If (ActiveControl <> OldCont) And Skal_Gemmes(ActiveControl) Then
    Begin
      // Evt. actions her
      OldCont := ActiveCont
    End;

Der ska' se'følig være en timer/timerevent på hver form.  Det kan du ikke undgå.

Du behøver ikke sætte timeren til true/false i dine Create/destroy's.  Du kan nøjes med at gøre det i IDE'ens Object Inspector. Det betyder se'følig at timer eventen kører i baggrunden når din form er skjult - Er det et problem?  (Kan være det, så'en rent tidsmæssigt).

NiP/Delphi
Avatar billede sjensen Nybegynder
25. november 1999 - 15:47 #6
Hej Delphi,

"Kan du ikke bare nøjes med en enkelt IF-linie i din Timer event:

  If (ActiveControl <> OldCont) And Skal_Gemmes(ActiveControl) Then
    Begin
      // Evt. actions her
      OldCont := ActiveCont
    End;"

Jo, bestemt, men da Skal_Gemmes kun returnerer true hvis det felt markøren er i er et af de flettyper jeg er interesseret i, betyder det mindre om OldCont bliver sat til værdien af activecont hver gang timeren aktiveres, selvom værdien allerede er der i forvejen.

Vedr. timer true/false: Det har du ret i, men jeg plejer altid selv at styre dem så jeg ved hvormange der er aktive samtidig.

sjensen
Avatar billede delphi Nybegynder
25. november 1999 - 15:50 #7
Så vidt jeg ved - og jeg har taget fejl før - , vil en timer der er aktiv, bruger de samme resourcer ligegyldigt om den er enablet eller ej.

Delphi
Avatar billede sjensen Nybegynder
25. november 1999 - 16:39 #8
Det er nok rigtigt, men den bruger da ikke tiden også, og 10 timers der hver er sat til at aktiveres med 100 msek tager trods alt noget tid fra maskinen, også selvom de ikke laver meget.

Som nævnt tidligere vil jeg prøve at implementere det i en af mine appls. og se hvordan det virker og så vender jeg tilbage. Jeg regner med at du hører fra mig (om dette) lige efter week-enden

Hilsen
Sjensen
Avatar billede kjeld.a Nybegynder
01. december 1999 - 08:59 #9
Hvad med at anvende delphi runtime type information (RTTI) i unit typinfo, jf. nedenstående eksempel til at klare dit problem. Problemet med at anvende RTTI er dog, at RTTI er udokumenteret fra Inprise's side, således at det evt. kan ændre sig i fremtidige versioner af delphi. Nedenstående kører under delphi 4 og 5, men burde generelt kunne køre under delphi32 generelt.

Et lille PS! I delphi 5 er tilføjet nogle nye "easy access" metoder til brug af RTTI, som er nemmere at bruge. Jeg har ikke anvendt dem i eksemplet, idet de ikke er implementeret i de tidligere udgave af delphi.

Her er så min kode (unit), hvor jeg indsætter en ny onexit-procedure for den aktive Twincontrol. Jeg har indsat kommentarer, så jeg håber at kode nogenlunde forståelig:

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure Edit1Exit(Sender: TObject);
  private
    { Private declarations }
    fonexit : tnotifyevent;
    fmyonexit : tnotifyevent; {oprettes fordi myownexit ikke kan typecastes, jf. linie 39 & 67}
    fwincontrol : Twincontrol;
    procedure FocusErSkiftet(sender : tobject);
    procedure myonexit(sender : tobject);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
uses typinfo; { delphi's unit med RTTI-metoder}

procedure TForm1.FormCreate(Sender: TObject);
begin
  fwincontrol := nil;
  fmyonexit := myonexit;
  Screen.OnActiveControlChange := FocusErSkiftet;
end;

procedure TForm1.FocusErSkiftet(sender: tobject);
var propinfo : ppropinfo;
begin
  if assigned(fwincontrol) then begin
    propinfo := getpropinfo(fwincontrol.classinfo, 'OnExit');
    if assigned(propinfo) then
      SetMethodProp(fwincontrol,propinfo,tmethod(fonexit)); {sæt oprindelig onexit-metode tilbage}
  end;

{egen kode indsættes her hvis udførsel ønskes efter fokusskift}
{  if assigned(fwincontrol) then begin
    label1.caption := fwincontrol.name;
    propinfo := getpropinfo(fwincontrol.classinfo, 'Color');
    SetOrdProp(fwincontrol,propinfo, clgray);
  end;}
{egen kode slut}

  if assigned(screen.activecontrol) then begin
    fwincontrol := screen.activecontrol; {sæt wincontrol til ny focused wincontrol}
    propinfo := getpropinfo(fwincontrol.classinfo, 'OnExit');
    if assigned(propinfo) then
      fonexit := tnotifyevent(GetMethodProp(fwincontrol,propinfo)) {gem wincontrol's onexit-metode}
    else
      fonexit := nil;
    SetMethodProp(fwincontrol,propinfo,tmethod(fmyonexit)); {sæt min onexit-metode som ny metode}
  end else begin
    fwincontrol := nil; //Rengøring
    fonexit := nil; //Rengøring
  end;
end;

procedure TForm1.myonexit(sender: tobject);
var propinfo : ppropinfo;
begin

{egen kode indsættes her hvis udførsel ønskes før fokusskift}
  if assigned(fwincontrol) then begin
    label1.caption := fwincontrol.name;
    propinfo := getpropinfo(fwincontrol.classinfo, 'Color');
    SetOrdProp(fwincontrol,propinfo, clgray);
  end;
{egen kode slut}

  if assigned(fonexit) then
    fonexit(self); {udfør oprindelig exit-metode}
end;

procedure TForm1.Edit1Exit(Sender: TObject);
begin
  label2.caption := inttostr(random(100));
end;

end.

Mvh
Kjeld
Avatar billede sjensen Nybegynder
02. december 1999 - 13:12 #10
Lige en kommentar til forslag og point fordeling:

Jeg takker begge for jeres indslag og begge virker umiddelbart. Delphi's forslag med en timer fik jeg til at virke elegant nok, og uden for meget vedligeholdelse.

Kjeld's derimod er lidt mere omfattende, men til gengæld uden en timer og dermed mindre ressource krævende. Så både Delphi og Kjeld har foreslået en brugbar løsning. Dog synes jeg Kjelds er mere elegant, specielt måske fordi jeg er sikker på at den løsning ville jeg aldrig selv have fundet på, og dermed har jeg også lært noget nyt.

Timer løsningen havde jeg formentligt fundet selv på et tidspunkt, fordi jeg bruger noget tilsvarende i andre situationer. Det skal dog ikke tage æren fre Delphi.

Jeg er meget tilfreds med begge svar. Og jeg håber at d'herrer/damer, hvad det nu er det gemmer sig navnene :-), er ligeså tilfredse med pointfordelingen.

Tak
sjensen
Avatar billede delphi Nybegynder
02. december 1999 - 13:34 #11
Takker - men jeg er nu mere glad for at have kunnet hjælpe end for point'sne.  Point er ligesom bare glasur på kagen....

Hr.(!) Delphi
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester