Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Button Selbstzerstörung (https://www.delphipraxis.net/186338-button-selbstzerstoerung.html)

weisswe 25. Aug 2015 11:23

Button Selbstzerstörung
 
Hallo!

Habe folgende Aufgabenstellung:
a) Erstelle dynamische Buttons auf einem Layout
b) Beim Klick auf einen der neu generieren Buttons führe Schritt a) aus
Klar ist, das ich beim Freigeben auch den aktuell geklickten Button zerstören muss -> Exception -> logisch
Wie kann man das "umschiffen"?

Delphi-Quellcode:
type barray = Array of TButton;
var btns: barray;

procedure TForm1.abtnClick(Sender: TObject);
var i: Integer;
begin
   for i := length(btns) - 1 downto 0 do btns[i].Free;
   SetLength(btns, 0);
   for i := 0 to random(9) + 1 do
   begin
      btns[i] := TButton.Create(nil);
      btns[i].name := 'abutton' + IntToStr(i);
      btns[i].text := 'Button' + IntToStr(i+1);
      btns[i].Parent := GridLayout1;
      btns[i].OnClick := abtnClick;
   end;
end;

TiGü 25. Aug 2015 11:27

AW: Button Selbstzerstörung
 
Delphi-Quellcode:
if Sender = deinButton then
  NichtZerstören;

weisswe 25. Aug 2015 11:57

AW: Button Selbstzerstörung
 
Zitat:

Zitat von TiGü (Beitrag 1313419)
Delphi-Quellcode:
if Sender = deinButton then
  NichtZerstören;

Aber ich möchten ja auch den gedrückten Button zerstören!?

Der schöne Günther 25. Aug 2015 12:04

AW: Button Selbstzerstörung
 
Ich verstehe das hinten und vorne nicht. Ein OnClick-Event eines Buttons kann doch den Button ganz normal zerstören? Schreib doch einfach mal in das
Delphi-Quellcode:
OnClick
-Event eines normalen Buttons
Delphi-Quellcode:
Sender.Destroy()
. Wo soll denn da die Exception sein?

Wo ich eher eine Exception sehe ist hier:
Delphi-Quellcode:
   SetLength(btns, 0);
    for i := 0 to random(9) + 1 do
    begin
       btns[i] := TButton.Create(nil);
[...]
Wie soll das funktionieren? Du setzt das Array (unnötigerweise) auf Länge Null und fängst dann an, darin herumzuschreiben.

DeddyH 25. Aug 2015 12:14

AW: Button Selbstzerstörung
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1313427)
Ein OnClick-Event eines Buttons kann doch den Button ganz normal zerstören?

Diesem Gedankenfehler war ich neulich für ein FMX.TListViewItem auch erlegen. Das Dumme ist, dass dort ggf. der Click-Handler ausgeführt, danach aber mit der Instanz weiter hantiert wird. Letztere ist aber nicht mehr da, wenn sie im OnClick freigegeben wird -> *Rumms*.

stahli 25. Aug 2015 12:17

AW: Button Selbstzerstörung
 
Die OnClick-Behandlung veranlasst ja noch der Button selbst.
Nach Erledigung kommt der Programmablauf wieder zurück zum Button.
Was dann passiert kannst Du nicht beeinflussen. Vielleicht will Windows den Button jetzt nochmal zeichnen o.ä. - und plötzlich ist er weg ;-)
Also der bisherige Speicherbereich ist undefiniert.

Ein Workaround wäre, den Button unsichtbar zu machen und irgendwo zu merken (in einer Liste oder globalen Variable o.ä.).
Dann kannst Du etwas später, wenn mal Zeit ist (und Windows garantiert nicht mehr benutzt), diesen freigeben.
Also so etwas wie einen Papierkorb bauen, der immer mal geleert wird.

Sonst wäre auch möglich, eine Message an den Button zu senden, der ihn veranlasst, sich freizugeben.
Dazu gab es schon Beiträge in der DP.

Mavarik 25. Aug 2015 12:29

AW: Button Selbstzerstörung
 
Zitat:

Zitat von TiGü (Beitrag 1313419)
Delphi-Quellcode:
if Sender = deinButton then
  NichtZerstören;

Fast...

Delphi-Quellcode:
type barray = Array of TButton;
var btns: barray;

procedure TForm1.abtnClick(Sender: TObject);
var
  i: Integer;
  MichNicht:TButton;
begin
  for i := length(btns) - 1 downto 0 do
    if TButton(Sender) = self
      then btns[0] := btns[i]
      else btns[i].Free;

  for i := 1 to random(9) + 1 do
    begin
       btns[i] := TButton.Create(nil);
       btns[i].name := 'abutton' + IntToStr(i);
       btns[i].text := 'Button' + IntToStr(i+1);
       btns[i].Parent := GridLayout1;
       btns[i].OnClick := abtnClick;
    end;
end;
:stupid:

Sir Rufo 25. Aug 2015 12:43

AW: Button Selbstzerstörung
 
Mit dem IdleWorker (s. da -> http://www.delphipraxis.net/1305417-post11.html) geht das einfach so
Delphi-Quellcode:
uses
  IdleWorker;

procedure TForm1.abtnClick(Sender: TObject);
begin
  TIdleWorker.Default.Execute(
    procedure
    var
      i: Integer;
    begin
      // alte Buttons entsorgen
      for i := low(btns) to high(btns) do
        btns[i].Free; // ein DisposeOf wäre hier besser

      // neue Länge für das Array
      SetLength(btns, random(9) + 1 );

      // neue Buttons erzeugen
      for i := low(btns) to high(btns) do
      begin
        btns[i] := TButton.Create(nil);
        btns[i].name := 'abutton' + IntToStr(i);
        btns[i].text := 'Button' + IntToStr(i+1);
        btns[i].Parent := GridLayout1;
        btns[i].OnClick := abtnClick;
      end;
    end );
end;

weisswe 25. Aug 2015 12:50

AW: Button Selbstzerstörung
 
Zitat:

Zitat von Sir Rufo (Beitrag 1313437)
Mit dem IdleWorker (s. da -> http://www.delphipraxis.net/1305417-post11.html) geht das einfach so

Einfach nur perfekt!!! :thumb:

DANKE Sir Rufo!!!

Mavarik 25. Aug 2015 12:57

AW: Button Selbstzerstörung
 
Zitat:

Zitat von Sir Rufo (Beitrag 1313437)
Mit dem IdleWorker (s. da -> http://www.delphipraxis.net/1305417-post11.html) geht das einfach so

Logisch - vorausgesetzt die Application ist nicht anderweitig beschäftigt...

Sir Rufo 25. Aug 2015 13:03

AW: Button Selbstzerstörung
 
Zitat:

Zitat von Mavarik (Beitrag 1313442)
Zitat:

Zitat von Sir Rufo (Beitrag 1313437)
Mit dem IdleWorker (s. da -> http://www.delphipraxis.net/1305417-post11.html) geht das einfach so

Logisch - vorausgesetzt die Application ist nicht anderweitig beschäftigt...

Vor und nach einem Button-Click ist die Anwendung eigentlich eher nicht beschäftigt.

SvB 25. Aug 2015 13:44

AW: Button Selbstzerstörung
 
Ich vermisse irgendwie in der Aufgabestellung den Punkt c) gebe die Buttons manuell wieder frei.

Da der Parent gesetzt wird, werden dann nicht die Buttons auch freigegeben, wenn das GridLayout1 freigegeben wird? Dann brauche ich mich doch selbst nicht drum zu kümmern, oder?

SvB 25. Aug 2015 13:47

AW: Button Selbstzerstörung
 
OK, ich habs gerade kapiert, wenn ein Button gedrückt wird, dann sollen erst mal alle vorhandenen freigegeben werden und dann wieder neue erzeugt werden. Ich dachte erst es kommen immer nur welche dazu.

hoika 25. Aug 2015 21:51

AW: Button Selbstzerstörung
 
Hallo,
auch ein Timer löst das Problem.


Heiko

DeddyH 25. Aug 2015 21:54

AW: Button Selbstzerstörung
 
Oder eine selbstdefinierte Message, zumindest solange es sich um Singlethreading handelt.

hoika 25. Aug 2015 22:17

AW: Button Selbstzerstörung
 
Hallo,
ja, mit PostMessage würde das gehen.

Heiko

Sir Rufo 25. Aug 2015 22:45

AW: Button Selbstzerstörung
 
Zitat:

Zitat von hoika (Beitrag 1313493)
ja, mit PostMessage würde das gehen.

Wenn der Code nur für die Windows-Plattform gedacht ist, geht das irgendwie ... umständlich ... schon.

Habe ich mehrere Plattformen im Sinn, dann kann man natürlich für Windows weiterhin die Messages verwenden und für alle anderen den IdleWorker ... nun ja, oder einfach den IdleWorker und sich der nächsten Aufgabe widmen ;)

idefix2 25. Aug 2015 23:36

AW: Button Selbstzerstörung
 
Mir entgeht der Sinn der Übung.
Warum nicht einfach die Buttons, die man gerade nicht braucht, invisible setzen, statt ständig Buttons zu erzeugen und wieder zu vernichten?

Sir Rufo 26. Aug 2015 00:21

AW: Button Selbstzerstörung
 
Zitat:

Zitat von idefix2 (Beitrag 1313498)
Mir entgeht der Sinn der Übung.

Kleiner Hinweis: Es geht nicht primär um das Anzeigen von Buttons

Perlsau 26. Aug 2015 00:23

AW: Button Selbstzerstörung
 
Zitat:

Zitat von idefix2 (Beitrag 1313498)
Mir entgeht der Sinn der Übung.

... manchen leuten scheint vernichten eben einfach spass zu machen ...

IBExpert 26. Aug 2015 08:03

AW: Button Selbstzerstörung
 
einfachste Version: mach den Button selbstmord nicht im onClick, sondern im OnMouseUp/OnKeyUp
Die Exceptions kommen, weil normalerweise eben nach OnClick noch einige andere Events kommen, die dann bei bereits zerstörter Instanz knallen.

weisswe 26. Aug 2015 08:25

AW: Button Selbstzerstörung
 
Hallo!

Danke für die vielen Reaktionen. :wink:

Hier einige Details zu meinem Projekt und wofür ich das brauche:
- Firemonkey Desktop und Mobile App (XE8)
- dynamsiche virtuelle UI für verschiedene hierachische Layer (Erzeugung neuer) - ich nenne sie in der Datenbank allgemein "bubbles"
- das "Zerstören" hab ich sowieso nicht in einem OnClick-Event sondern in einem MouseUp-Event (brauch ich für die Toucheingabe -> speziell Win10 (LongPress))
- mein Beispiel hier ist eine sehr vereinfachte Darstellung des Problems
- Lösung wurde von Sir Rufo gegeben die bereits eingebaut ist und bestens funktioniert - Danke nochmal

idefix2 26. Aug 2015 08:56

AW: Button Selbstzerstörung
 
Zitat:

Zitat von Sir Rufo (Beitrag 1313502)
Zitat:

Zitat von idefix2 (Beitrag 1313498)
Mir entgeht der Sinn der Übung.

Kleiner Hinweis: Es geht nicht primär um das Anzeigen von Buttons

Ich verstehe schon, dass die Beantwortung der akademischen Frage, wie so ein Problem zu lösen ist, vielleicht in ganz speziellen Konstellationen relevant sein kann - mir fallen aber eigentlich keine Anwendungen dafür ein.

Bei der geschilderten Aufgabe halte ich es jedenfalls nicht für zielführend, ständig Buttons zu zerstören und neu zu erstellen. Es wäre hier meines Erachtens eben wesentlich gescheiter, mit einem Feld von vorher erstellten Buttons zu operieren (oder, falls keine sinnvolle Maximalzahl angegeben werden kann, die Buttons bei Bedarf on the Fly zu erstellen, wenn keine unsichtbaren Buttons mehr in Reserve sind), die je nach Bedarf angezeigt werden oder nicht.

idefix2 26. Aug 2015 09:01

AW: Button Selbstzerstörung
 
Zitat:

Zitat von Perlsau (Beitrag 1313504)
... manchen leuten scheint vernichten eben einfach spass zu machen ...

In den Spiegel geschaut?

weisswe 26. Aug 2015 09:15

AW: Button Selbstzerstörung
 
Ok - noch ein paar Infos.

Es handelt sich nicht um "gewöhnliche Buttons" die ich dynamisch erstellen muss, sondern um irgendwelche Objekte.
Da gibt es keine maximale Anzahl statischer Objekte.
Die Objekte sind z.b. Häuser, Bäume, Autos
In einem anderen Fall Sonnensysteme, Planeten, Monde
Oder auch nur Kreise, Rechtecke, Linien, ...

Darum nenne ich sie allgemein Bubbles... :cyclops:

BUG 26. Aug 2015 09:34

AW: Button Selbstzerstörung
 
Zitat:

Zitat von weisswe (Beitrag 1313524)
irgendwelche Objekte ... Darum nenne ich sie allgemein Bubbles... :cyclops:

Objects wäre auch zu einfach :stupid:

idefix2 26. Aug 2015 10:32

AW: Button Selbstzerstörung
 
Zitat:

Es handelt sich nicht um "gewöhnliche Buttons" die ich dynamisch erstellen muss, sondern um irgendwelche Objekte.
Auch da wäre zu überlegen, ob es nicht besser wäre, die Objekte (Nachdem sie auf der Form dargestellt werden, gehe ich davon aus, dass sie alle von TControl abgeleitet sind, und es gibt wohl nur eine begrenzte Anzahl von Varianten), die man nicht mehr braucht, auf Reserve vorzuhalten, statt sie zu zerstören:

Delphi-Quellcode:
Type

Form1=class(Tform)
  private
  FObjects: array of TControl;

...

function Form1.Newcontrol (Typ: TControlClass): TControl;
var
  l: integer;
  o: TControl;
begin
for o in FObjects do
    if not o.visible and (o is Typ)
    then begin
         o.Visible:=true;
         result:=o;
         exit;
         end;
result:=Typ.Create(self);
result.Parent:=self;
l:=length(FObjects);
setlength(FObjects, l+1);
FObjects[l]:=result;
end;
und die Controls, die man gerade nicht braucht, statt zu löschen, einfach invisible setzen.

stahli 26. Aug 2015 11:54

AW: Button Selbstzerstörung
 
Das muss nicht der bessere Ansatz sein.

Wenn Du jetzt 1 Button und 20 Labels hast und in der nächsten Darstellung 1 Label und 20 Buttons und in der nächsten Darstellung 10 Checkboxen und 1 Edit würde es einen unnötigen Aufwand mit sich bringen, die aussortierten Controls ständig weiter mitzuschleppen und zu behandeln.
Wenn man z.B. ein Control sucht muss man ggf. auch nochmal die Karteileichen überprüfen.

Es gibt natürlich Anwendungsfälle, wo solch eine Pufferung sinnvoll ist, aber ganz generell kann man das sicher nicht sagen.

idefix2 26. Aug 2015 12:52

AW: Button Selbstzerstörung
 
Zitat:

Zitat von stahli (Beitrag 1313543)
Das muss nicht der bessere Ansatz sein.

Stimmt, muss nicht:
Zitat:

Zitat von idefix2 (Beitrag 1313529)
Auch da wäre zu überlegen, ob es nicht besser wäre, ...


himitsu 27. Aug 2015 14:28

AW: Button Selbstzerstörung
 
Wie war das nochmal?
Säge nicht den Ast ab, auf dem du grade sitzt?

Delphi-Referenz durchsuchenCM_RELEASE
Einfach mal bei TForm abgucken, den Button ableiten und es dort implementieren.
(wäre auch zu einfach gewesen, wenn Emba das einfach bereits ins TComponent/TControl/TWinControl implementiert hätte)


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:42 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz