Reakce MDI formuláře na smazání objektu, který MDI formulářem spravován. – Delphi – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Reakce MDI formuláře na smazání objektu, který MDI formulářem spravován. – Delphi – Fórum – Programujte.comReakce MDI formuláře na smazání objektu, který MDI formulářem spravován. – Delphi – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené — příspěvek s řešením.
Navara0
Návštěvník
24. 3. 2023   #1
-
0
-

Zdravím,

tvořím aplikaci, ve které se vytváří a spravuje struktura objektů pomocí MDI Formulářů. Vazba MDI na formulář je provedena pomocí proměnné typu třídy konkrétního objektu který má formulář spravovat (lze v něm nastavovat vlastnosti toho objektu). 

Například mám třídu Traťová kolej:

TTratovaKolej = class
  CreateID: Integer;
  Cislo: ShortString;
  Smer: ShortString;
  Zkratka: ShortString;
  NetID: ShortString;

  constructor Create(aCreateID: Integer);
  destructor Destroy(); override;
end;

Objekty, vytvořené podle této třídy (respektivě ukazatele na ně), jsou po vytvoření ukládány v poli: 

ArrTratoveKoleje: Array of TTratovaKolej;

Když chci vlastnosti daného objektu upravit, vyvolám MDI formulář, ve kterém je v části public deklarována proměnná typu TTratovaKolej 

    //...
  private
    { Private declarations }
  public
    { Public declarations }

    ATratovaKolej: TTratovaKolej;
    //...

Do této proměnné vložím při vytváření formuláře odkaz na konkrétní objekt z výše uvedeného pole:

procedure TSpravaMDI.CreateMDIChild_TratovaKolej(
  NovaTK: Boolean;
  ATratovaKolej: TTratovaKolej);
var
  Child: TDlgTratovaKolej;
begin
  Child := TDlgTratovaKolej.Create(Application);
  //...
  if NovaTK
  then 
    Child.ATratovaKolej := TTratovaKolej.Create(Indexer.GetID())
  else begin
    Child.ATratovaKolej := ATratovaKolej;
    Child.PrevzitKolej();
    //Nastavuje do editačních políček hodnoty z objektu
  end;
end;

//volání pro vytvoření okna, správný index je předem zjištěný
SpravaMDI.CreateMDIChild_TratovaKolej(False, ArrTratoveKoleje[IndexKoleje]);

Otevření okna, úprava vlastností, i uložení do konkrétního objektu probíhá v pořádku. Problém nastane, když vedle tohoto okna otevřu jiné, ve kterém je možnost smazat objekt (resp. všechny objekty), na který odkazuje proměnná ATratovaKolej v MDI formuláři. Pro uvolnění objektu používám  

for i := 0 to High(ArrTratoveKoleje) do
begin
  FreeAndNil(ArrTratoveKoleje[i]);
end;

Problém je, že smazání proběhne, ale odkaz, držený v MDI formuláři, je "platný", respektivě se chová divně (při náhledu v Debug inspectoru) jsou v proměnných tohoto "smazaného" objektu nesmyslné hodnoty. 

Očekával jsem že odchytit smazání objektu půjde odchytit tím, že odkazt na smazaný objekt se změní na nil. To se ale nestane, assigned(ATratovaKolej) vrací také true.

Kde dělám chybu, popřípadě jak ve formuláři zareagovat na smazání objektu, na který se v MDI formuláři takto odkazuji?

Díky, N.

Nahlásit jako SPAM
IP: 46.135.18.–
JerryM0
Věrný člen
25. 3. 2023   #2
-
0
-

Když mažeš MDI form tak by si měl někde dát NULL v seznamu MDI formulářů, který vlastní rodičovský formulář. Tedy "zrušit" propojení které je obousměrné.

https://soonsantos.medium.com/working-with-mdi-forms-in-delphi-d7c37a176f5f

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:1ccd:71b:78d8:499d...–
Navara0
Návštěvník
25. 3. 2023   #3
-
0
-

Nerozumíme si, respektivě hned ve druhé větě jsem napsal hovadinu. To je tak, když se spěchá...

Mělo tam být napsané Vazba konkrétního MDI formuláře na objekt, do kterého se ukládají ve formuláři zadané údaje, je provedena pomocí proměnné typu třídy konkrétního objektu, uvedené v public části toho MDI formuláře.Je tam tedy vazba MDI formulář - odkaz na existující objekt.

Jde o to, jak reagovat na zrušení objektu na který si MDI formulář drží ten odkaz. Když vytvořím pár objektů, otevřu si je v těch MDI oknech s předáním toho odkazu, ta nechám otevřená a přitom ty objekty zruším, aby to MDI umělo nějak poznat, že už nemá do čeho ukládat úpravy. 

Vyčlenil jsem z programu problémový úsek do zvláštního projektu a posílám kompletní zdroj:

https://www.navara.wz.cz/DELPHI/TestMDI.zip

Stačí vytvořit pár nových, v seznamu nalevo budou existující objekty vypsané, otevřít je pro úpravu, a přitom je smazat tlačítky na horní liště hl. okna. Když se následně provede uložení v těch MDI oknech, někdy se zobrazí chyba, někdy ne, a pokud se po vymazání provede aktualizace, v MDI oknech s takto neplatným odkazem se zobrazí nesmyslné hodnoty.

Nahlásit jako SPAM
IP: 37.77.244.–
JerryM0
Věrný člen
25. 3. 2023   #4
-
0
-

při kliknutí na odkaz mi to píše:

Varování: možné bezpečnostní riziko

Firefox zjistil možné ohrožení bezpečnosti a stránku na serveru www.navara.wz.cz nenačetl. Pokud se přesto rozhodnete stránku navštívit, útočníci se mohou pokusit zcizit vaše údaje jako např. hesla, e-mailové adresy nebo údaje o platební kartě.

Co s tím můžete dělat?

Příčina tohoto problému je pravděpodobně na straně serveru a vy ji bohužel nemůžete odstranit. Můžete o tomto problému informovat správce webu.

Zjistit více…

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:1ccd:71b:78d8:499d...–
JerryM0
Věrný člen
25. 3. 2023   #5
-
0
-

#3 Navara
no já myslim že je to stejný ne ? MDI má kontejner ve kterém jsou uložené všechny objekty, které si kdy do MDI vložil - protože MDI má víc oken, každé okno má svůj kontejner a v něm musíš zrušit tu vazbu na rušený objekt který si konkrétního kontejneru okna MDI vložil.

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:1ccd:71b:78d8:499d...–
Navara0
Návštěvník
25. 3. 2023   #6
-
0
-

Mně to tady občas píše že webzdarma nepodporuje https, ale stáhnout mně to šlo, zkoušel jsem to před odesláním.. ok - jinak: 

https://www.uschovna.cz/download/IKYTMJ2IJ676Y22E-LSY/GKP8CXGXY4/

Já měl za to, že když zruším nějaký objekt, tak všechny přímé odkazy na něj se automaticky změní na nil. Buďto jsem se mýlil nebo to dělám blbě. Zkus se na to, prosím, podívat - tady z Úschovny to snad pujde stáhnout v pohodě.

Jde jen o to, jak zareagovat zevnitř instance toho dialogu na to, že ten předaný odkaz už není platný. Zevnitř proto, že ta aplikace má různých MDI formulářů mnoho, objektů které jsou jim takto předávány je také spousta různých, a při každé změně celé té struktury prověřovat platnost všech odkazů by bylo nepřehledné a náchylné na chyby. 

Nahlásit jako SPAM
IP: 37.77.244.–
Řešení
JerryM0
Věrný člen
25. 3. 2023   #7
-
0
-
Vyřešeno Nejlepší odpověď

já už nemám RAD studio nainstalovaný ale tady je příklad

https://www.youtube.com/watch?v=LDWvSQMavdA

a NIL se opravdu dávat musí hned po smazání toho objektu co ho rveš do kontejneru nějakého okna MDI

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:1ccd:71b:78d8:499d...–
JerryM0
Věrný člen
25. 3. 2023   #8
-
0
-

a v jaký verzi RAD studia to děláš ?

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:1ccd:71b:78d8:499d...–
JerryM0
Věrný člen
25. 3. 2023   #9
-
0
-

když ten EXE spustim tak mě to chybu nehází .. mužu přidávat i ukládat i zavírat

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:1ccd:71b:78d8:499d...–
JerryM0
Věrný člen
25. 3. 2023   #10
-
0
-

a navíc reakce zevnitř instance uzavíraného dětského okna MDI je zachytitelná přes

https://docwiki.embarcadero.com/Libraries/Sydney/en/Vcl.Forms.TForm.OnClose

http://www.delphigroups.info/2/a5/409973.html

https://stackoverflow.com/questions/479208/how-do-i-gracefully-exit-a-mdi-form-that-has-code-executing-in-delphi

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:1ccd:71b:78d8:499d...–
Navara0
Návštěvník
25. 3. 2023   #11
-
0
-

#9 JerryM

Ano, takto to funguje bez problému.

Myslím že si pořád nerozumíme. Funguje to dobře - do chvíle, než ty MDI childy nechám otevřené pro úpravy, a stisknu nahoře Smazat vše. Ta okna zůstanou otevřená, a odkazují v proměnné ATratovaKolej na neplatné místo - a to v těch MDI childech chci odchytit. Nikoliv jejich zavírání, ale to že jsou otevřená pro upravování vlastností něčeho, co již neexistuje.

  • Vytvořit jeden nebo více instancí objektu TTratovaKolej.
  • Otevřít je pro úpravy v MDI formulářích.
  • Nechat je otevřené, a přitom stisknout nahoře Smazat vše. 
  • Teď bych předpokládal, že při použití tlačítka Uložit v tom MDI formuláři mi podmínka if Assigned(ATratovaKolej) vrátí false, ale vrací true. 

#5 JerryM
To bude asi řešení. Holt budu muset z destroy funkce objektu TTratovaKolej volat něco, co projde všechna MDI okna, a pokud najde v MDI ten konkrétní mazaný objekt, tak ho ručně překlopit na NIL (a třeba ten child rovnou zavřít). Tomuhle jsem se právě chtěl vyhnout, té ruční kontrole.

Předpokládal jsem (chybně) že se když použiju Smazat vše, stane se automaticky u všech MDI formulářů, (otevřených pro úpravu) z toho odkazu nil a bude mi stačit testovat v tom MDI jestli jeAssigned(ATratovaKolej).

#8 JerryM
Kdyby RAD... Delphi 7 SE (7.3.4.3, CnPack). Asi by stálo za úvahu trošku upgrade.

Nahlásit jako SPAM
IP: 83.136.207.–
JerryM0
Věrný člen
26. 3. 2023   #12
-
0
-

jo te´d sem to zkusil, takže když otevřu 4 okna a uložim je a pak je nechám otevřený a navíc otevřu jedno okno pro úpravy a pak stisknu "zavřít vše" tak se mi nic nezavře.

a k tomu náleží tenhle kod:

procedure TMainForm.SmazatVsechnyKoleje;
var
  AInt: Integer;
begin
  if Length(ArrTratoveKoleje) > 0 then
  begin
    for AInt := High(ArrTratoveKoleje) downto 0 do
    begin
      FreeAndNil(ArrTratoveKoleje[AInt]);
    end;
  end;
  SetLength(ArrTratoveKoleje, 0);
  VypsatKoleje();
end;

aha tak to bude asi blbě napsaný ...

jednak řádek
if Length(ArrTratoveKoleje) > 0 then
by měl bejt asi napsanej z principu napsanej obráceně:


if Length(ArrTratoveKoleje) = 0 then

  exit

end if

chápeš jo ?

a pak musíš procházet jedno okno po druhým a uzavírat ho samostatně příkazem Close a hlavně jestli v nějakým okně používáš nějaký data tak musíš při uzavírání uvolnit pamě´t ... to se dělá v tý metodě Closing , kterou má přidruženou každý MDI okno ...

a dále Delphi 7 SE (7.3.4.3, CnPack). :) :) :)  to je opravdu středověk :)

co třeba Delphi 10.3.3 ???
 

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:8044:3225:b968:6092...–
JerryM0
Věrný člen
26. 3. 2023   #13
-
0
-

magnet:?xt=urn:btih:D34F44A2270872A0D5C354C9820EFFD35C09C9F8&dn=Embarcadero+RAD+Studio+10.3.3+Rio+v26.0.36039.7899+Architect+%2B+Keygen+%5BFTUApps%5D&tr=udp%3A%2F%2Fopen.demonii.si%3A1337%2Fannounce&tr=udp%3A%2F%2Fp4p.arenabg.com%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.torrent.eu.org%3A451%2Fannounce&tr=udp%3A%2F%2Ftracker.cyberia.is%3A6969%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2710%2Fannounce&tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce&tr=udp%3A%2F%2Fexplodie.org%3A6969%2Fannounce&tr=udp%3A%2F%2Fdenis.stalker.upeer.me%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.tiny-vps.com%3A6969%2Fannounce&tr=udp%3A%2F%2Fipv4.tracker.harry.lu%3A80%2Fannounce&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=http%3A%2F%2Ftracker.openbittorrent.com%3A80%2Fannounce&tr=udp%3A%2F%2Fopentracker.i2p.rocks%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.internetwarriors.net%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Fcoppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.zer0day.to%3A1337%2Fannounce

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:8044:3225:b968:6092...–
Navara0
Návštěvník
26. 3. 2023   #14
-
0
-

#12 JerryM
navíc otevřu jedno okno pro úpravy a pak stisknu "zavřít vše" tak se mi nic nezavře.

 To je zhruba ten problém. Ta děcka se nezavřou - ono tam ani nic takového není, aby se zavřela. Mně šlo o to, jak zevnitř těch kontejnerů odchytit, že už není kam ukládat ty úpravy - zobrazení té hlášky "...neexistuje" (a případně je rovnou zavřít, což bych tam pak dopsal). 

Už jsem to vyřešil jinak, v destroy objektu koleje je doplněno volání aby se ty childy zavřely:

procedure TTratovaKolej.Destroy(); override;
begin
  MainForm.ZavritMDIPriRuseniKoleje(Self);
  inherited;
end;

A zavírací procedura vypadá nějak takhle:

procedure ZavritMDIPriRuseniKoleje(RusenaKolej: TTratovaKolej);
var
  iChild: Integer;
begin
  if Main.MDIFormCount = 0 
  then Exit;

  for iChild := Main.MDIFormCount -1 downto 0 do
  begin
    if Main.MDICHild[iOkno].ATratovaKolej = RusenaKolej then 
    begin
      Main.MDICHild[iOkno].ATratovaKolej := nil;
      Main.MDICHild[iOkno].Close();
    end;
  end;
end;

Zajímavé ale je, že když jsem to zkusil krokovat, a vyvolalo se toto uzavření, tak ve chvíli kdy jsem do ATratovaKolej vložil nil, projevilo se to i v tom poli ArrTratoveKoleje, v té položce kam ten odkaz vedl. 

Takže když udělám nad tím polem objektů FreeAndNil(ArrTratoveKoleje[index]), tak se NIL do odkazu v kontejneru childu nepřenese, ale když to udělám v tom MDI Childu, tak se to do toho pole přenese.

Length(ArrTratoveKoleje) > 0 není obráceně proto, že by se na konci neprovedlo VypsatKoleje, ale je fakt že k tomu se vlastně ten program nikdy nedostane, protože ať bych to smazal po jednom nebo všechny najednou, vždycky se na konci provede to vypsání. Nikdy by tak nemělo dojít k situaci kdy by bylo potřeba aktualizovat výpis přestože je pole předem prázdné. Upravil jsem.

Doplnil jsem to do ukázky, chová se to naprosto přesně jak má. Když se smaže kterákoliv položka v ArrTratoveKoleje (ať už jedna nebo všechny najednou), která je zároveň zavázaná do nějakého childu, tak se ten child zavře. Ostatní s nadále platnými odkazy (nebo pro vytváření nové položky) zůstanou otevřená. Takto jsem si to představoval. 

Každopádně je to vyřešené, funguje to jak má. Posílám odkaz, bohužel bude dostupný jen po omezenou dobu (proto jsem to předtím dával na své wz se záměrem to tam nechat "naneurčito", aby to bylo alespoň nějakou dobu dostupné i pro další čtenáře).

https://www.uschovna.cz/download/IL42KF5CGLEY8C76-WLA/P2ZMVLW2R7/

Nahlásit jako SPAM
IP: 37.77.244.–
JerryM0
Věrný člen
26. 3. 2023   #15
-
0
-

skvělé :)

https://uloz.to/file/CDRbUg5uNGvG/embarcadero-rad-studio-10-3-3-rio-v26-0-36039-7899-architect-keygen-password-is-admin-rar#!ZGSwZwR2AGMzLwIxATWxBQWuMTMzBRq2E05nEKAgowqYpmx4BD==

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:8044:3225:b968:6092...–
Navara0
Návštěvník
26. 3. 2023   #16
-
0
-

Táhnu táhnu popotahuji, zítra si s tím zkusím potykat a uvidíme co uvidíme. 

Děkuji za odkaz i za Tvůj čas při řešení celého tématu :) 

Nahlásit jako SPAM
IP: 37.77.244.–
JerryM0
Věrný člen
27. 3. 2023   #17
-
0
-

eště by bylo dobrý přečíst si tohle :)

https://en.wikipedia.org/wiki/Indentation_style

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:409c:997b:5ee1:8610...–
JerryM0
Věrný člen
29. 3. 2023   #18
-
0
-

https://uloz.to/file/tCsxJHmmf5bv/rad-studio-11-3-11-2-password-is-admin-rar#!ZGx4MGR2AQuvLwt1LzIxZwDlLwIuAKMvAJM3pH95EUOTBTMwMt==

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:488d:f3e8:50cd:8123...–
MilanL+1
Grafoman
3. 4. 2023   #19
-
0
-

#14 Navara
Ahoj, zase jsem týden nebyl, tak přicházím s křížkem po funuse.

Variantou by možná bylo vytvořit si v TTratovaKolej proměnou pro MDIchild, kam se při otevření uloží  a při zavření uvolní daná instance MDIchildu, pak ti při smazání stačí otestovat proměnou a v případě že existuje instance jí zavřít.

Budeš pak mít křížové propojení MDIchild Tratovou kolejí, kdy o soběbudou navzájem vědět.

S MDI jsem zatím nedělal, ale u jiného programu mi toto fungovalo na několik subformů.

Nahlásit jako SPAM
IP: 91.139.9.–
JerryM0
Věrný člen
3. 4. 2023   #20
-
0
-

jo jo kdo pozdě chodí sám sobě škodí :) :) :) :) 

Nahlásit jako SPAM
IP: 2a00:1028:83bc:e52a:c008:32a:cb43:9f7f...–
Navara0
Návštěvník
6. 4. 2023   #21
-
0
-

#19 MilanL
Ahoj,

tato varianta mě napadla taky, ale použít ji nelze (nebo alespoň ne takto). Objektů je tam struktura, která má až 5 úrovní, a může se tak stát že jeden objekt bude zavázaný ve více formulářích najednou. Ne tedy přímo pro úpravy, to lze dělat vždy jen jedním, ale - zkusím vysvětlit na příkladu.

Kdyby to byla například struktura zaměstnanců ve více firmách, tak tam bude figurovat pole objektu TSpolecnost, která má v sobě pole objektů TOddeleni, které má v sobě pole TZamestnanci. A teď když chci upravit nějakého zaměstnance, MDI formulář dostane odkazy na všechny tři objekty. MDI formulář pro oddělení bude mít dva (TSpolecnost, TOddeleni). Zamestnance lze otevřít všechny najednou, vedle toho lze otevřít v jiném MDI objekt TSpolecnost, v jiném zase TOddeleni.

Tzn. čím vyšší prvek struktury, tím spíše bude někdy zavázán ve více MDI formulářích současně, a musel by tak mít pro MDI ne jeden odkaz na instanci ale hned celé pole odkazů na instance. Je to také možnost, možná i jednodušší než tak jak to mám udělané teď. 

Nahlásit jako SPAM
IP: 185.75.139.–
MilanL+1
Grafoman
11. 4. 2023   #22
-
0
-

#21 Navara
zas trošku zpoždění jsem měl dovolenou.

No nevím jak to máš přesně řešené, ale vidím 1 podstatnou nevýhodu, v okamžiku kdy mažeš nějakou vyšší vrstvu, tak musíš ve všech těch úrovních procházet všechny podřízené objekty a pro všechny kontrolovat celé pole MDI.

Lze řešit společným předkem nebo použitím interface, při správném použití i rekurzívně.

Nahlásit jako SPAM
IP: 185.112.167.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 6 hostů

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý