Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - Close eines dynamisches TForm


ardely - Mo 04.03.13 10:37
Titel: Close eines dynamisches TForm
Guten Morgen,

Ich habe das Wochenende im Internet lange gesucht, allerdings ohne wirklichen Erfolg!
Meine Fragestellung ist bei der Erstellung eines dynamische Form, ich möchte gern mit der Mausetaste auf die Form anklicken, sodass die 'FormV' schließt.
Hier ist ein Beispiel, beim Kompilieren bekomme ich ein Error an dieser Stelle "FormV.OnClick := CloseMe;".


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
procedure ShowMyFormV;
var
 FormV: TForm;

procedure CloseMe(Sender: TObject);
begin
 // ShowMessage('Forme close..');
 close;
end;

begin

 FormV := TForm.Create(nil);
 try
  FormV.BorderStyle := bsDialog;
  FormV.Caption := 'My Dynamic Form!';
  FormV.Position := poScreenCenter;
  FormV.BorderStyle := bsNone;
  FormV.ClientWidth := 500;
  FormV.ClientHeight := 100;
  FormV.OnClick := CloseMe;  <-- Kompilier error 
  FormV.ShowModal;
 finally
  FormV.Free;
 end;

end;


Ich bedanke mich herzlich für hier Hilfe.
Grüsse.


Mathematiker - Mo 04.03.13 10:49

Hallo,
Deine Methode CloseMe muss zur Klasse TFormV gehören, d.h.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  TFormV = class(TForm
  ...
  ...
  private
    procedure CloseMe(Sender : TObject);
  published
  end;
und außerdem

Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TFormV.CloseMe(Sender: TObject);
begin
 // ShowMessage('Forme close..');
 close;
end;

Dann müsste es funktionieren.

Beste Grüße
Mathematiker


ardely - Mo 04.03.13 11:23

Ich habe noch immer Kompiler Error auf.

Delphi-Quelltext
1:
procedure FormV.CloseMe(Sender: Tobject);                    

Und zwar wenn ich die Procedure FormV.CloseMe() innerhalb der procedure 'procedure ShowMyFormV;' und oder ausserhalb der procedure 'procedure ShowMyFormV;' einsätze.
Der Error ist:
1.Undeclared identifier 'CloseMe' at line ...(für → FormV.OnClick := CloseMe;)
2.Unit1 doeas not contain a member named 'closeMe' at line … (für → procedure FormV.CloseMe(Sender: Tobject);)
Welchen Vorschlag kannst du mir noch geben?


WasWeißDennIch - Mo 04.03.13 11:44

Hast Du die Methode denn auch in der Formulardeklaration (interface-Abschnitt) eingefügt?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
type
  TForm1 = class(TForm)
    ...
  private
    (* Hier einfügen *)
    procedure CloseMe(Sender: TObject; var Action: TCloseAction);
    ...
  end;

Wenn man nun STRG-SHIFT-C drückt, fügt Delphi (allerdings nicht Starter) automatisch den entsprechenden Methodenrumpf in den Quelltext (implementation-Abschnitt) ein.

Delphi-Quelltext
1:
2:
3:
4:
procedure TForm1.CloseMe(Sender: TObject; var Action: TCloseAction);
begin

end;

Damit ist die Methode syntaktisch korrekt angelegt und kann zugewiesen werden.


ardely - Mo 04.03.13 12:19

Danke für Ihre Antwort, habe manches ausprobiert, leider bekomme ich das noch nicht hin!
So sieht die Unit aus, was könnte ich hier falsch gemacht habe?
Bekomme Kompiler Error : Incompatible types: method pointer and regular procedure (für-> FormV.OnClick := CloseMe; )

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
type
 TFormV = class(TForm)
 //..
 //..
  private
    { Private declarations }
  // procedure CloseMe(Sender: TObject);
 
 public
    { Public declarations }
 published

 end;

//..

type
 TForm1 = class(TForm)
 // .. 
 private
    { Private declarations }
 
  procedure CloseMe(Sender: TObject; var Action: TCloseAction);
  procedure ShowMyFormV;
 public
    { Public declarations }
 end;
//..
implementation

procedure Tform1.ShowMyFormV;
var
 FormV: TForm;

 // procedure CloseMe(Sender: TObject);
 // begin
 //  ShowMessage('Forme close..');
 //  close;
 // end;

begin

 FormV := TForm.Create(nil);
 try
  FormV.BorderStyle := bsDialog;
  FormV.Caption := 'My Dynamic Form!';
  FormV.Position := poScreenCenter;
  FormV.BorderStyle := bsNone;
  FormV.ClientWidth := 500;
  FormV.ClientHeight := 100;
  FormV.OnClick := CloseMe;  <-- Kompiler error 
  FormV.ShowModal;
 finally
  FormV.Free;
 end;
end;  

procedure Tform1.CloseMe(Sender: TObject);
begin
 // ShowMessage('Forme close..');
 close;
end;        
//..


WasWeißDennIch - Mo 04.03.13 12:25


Delphi-Quelltext
1:
procedure CloseMe(Sender: TObjectvar Action: TCloseAction);                    

So muss es auch implementiert sein.


ardely - Mo 04.03.13 12:53

Danke für deine Empfehlung, habe auch vorher so ausprobiert aber bekomme immer noch,
Kompiler Error: E2009 Incompatible type: Parameter lists differ.
Danke für Ihre Unterstützung.


WasWeißDennIch - Mo 04.03.13 13:00

Zitat:

Delphi-Quelltext
1:
2:
3:
4:
5:
procedure Tform1.CloseMe(Sender: TObject);
begin
 // ShowMessage('Forme close..');
 close;
end;

Wo ist da der Action-Parameter? Oder wie sieht der aktuelle Code jetzt aus?


ardely - Mo 04.03.13 13:17

So sieht die aktuelle Unit-code aus.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
unit Unit1;

interface

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

//-----------------------------------------
 type
 TFormV = class(TForm)
 //..
 //..
  private
    { Private declarations }
  // procedure CloseMe(Sender: TObject);
 public
    { Public declarations }
 published

 end;
//-----------------------------------------
type
 TForm1 = class(TForm)
 // ..
 private
    { Private declarations }
  procedure CloseMe(Sender: TObject; var Action: TCloseAction);
  procedure ShowMyFormV;
 public
    { Public declarations }
 end;

var
 Form1: TForm1;
implementation

{$R *.dfm}


procedure Tform1.ShowMyFormV;
var
 FormV: TForm;

{
// Nur hier ausprobiert ...
procedure  (Tform1.)CloseMe(Sender: TObject; var Action: TCloseAction);
begin
 ShowMessage('close ..');
  Action := caFree;
 // close;
end;
}


begin

 FormV := TForm.Create(nil);
 try
  FormV.BorderStyle := bsDialog;
  FormV.Caption := 'My Dynamic Form!';
  FormV.Position := poScreenCenter;
  FormV.BorderStyle := bsNone;
  FormV.ClientWidth := 400;
  FormV.ClientHeight := 200;
  FormV.OnClick := CloseMe;  <-- Kompiler error:  E2009 Incompatible type: Parameter lists differ.  
  FormV.ShowModal;
 finally
  FormV.Free;
 end;

end;

procedure Tform1.CloseMe(Sender: TObject; var Action: TCloseAction);
begin
 // ShowMessage('Forme close..');
 Action := caFree;
 // close;
end;

end.


WasWeißDennIch - Mo 04.03.13 14:02

*Aaahhhh* sry, mein Fehler :autsch: . Es geht ja um OnClick, nicht um OnClose, das sind unterschiedliche Event-Typen. Also, FormV soll bei Click geschlossen werden, richtig?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
type
  TForm1 = class(TForm)
  ...
  private
    procedure CloseMe(Sender: TObject);
  ...
  end;

procedure TForm1.CloseMe(Sender: TObject);
begin
  if Sender is TForm then
    TForm(Sender).Close;
end;

So sollte sich das auch zuweisen lassen.


ardely - Mo 04.03.13 15:22

Schade, dass du mein Jubel nicht gesehen hast, dass es genau so funktioniert wie ich mir das gewünscht habe, vielen Dank.
Mein procedure Name war vielleicht auch ein bisschen verwirrend...

Ich hätte nur noch eine letzte Frage um meine Erkenntnisse noch zu vertiefen.
Ist es möglich die 'procedure Tform1.CloseMe(Sender: Tobject);'
innen im Procedure ShowMyFormV einzubauen.
So etwas.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure Tform1.ShowMyFormV;
var
 FormV: TForm;

procedure  CloseMe(Sender: TObject);
begin
 if Sender is TForm then
    TForm(Sender).Close;
end;

begin

 FormV := TForm.Create(nil);
 try
// ..
  FormV.OnClick := CloseMe;
  FormV.ShowModal;
 finally
  FormV.Free;
 end;
end;


Ich habe verschiedene Möglichkeit ausprobiert ohne erfolg, aber ich bin nicht sicher, ob es überhaupt möglich ist!

Noch einmal großen Dank für deine vorherige Hilfe.


WasWeißDennIch - Mo 04.03.13 15:38

Nein, das geht so leider nicht. Eventhandlern können i.A. nur Methoden zugewiesen werden, d.h. sie müssen zu einer Klasse gehören.


bummi - Mo 04.03.13 17:53

Du kannst trotzdem in die Nähe des gewünschten gelangen

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
unit Unit1;

interface

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

type
  TDummyClass=Class(TObject)
    Class Procedure OnClose(Sender: TObject; var Action: TCloseAction);
  End;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  OnClose := TDummyClass.OnClose;
end;


{ TDummyClass }

class procedure TDummyClass.OnClose(Sender: TObject; var Action: TCloseAction);
begin
   Showmessage(TForm(Sender).Caption);
   Action := caFree;

end;

end.


WasWeißDennIch - Mo 04.03.13 18:34

Was der Code mit dem gewünschten zu tun haben soll, kann ich leider nicht erkennen. Dazu müsste man die Klasse samt Klassenmethode innerhalb der ShowMyFormV-Methode deklarieren und implementieren.


bummi - Mo 04.03.13 19:01

Ich will nicht schon wieder Haare zählen und Erbsen spalten ....

TDummyClass würde sich in einer Tools Unit befinden und die Class Procedure instanzlos wie eine "Prozedur" zugewiesen werden können, mit einem einheitlichen Verhalten, aber lassen wir eine eine weitere Vertiefung ....


WasWeißDennIch - Mo 04.03.13 19:13

Das war aber nicht die Frage ;)
Zitat:
Ist es möglich die 'procedure Tform1.CloseMe(Sender: Tobject);' innen im Procedure ShowMyFormV einzubauen.

Hat nun gar nix mit Erbsenzählerei zu tun, die kann ich nämlich auch nicht leiden.


bummi - Mo 04.03.13 19:48

OKOKOK, das hätte ich noch anzubieten ...


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
procedure TForm1.Button1Click(Sender: TObject);
begin
 ShowMyFormV;
end;

procedure Tform1.ShowMyFormV;
var
 FormV: TForm;
 Meth: TMethod;
procedure  CloseMe(DoNotUseSelf_ItsInvalid:Pointer;Sender: TObject);
begin
 Showmessage(Sender.ClassName);
 if Sender is TForm then
    TForm(Sender).Close;
end;

begin
 Meth.Data := nil;
 Meth.Code := @CloseMe;
 FormV := TForm.Create(nil);
 try
 FormV.OnClick := TNotifyEvent(Meth);
 FormV.ShowModal;

 finally
  FormV.Free;
 end;
end;


ardely - Mo 04.03.13 23:30

Hallo,
Genial, supergut deine Lösung, ich habe es sofort noch mit zusätzlich 'FormV.OnPaint :=' ausprobiert und es funktioniert sehr gut.
Und wollte noch als letzte hinzufügen 'FormV.OnMouseDown :=' und konfigurieren, das habe ich leider nicht hin bekommen.

Wie soll ich diese procedure FormMouseDown() umändern.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
//..
procedure  FormMouseDown( ????  Pointer; Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Sender is TForm then TForm(Sender).Close;
end;
//..
begin
 MethC.Data := nil;
 MethC.Code := @FormMouseDown;
 // ..
 FormV.OnMouseDown:= TNotifyEvent(MethC);
 //..


Ihr seid wirklich super, noch einmal vielen Dank.
Grüss


bummi - Mo 04.03.13 23:40

der Eventtyp passt nicht


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
procedure Tform2.ShowMyFormV;
var
 FormV: TForm;
 Meth: TMethod;
procedure  MouseDown(DoNotUseSelf_ItsInvalid:Pointer;Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 Showmessage(Format('%s x:%d y:%d',[Sender.ClassName,x,y]));
 if Sender is TForm then
    TForm(Sender).Close;
end;

begin
 Meth.Data := nil;
 Meth.Code := @MouseDown;
 FormV := TForm.Create(nil);
 try
 FormV.OnMouseDown := TMouseEvent(Meth);
 FormV.ShowModal;

 finally
  FormV.Free;
 end;
end;


WasWeißDennIch - Di 05.03.13 09:07

Ich frage mich ernsthaft nach dem Sinn des Ganzen, aber wenn der TE damit zufrieden ist, soll es mir auch egal sein.


ardely - Di 05.03.13 11:16

Echt klasse, an euch alle, für die Schnelle supergute hilfreiche Lösungen, bin jetzt gut vorwärtsgekommen, DANKE.
Grüss