Lazarus 3.0 (2023.12.21.)
Letöltés

  • Oldal:
  • 1

TÉMA:

Dinamikusan létrehozott vezérlők közös eseménykezelője 2023 febr. 14 08:35 #2639

  • Hozso
  • Hozso profilkép Témaindító
  • Haladó forumozó
  • Haladó forumozó
  • Hozzászólások: 33
  • Köszönetek: 0
Köszönöm a segítséget! Ez alapján sikerült megoldanom. Így néz ki a tesztprogram ide vonatkozó része:
procedure TfrmMain.CardOnClick(Sender: TObject);
var   iTmp: integer;
begin
  frmMain.memMemo.Text:=frmMain.memMemo.Text+'Click (index as of form component): '+IntToStr(TControl(Sender).ComponentIndex)+#13#10;
  iTmp:=0;
  While not (Sender = pnlCards.Controls[iTmp]) do  
  begin    
    iTmp:=iTmp+1;
  end;
  frmMain.memMemo.Text:=frmMain.memMemo.Text+'Click (index as of panel component): '+IntToStr(iTmp)+#13#10;
end;

(A mellékelt képen látható, hogy rendben visszakapom klikkeléskor az elem indexét a formon lévő elemek alapján és a panelen belül is, a panelra vonatkoztatva.)
Mellékletek:

Dinamikusan létrehozott vezérlők közös eseménykezelője 2023 febr. 13 15:02 #2638

  • Gábor
  • Gábor profilkép
  • Adminisztrátor
  • Adminisztrátor
  • Hozzászólások: 504
  • Köszönetek: 86
Az eseménykezelőknek van Sender:TObject paramétere, mely minden esetben közvetlenül a kattintási eseményt elkapó objektumra mutat.
Esetedben a TImage(Sender) álruhába bújtatva lekérdezheted és kezelheted az adott kép adatait (pl a nevét vagy bármi mást).
Ha az általad létrehozott tömbbeli (vagy a TPanel.Components-beli) sorszámára vagy kiváncsi akkor a Sender-t kell megkeresned a tömbben, mint bármilyen más elemet egy akármilyen tömbben (végigjárással).

Haladók számára az IN operátor felülbírálása is egy lehetőség.
Hogyan kérdezzünk okosan? / Mit kell tennünk kérdezés előtt? -- Lazarus 3.0 -- FPC 3.2-- GNU/Linux 5.15.0 x86_64
Megköszönték: Hozso

Dinamikusan létrehozott vezérlők közös eseménykezelője 2023 febr. 13 12:38 #2637

  • Hozso
  • Hozso profilkép Témaindító
  • Haladó forumozó
  • Haladó forumozó
  • Hozzászólások: 33
  • Köszönetek: 0
Ismét én, ugyan ezzel a problémával küzdök...

Egy másik projekten dolgozok, feltettem egy TPanel-t (a neve pnlCards) egy formra még szerkesztési időben. Futáskor a méretét az igényeknek megfelelően megnövelem és felteszem rá az általam létrehozott TImage elemeket. Ezeknek a szülője a TPanel. Ezek a TImage elemek egy kételemű tömbben vannak definiálva. Egy közös OnClick eseménykezelőjük van, első körben szeretném kiíratni, hogy hányadik TImage-re történt a kattintás. Honnan tudom, hogy hányadik elemre kattintottak?

  Ha az OnClick eseménykezelőbe ezt írom:

frmMain.memMemo.Text:=frmMain.memMemo.Text+'Click on: '+IntToStr(pnlCards.ComponentIndex)+#13#10;

  akkor mindig 4-et kapok, bármelyik TImage-re kattintok. (Ez gondolom a formon a TPanel indexe, mivel van rajta még néhány más komponens.)
 

Dinamikusan létrehozott vezérlők közös eseménykezelője 2022 okt. 27 07:04 #2622

  • Hozso
  • Hozso profilkép Témaindító
  • Haladó forumozó
  • Haladó forumozó
  • Hozzászólások: 33
  • Köszönetek: 0
Köszönöm a segítséget, ezt így már tudom használni! (Most még maradok a TPanel nélküli megoldásnál, de legközelebb már ezzel fogom készíteni az ilyen feladatokat.)

Dinamikusan létrehozott vezérlők közös eseménykezelője 2022 okt. 26 14:52 #2621

  • Gábor
  • Gábor profilkép
  • Adminisztrátor
  • Adminisztrátor
  • Hozzászólások: 504
  • Köszönetek: 86
Természetesen TForm-on is ugyanúgy működik, hiszen annak is elérhető a .Components tulajdonsága. Én ennek ellenére TPanel-re tenném, mert úgy könnyebb lenne őket együtt kezelni (csak a panel elemein kell végigmenni) ha a Form-ra később egyéb dolgok is kerülnek.
Hogyan kérdezzünk okosan? / Mit kell tennünk kérdezés előtt? -- Lazarus 3.0 -- FPC 3.2-- GNU/Linux 5.15.0 x86_64
Megköszönték: Hozso

Dinamikusan létrehozott vezérlők közös eseménykezelője 2022 okt. 26 13:44 #2620

  • Hozso
  • Hozso profilkép Témaindító
  • Haladó forumozó
  • Haladó forumozó
  • Hozzászólások: 33
  • Köszönetek: 0
Nem volt zavaros, értem amit írtál. De ez csak akkor működik, ha egy TPanel-re pakolom fel a vezérlőket? A formra rakva (TPanel nélkül) is működhet a dolog? (Bocs, ha hülyeséget kérdezek...)

Dinamikusan létrehozott vezérlők közös eseménykezelője 2022 okt. 26 12:39 #2619

  • Gábor
  • Gábor profilkép
  • Adminisztrátor
  • Adminisztrátor
  • Hozzászólások: 504
  • Köszönetek: 86
A TForm és a TPanel is a TComponent leszármazottja, mely(ek)nek van .Components nevű tulajdonsága (és persze .Name is), ami a rajtuk elhelyezett elemeket tartalmazza.
Így aztán a TComponent lehetőségeinek szem előtt tartásával megvalósítható az amit szeretnél.

Pl. ha a Form1-en elhelyezel egy TPalel-t, melynek a neve Panel1 akkor az ezen elhelyezett TEdit-ek már a Panel1.Components[index] kifejezés használatával elérhetők, ahol 0 alaporól indulva index:=(sor*sorhossz)+oszlop

Remélem nem írtam túl zavarosan :)
Hogyan kérdezzünk okosan? / Mit kell tennünk kérdezés előtt? -- Lazarus 3.0 -- FPC 3.2-- GNU/Linux 5.15.0 x86_64

Dinamikusan létrehozott vezérlők közös eseménykezelője 2022 okt. 26 11:52 #2618

  • Hozso
  • Hozso profilkép Témaindító
  • Haladó forumozó
  • Haladó forumozó
  • Hozzászólások: 33
  • Köszönetek: 0
Köszönöm, ezt a 'TControl(Sender).Name' megoldást tudom használni.

Azt esetleg meg lehet oldani, hogy a kétdimenziós tömb elemeit egyből "megkapjam" valahol?

Arra gondolok, hogy van egy edtMsg[x,y] tömbbe rendezett TEditfileld. A létrehozáskor meg tudom csinálni, hogy a nevük sorra utaljon a tömbindexekre és a fenti megoldással a tömbindexeket vissza tudom "keresni" a név alapján. De ennél "elegánsabb" lenne, ha valahogy a tömbindexeket egyből tudnám használni. Már, ha ez megoldható...

 

Dinamikusan létrehozott vezérlők közös eseménykezelője 2022 okt. 26 10:26 #2617

  • Gábor
  • Gábor profilkép
  • Adminisztrátor
  • Adminisztrátor
  • Hozzászólások: 504
  • Köszönetek: 86
Az eseménykezelők Sender:TObject paramétere mindig a kiváltó objektumra mutat.
A kiváltó objektum nevét (és minden TControl-ból örökölt infóját is) az alábbi módon olvashatod ki:
procedure TForm1.Button1Click(Sender: TObject);
begin
    Label1.Caption := TControl(Sender).Name;
end;
Részleteket lásd a TControl leírásában.
Természetesen bármely ős típust lehet használni a maszkolásra vagy akár olyat is, amely egy esetleges leszármazott, de ez utóbbit csak akkor ha biztos a dolog, máskülönben súlyos kivétel (hiba) keletkezhet.

Ha adott típusú objektumok eseményét akarod kezelni (pl. bármely TButton típusú objektum):
if Sender is TButton then ValamiLegyen;
Ha egy meghatározott objektum eseményét akarod kezelni (itt Button1 kattintását):
if Sender = Button1 then ValamiLegyen;
Hogyan kérdezzünk okosan? / Mit kell tennünk kérdezés előtt? -- Lazarus 3.0 -- FPC 3.2-- GNU/Linux 5.15.0 x86_64

Dinamikusan létrehozott vezérlők közös eseménykezelője 2022 okt. 26 09:09 #2615

  • Hozso
  • Hozso profilkép Témaindító
  • Haladó forumozó
  • Haladó forumozó
  • Hozzászólások: 33
  • Köszönetek: 0
  Elnézést, ha már volt ilyen téma, de nem tudom, hogyan is tudnék ilyesmire rákeresni... (elég bonyolult a kérdés ahhoz, hogy ne legyen egyszerű rákeresni a megoldásra...)

  Adva van több form, amelyeken dinamikusan hozok létre grafikus szabványos vezérlőket. Pl. ComboBox-okat, Edit mezőket stb. Van amelyik egy- és van, amelyik kétdimenziós tömbbe van szervezve. Azt sikerült megoldanom, hogy a létrehozáskor megadom egy-egy vezérlő csoportnak, hogy mi legyen az adott esemény kezelője. (Egy eljárás.)
  A kérdésem, hogy honnan tudja az eljárás, hogy épp melyik vezérlő váltotta ki a meghívását? (Most azt csinálom, hogy ha lefut az eseménykezelő, akkor az összes vezérlőelemen elvégzi a szükséges vizsgálatokat. De ha sok vezérlő van, akkor ez sokáig tart, illetve eleve praktikusabb lenne, csak azon az egy elemen elvégezni a szükséges műveleteket, amelyik kiváltotta az eseményt.)

  Mellékelek egy kis részletet a programomból. A SetDataFields()-ben az összes mezőre végrehajtom a vizsgálatot, de ha tudnám, hogy melyik elem váltotta ki az eseményt, akkor elég lenne csak azzal foglalkozni... 


   Horváth Zsolt
 
for iTmp:=0 to 15 do                //slave address hardware type labels
  begin
    frmMain.cboHWType[iTmp]:=TComboBox.Create(self);
    with cboHWType[iTmp] do
    begin
      Parent:=self;
      Height:=cLblHWTableHeight;
      Width:=cCboHWTypeWidth;
      Left:=cLblHWTableStartX+cLblHWTableXDist;
      Top:=cLblHWTableStartY+cLblHWTableYDist*iTmp;
      Name:='cboHWType_'+IntToStr(iTmp);
      Items:=lstHWType;
      ItemIndex:=0;
      Style:=csDropDownList;
      OnChange:=@SetFields;
      Font.Name:=cLabelFontType;
      Font.Size:=cLabelFontSize;
    end;
 
  end;                                         
 
...
 
procedure TfrmMain.SetFields(Sender: TObject);
          //combo box changed, set the data fields
begin
  SetDataFields();
end;
 
...
 
 
procedure SetDataFields();
          //set the visibility and enable properties of the IODat fields
var
  iTmp, iTmp2: integer;
 
begin
  for iTmp:=0 to 15 do
  begin
    if (frmMain.cboHWType[iTmp].Text=cHWType01) then
    begin
      for iTmp2:=0 to 15 do
      begin
        frmMain.chkIODat[iTmp,iTmp2].Visible:=true;
        frmMain.chkIODat[iTmp,iTmp2].Enabled:=false;
      end;
      for iTmp2:=0 to 7 do frmMain.edtIODat[iTmp,iTmp2].Visible:=false;
    end;
    if (frmMain.cboHWType[iTmp].Text=cHWType02) then
    begin
      for iTmp2:=0 to 15 do
      begin
        frmMain.chkIODat[iTmp,iTmp2].Visible:=true;
        frmMain.chkIODat[iTmp,iTmp2].Enabled:=true;
      end;
      for iTmp2:=0 to 7 do frmMain.edtIODat[iTmp,iTmp2].Visible:=false;
    end;
    if (frmMain.cboHWType[iTmp].Text=cHWType03) then
    begin
      for iTmp2:=0 to 7 do
      begin
        frmMain.edtIODat[iTmp,iTmp2].Visible:=true;
        frmMain.edtIODat[iTmp,iTmp2].Enabled:=false;
      end;
      for iTmp2:=0 to 15 do frmMain.chkIODat[iTmp,iTmp2].Visible:=false;
    end;
    if (frmMain.cboHWType[iTmp].Text=cHWType04) then
    begin
      for iTmp2:=0 to 7 do
      begin
        frmMain.edtIODat[iTmp,iTmp2].Visible:=true;
        frmMain.edtIODat[iTmp,iTmp2].Enabled:=true;
      end;
      for iTmp2:=0 to 15 do frmMain.chkIODat[iTmp,iTmp2].Visible:=false;
    end;
    if (frmMain.cboHWType[iTmp].Text='-') then
    begin
      for iTmp2:=0 to 7 do frmMain.edtIODat[iTmp,iTmp2].Visible:=false;
      for iTmp2:=0 to 15 do frmMain.chkIODat[iTmp,iTmp2].Visible:=false;
    end;
   end;
 
end;
 

  • Oldal:
  • 1