Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - eigenes objekt->procedure zuweisen
covel - Mi 12.07.06 11:11
Titel: eigenes objekt->procedure zuweisen
Moin, komme mal wieder nicht weiter!!
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| btn_close:= TButton.Create(form1); with btn_close do begin parent:=test; width:=10; height:=10; top:=0; left:=90; OnClick:=Close; <- Hier möchte ich dem btn_close eine procedure zuweisen!! Wird auch gemacht nur es wird kein Parameter übergeben! end; |
Hoffe es kann mir jemand helfen!
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: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143:
| unit objekte;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls,unit1;
type TAuto= class(TObject) fx:Integer; fy:Integer; test:TPanel; btn_close:TButton; constructor Create; destructor destroy;
procedure ControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;X, Y: Integer); procedure ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure ControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure close(Sender:TObject); end;
implementation var
inReposition : boolean; oldPos : TPoint; Sender:TPanel;
constructor TAuto.Create; begin inherited; test := TPanel.Create(form1); with test do begin Visible :=true; Parent:=form1; Width :=100; Height :=100; onMouseDown:=ControlMouseDown; OnMouseUp:=ControlMouseUp; OnMouseMove:=ControlMouseMove; end; inherited; btn_close:= TButton.Create(form1); with btn_close do begin parent:=test; width:=10; height:=10; top:=0; left:=90; OnClick:=Close; end;
end;
destructor TAuto.Destroy; begin btn_close.Free; test.free; inherited; end;
procedure TAuto.close(Sender:TObject); begin TPanel(sender).Caption :='test'; end;
procedure TAuto.ControlMouseUp( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if inReposition then begin Screen.Cursor := crDefault; ReleaseCapture; inReposition := False; end; end;
procedure Tauto.ControlMouseMove( Sender: TObject; Shift: TShiftState; X, Y: Integer); const minWidth = 20; minHeight = 20; var newPos: TPoint; frmPoint : TPoint; begin if inReposition then begin with TWinControl(Sender) do begin GetCursorPos(newPos);
if ssShift in Shift then begin Screen.Cursor := crSizeNWSE; frmPoint := ScreenToClient(Mouse.CursorPos); if frmPoint.X > minWidth then Width := frmPoint.X; if frmPoint.Y > minHeight then Height := frmPoint.Y; end else begin Screen.Cursor := crSize; Left := Left - oldPos.X + newPos.X; Top := Top - oldPos.Y + newPos.Y; oldPos := newPos; end; end; end; end;
procedure TAuto.ControlMouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if(Sender is TWinControl) then begin inReposition:=True; SetCapture(TWinControl(Sender).Handle); GetCursorPos(oldPos); end; end;
end. |
Moderiert von
Christian S.: Delphi-Tags hinzugefügt
crowley - Mi 12.07.06 11:35
schau dir noch mal deine Close-Procedure an:
du weist einem Button die Close-Procedure für das OnClick- Event zu... in der Procedure selber greifst du aber auf TPanel(Sender) zu, das kann nicht funktionieren, da der Sender dein Button ist. Wenn, muss es an der Stelle entweder TButton(Sender).Caption oder test.Caption heissen, je nachdem, in welches Caption du nun was schreiben willst.
covel - Mi 12.07.06 11:48
ohh, da habe ich was übersehen, es funkt. nun. besten dank
crowley - Mi 12.07.06 11:59
vielleicht täusche ich mich ja, aber hatten wir nicht in einem ähnlichen Thread von dir schon mal gesagt, dass du deine Klasse vielleicht von TPanel und nicht von TObject ableiten solltest?
desweiteren solltest du vermeiden, ggf. zentral vorbelegte Procedure- Namen zu mißbrauchen (Close ist quasi mehrfach vorbelegt... nenne es vielleicht besser: BtnClose oder noch besser BtnCloseClick).
Wird dein ButtonClick eigentlich überhaupt aufgerufen? Habe die Befürchtung, dass du mit deinem
ControlMouseDown bzw. ControlMouseUp das schon abfängst bzw. nicht entsprechend weiterleitest.
Was soll eigentlich deine globale Variable Sender? Schmeiss die mal lieber weg... kann sein, dass die die Wurzel allen Übels ist und anstatt auf den Parameter Sender im Close greift dein Close auf die nicht initialisierte Variable Sender zu.
covel - Mi 12.07.06 14:08
Jo, habe vor ein paar tagen etwas ähnliches gepostet!!! Habe deine Tips bis auf das Objekt als TPanel zudeklarieren befolgt!
Habe jedoch wieder ein Problem :-( Wenn ich zwei Instanzen erzeugt habe, kann ich das erste Objekt also Auto1 löschen ohne Fehlermeldung wenn ich aber Auto2 per btncloseclick löschen will kommt immer eine EAccessViolation Exeption!!!
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: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145:
| unit objekte;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls,unit1;
type TAuto= class(TObject) fx:Integer; fy:Integer; test:TPanel; btn_close:TButton; constructor Create(AOwner: TComponent); destructor destroy;
procedure ControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;X, Y: Integer); procedure ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure ControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure BtnCloseClick(Sender:TObject); end;
implementation var
inReposition : boolean; oldPos : TPoint; constructor TAuto.Create; begin test := TPanel.Create(form1); with test do begin Visible :=true; Parent:=form1; Width :=100; Height :=100; onMouseDown:=ControlMouseDown; OnMouseUp:=ControlMouseUp; OnMouseMove:=ControlMouseMove; end; btn_close:= TButton.Create(form1); with btn_close do begin parent:=test; width:=10; height:=10; caption:= 'x'; top:=0; left:=90; OnClick:=BtnCloseClick; end;
end;
destructor TAuto.Destroy; begin btn_close.Free; inherited; end;
procedure TAuto.BtnCloseClick(Sender:TObject); begin TButton(sender).parent.free; inherited; end;
procedure TAuto.ControlMouseUp( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if inReposition then begin Screen.Cursor := crDefault; ReleaseCapture; inReposition := False; end; end;
procedure Tauto.ControlMouseMove( Sender: TObject; Shift: TShiftState; X, Y: Integer); const minWidth = 20; minHeight = 20; var newPos: TPoint; frmPoint : TPoint; begin if inReposition then begin with TWinControl(Sender) do begin GetCursorPos(newPos);
if ssShift in Shift then begin Screen.Cursor := crSizeNWSE; frmPoint := ScreenToClient(Mouse.CursorPos); if frmPoint.X > minWidth then Width := frmPoint.X; if frmPoint.Y > minHeight then Height := frmPoint.Y; end else begin Screen.Cursor := crSize; Left := Left - oldPos.X + newPos.X; Top := Top - oldPos.Y + newPos.Y; oldPos := newPos; end; end; end; end;
procedure TAuto.ControlMouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if(Sender is TWinControl) then begin inReposition:=True; SetCapture(TWinControl(Sender).Handle); GetCursorPos(oldPos); end; end;
end. |
jakobwenzel - Mi 12.07.06 14:11
Kanns sein, dass du Auto2 als
initialisierst?
covel - Mi 12.07.06 14:23
nein, sodern mit
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| uses objekte; {$R *.dfm}
var auto1,auto2:Tauto;
procedure TForm1.Panel1Click(Sender: TObject); begin Auto1:=TAuto.Create(self);Auto2:=TAuto.Create(self); end; |
oder ist das dass gleiche wie auto2:=auto1;?
crowley - Mi 12.07.06 14:28
nein... die wurzel des bösen ist, dass du nur EINEN button erzeugst...
du erzeugst ihn ja immer mit
Delphi-Quelltext
1:
| btn_close := TButton.Create(form1); |
Dabei soll der Owner des Buttons nicht das Form sondern dein Auto sein, oder ? dadurch erzeugst du eine Instanz deines btn_close nach der anderen, aber du hast immer nur den zuletzt erzeugten... gibst du diesen frei, hast du keinen button mehr, auf den du zugreifen kannst... dafür aber noch viele im speicher!
desweiteren... kann ich anfangen zu schreien, wenn ich in einem constructor eines Objektes sowas lese
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:
| constructor TAuto.Create; begin test := TPanel.Create(form1); with test do begin Visible :=true; Parent:=form1; Width :=100; Height :=100; onMouseDown:=ControlMouseDown; OnMouseUp:=ControlMouseUp; OnMouseMove:=ControlMouseMove; end; btn_close:= TButton.Create(form1); with btn_close do begin parent:=test; width:=10; height:=10; caption:= 'x'; top:=0; left:=90; OnClick:=BtnCloseClick; end; end; |
Du setzt damit voraus, dass bei der Verwendung von der Klasse TAuto IMMER ein form1 vorhanden ist! lass das form1 da weg! entweder packst du da nil rein... oder Self... oder du solltest da definitiv ein Panel draus machen, dann brauchst du auch dein test nicht mehr! Im constructor solltest du als ERSTES immer das inherited Create; aufrufen.
Desweiteren solltest du auch im destructor auch test freigeben...
_frank_ - Mi 12.07.06 14:32
nein, ist nicht das gleiche...hast es schon richtig gemacht.
bei Auto2:=auto1; kopierst du nur den Pointer, d.h. es zeigen beide variablen auf 1 Objekt. wenn du es freigibst, sind beide Pointer (da gleich) ungültig.
Create erstellt ein neues Objekt und gibt den Pointer zurück, welchen du deiner variablen zuweist.
Gruß Frank
covel - Mo 17.07.06 09:51
So ich erzeuge nun die Buttons als Array, kann die einzelnen Panels aber immer noch nicht über Btn_close löschen.
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: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142:
| unit objekte;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls,unit1;
type
TAuto= class(TObject) fx:Integer; fy:Integer; test:Array[0..10] of TPanel; btn_close:Array [0..10] of TButton; constructor Create(AOwner: TComponent);
procedure ControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;X, Y: Integer); procedure ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure ControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure BtnCloseClick(Sender:TObject); end;
implementation var inReposition : boolean; oldPos : TPoint; x,y: integer;
constructor TAuto.Create; begin test[x] := TPanel.Create(nil); with test[x] do begin Visible :=true; Parent:=form1; Width :=100; Height :=100; onMouseDown:=ControlMouseDown; OnMouseUp:=ControlMouseUp; OnMouseMove:=ControlMouseMove; caption:= inttostr(x); end;
btn_close[y]:= TButton.Create(nil); with btn_close[y] do begin parent:=test[x]; width:=10; height:=10; caption:= 'x'; top:=0; left:=90; OnClick:=BtnCloseClick; end; inc(x); inc(y); end;
procedure TAuto.BtnCloseClick(Sender:TObject); begin TButton(sender).destroy; inherited; end;
procedure TAuto.ControlMouseUp( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if inReposition then begin Screen.Cursor := crDefault; ReleaseCapture; inReposition := False; end; end;
procedure Tauto.ControlMouseMove( Sender: TObject; Shift: TShiftState; X, Y: Integer); const minWidth = 20; minHeight = 20; var newPos: TPoint; frmPoint : TPoint; begin if inReposition then begin with TWinControl(Sender) do begin GetCursorPos(newPos);
if ssShift in Shift then begin Screen.Cursor := crSizeNWSE; frmPoint := ScreenToClient(Mouse.CursorPos); if frmPoint.X > minWidth then Width := frmPoint.X; if frmPoint.Y > minHeight then Height := frmPoint.Y; end else begin Screen.Cursor := crSize; Left := Left - oldPos.X + newPos.X; Top := Top - oldPos.Y + newPos.Y; oldPos := newPos; end; end; end; end;
procedure TAuto.ControlMouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if(Sender is TWinControl) then begin inReposition:=True; SetCapture(TWinControl(Sender).Handle); GetCursorPos(oldPos); end; end;
end. |
crowley - Mo 17.07.06 10:10
Was hältst du davon ?
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:
| unit objekte;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls;
type
TAuto= class(TObject) fx:Integer; fy:Integer; test:TPanel; btn_close:TButton; constructor Create(AOwner: TComponent); destructor destroy; procedure BtnCloseClick(Sender:TObject); end;
implementation var inReposition : boolean; oldPos : TPoint;
constructor TAuto.Create(AOwner: TComponent); begin inherited Create;
test := TPanel.Create(Self); with test do begin Visible := true; Parent := AOwner; Width := 100; Height := 100; onMouseDown:=ControlMouseDown; OnMouseUp:=ControlMouseUp; OnMouseMove:=ControlMouseMove; end;
btn_close := TButton.Create(test); with btn_close do begin parent:=test; width:=10; height:=10; caption:='x'; top:=0; left:=90; OnClick:=BtnCloseClick; end; end;
destructor TAuto.Destroy; begin test.free; btn_close.free;
inherited; end;
procedure TAuto.BtnCloseClick(Sender:TObject); begin Close; end;
end. |
Noch einmal: Leite dir TAuto von TPanel ab. Desweiteren kannst du in einer Ereignis-Routine die aufrufende Komponente nicht freigeben. Das gibt dir immer einen Zugriffsfehler, da diese Komponente ja quasi "noch in Benutzung" ist. Dein Code ist seeeehr fehleranfällig, so wie du ihn da zusammenbaust... und noch etwas: benutze den destructor, da solltest du ALLE im Panel integrierten Komponenten frei geben.
covel - Mo 17.07.06 11:01
wie leite ich TAuto den von TPanel genau ab?? Bei deinem Quellcode bekommen ich ne fehlermeldung
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| test := TPanel.Create(self); with test do begin Visible := true; Parent := AOwner; Width := 100; Height := 100; onMouseDown:=ControlMouseDown; OnMouseUp:=ControlMouseUp; OnMouseMove:=ControlMouseMove; end; |
crowley - Mo 17.07.06 11:10
Ist gar nicht mal so schwer ;)
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: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122:
| unit objekte; interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls; type TAuto= class(TPanel) fx:Integer; fy:Integer; btn_close:TButton; constructor Create(AOwner: TComponent); destructor destroy; procedure BtnCloseClick(Sender:TObject); procedure ControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;X, Y: Integer); procedure ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure ControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); end;
implementation var inReposition : boolean; oldPos : TPoint; constructor TAuto.Create(AOwner: TComponent); begin inherited Create(AOwner);
Visible := true; Width := 100; Height := 100; OnMouseDown:=ControlMouseDown; OnMouseUp:=ControlMouseUp; OnMouseMove:=ControlMouseMove;
btn_close := TButton.Create(Self); with btn_close do begin parent:=Self; width:=10; height:=10; caption:='x'; top:=0; left:=90; OnClick:=BtnCloseClick; end; end;
destructor TAuto.Destroy; begin btn_close.free; inherited; end; procedure TAuto.BtnCloseClick(Sender:TObject); begin Self.Free; end;
procedure TAuto.ControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if inReposition then begin Screen.Cursor := crDefault; ReleaseCapture; inReposition := False; end; end;
procedure TAuto.ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); const minWidth = 20; minHeight = 20; var newPos: TPoint; frmPoint : TPoint; begin if inReposition then begin with TWinControl(Sender) do begin GetCursorPos(newPos);
if ssShift in Shift then begin Screen.Cursor := crSizeNWSE; frmPoint := ScreenToClient(Mouse.CursorPos); if frmPoint.X > minWidth then Width := frmPoint.X; if frmPoint.Y > minHeight then Height := frmPoint.Y; end else begin Screen.Cursor := crSize; Left := Left - oldPos.X + newPos.X; Top := Top - oldPos.Y + newPos.Y; oldPos := newPos; end; end; end; end; procedure TAuto.ControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if(Sender is TWinControl) then begin inReposition:=True; SetCapture(TWinControl(Sender).Handle); GetCursorPos(oldPos); end; end; end. |
covel - Mo 17.07.06 11:30
bekomme ne fehlermeldung bei
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| TAuto= class(TPanel) fx:Integer; <---[Fehler] objekte.pas(193): Das Published-Feld 'fx' ist weder vom Typ class noch interface fy:Integer; <---[Fehler] objekte.pas(194): Das Published-Feld 'fy' ist weder vom Typ class noch interface btn_close:TButton; constructor Create(AOwner: TComponent); destructor destroy; |
habe die zeilen gelöscht!
Jedoch wenn ich nun mit
Delphi-Quelltext
1: 2: 3: 4:
| procedure TForm1.Panel1Click(Sender: TObject); begin Auto1:=TAuto.Create(self); end; |
Auto1 erzeugen will wird es mir auf der Form1 nicht angezeigt!! Muss ich nen parent setzen?ß
Grüße Michael
crowley - Mo 17.07.06 11:40
Mein Fehler:
du solltest in einem Objekt/Klasse/Komponente immer zwischen private/public/published- properties/procedure etc differenzieren. fx, fy hattest du ja gar nicht benutzt, warum somit sowieso überflüssig.
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:
| type TAuto= class(TPanel) private btn_close:TButton; procedure BtnCloseClick(Sender:TObject); procedure ControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;X, Y: Integer); procedure ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure ControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); public constructor Create(AOwner: TComponent); destructor destroy; end;
implementation
constructor TAuto.Create(AOwner: TComponent); begin inherited Create(AOwner);
Parent := AOwner; Visible := true; Width := 100; Height := 100; OnMouseDown:=ControlMouseDown; OnMouseUp:=ControlMouseUp; OnMouseMove:=ControlMouseMove; |
covel - Mo 17.07.06 11:44
Noch nen Fehler :-(
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| constructor TAuto.Create(AOwner: TComponent); begin inherited Create(AOwner); Parent := AOwner; <---[Fehler] objekte.pas(214): Inkompatible Typen: 'TWinControl' und 'TComponent' Visible := true; left:=10; top:=10; Width := 100; Height := 100; OnMouseDown:=ControlMouseDown; OnMouseUp:=ControlMouseUp; OnMouseMove:=ControlMouseMove; |
crowley - Mo 17.07.06 12:09
tu mir mal einen gefallen und poste mal deine ganze unit (oder pack mir das ganze projekt mal in eine zip datei)... mit dieser flickenarbeit kommen wir ja nicht wirklich voran ;)
C.
covel - Mo 17.07.06 12:16
here it is!! Erstmal besten dank das du dir so viel mühe gibst!!!!
crowley - Mo 17.07.06 12:35
momentan ist unsere firmenfirewall auf "paranoid" eingestellt und ich kann die datei von hier aus nicht herunterladen. ich schau mir das heute abend mal von zuhause an.
hoffe, du kannst noch so lange warten ;)
C.
covel - Mo 17.07.06 12:38
alles klar ich warte :-)
crowley - Mo 17.07.06 21:11
ich habe ein paar kleine veränderungen an dem quelltext vorgenommen, aber nach wie vor gilt: du kannst eine komponente nicht in einer ihrer eigenen ereignisroutinen freigeben.
dafür müsstest du dir noch eine andere lösung einfallen lassen...
covel - Do 20.07.06 09:42
sry das ich mich erst so spät melde. funktioniert alles super!! aber wie kann ich die Panels wieder löschen?? Ich könnte es per timer oder über nen extra button realisieren! Denke mal die timer lösung ist nicht sehr elegant. Könnte ich das Problem auch mit Threads lösen?
grüße michael
crowley - Do 20.07.06 09:46
hm... du könntest deinem Auto ein eigenes Event spendieren (sowas wie "ButtonClick")... und das rufst du aus dem Programm heraus auf (nicht innerhalb der Komponente).
Da drin machst du dann dein "free".
covel - Fr 21.07.06 10:08
könntest du mir noch nen tip geben?? weiß nicht so recht wie ich anfangen soll.
freak4fun - Fr 21.07.06 10:40
Hallo,
ich hab auch mal mein Glück versucht. Du hast noch einige sehr unschöne Sachen drin, wie globale Variablen. *schüttel* Aber das wird schon. ;)
Ich hoffe das hilft dir weiter.
MfG
freak 8)
covel - Fr 21.07.06 10:46
leider hilft mir das nicht weiter, da beim löschen des Panels immer noch eine Fehlermeldung kommt.
freak4fun - Fr 21.07.06 11:05
Welche Fehlermelfung bekommst du denn? Ich hatte mit meinem Code keine Probleme. Wäre auch noch interessant an welcher Stelle. ;)
MfG
freak
covel - Fr 21.07.06 11:30
Der Fehler: ist eine Exception der Klasse EAccessViolation aufgetreten.
Der Fehler passiert in folgendem Quellcode. Denke mal es liegt daran das ich das Panel und den Button löschen will während dieser die Lösch-Aktion noch ausführt.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| destructor TAuto.Destroy; begin btn_close.free; inherited; end;
procedure TAuto.BtnCloseClick(Sender:TObject); begin Self.Free; end; |
Ich müßte beim BtnCloseClick nen timer aufrufen, welcher als Parameter den namen des PAnel übergibt. Weiß aber nicht wie das gehen soll.
covel - Fr 21.07.06 13:55
das hat sehr geholfen!!! Nur wird das Panel auf dem der Button erstellt worde ist nicht mitgelöscht. Ist klar warum!! Wie kann ich aber das problem lösen ??
Rufe den Code wie folgt auf :
Delphi-Quelltext
1: 2: 3: 4:
| procedure TAuto.BtnCloseClick(Sender:TObject); begin PostMessage(Self.Handle, WM_KILL_CONTROL, 0, Integer(Sender)); end; |
erstellt wird das objekt wie folgt:
Delphi-Quelltext
1: 2: 3:
| Auto1 := TAuto.Create(self); Auto2 := TAuto.Create(self); Auto3 := TAuto.Create(self); |
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| type TAuto= class(TPanel) private btn_close:TButton; procedure BtnCloseClick(Sender:TObject); procedure ControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;X, Y: Integer); procedure ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure ControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
public procedure WMKillControl(var msg:TMessage); message WM_KILL_CONTROL; constructor Create(AOwner: TComponent); override; destructor Destroy; override; end; |
freak4fun - Fr 21.07.06 15:27
Ich hab es mit
Delphi-Quelltext
1:
| PostMessage(Parent.Handle, WM_KILL_CONTROL, 0, Integer(Sender)); |
versucht, aber das gibt wieder eine Exception. :( Kannst du nicht auf den Schließen-Button verzichten und den Code direkt für das Panel benutzen? Oder ist das onClick schon belegt?
//edt: Versuch mal:
Delphi-Quelltext
1:
| PostMessage(Self.Handle, WM_KILL_CONTROL, 0, Integer((Sender as TButton).Parent)); |
MfG
freak
covel - Mo 24.07.06 08:21
So das mit:
Delphi-Quelltext
1:
| PostMessage(Self.Handle, WM_KILL_CONTROL, 0, Integer((Sender as TButton).Parent)); |
hat geklappt. Jedoch werden die Variablen Auto1, Auto2... nicht wieder freigegeben. Wie kann ich diese nun mit freigeben?? Habe es mit FreeAndNil(self) versucht, bekomme jedoch eine Exception.
freak4fun - Mo 24.07.06 09:21
Wenn du das Auto.Create(Self); aufrifst wird als owner das Form gesetzt. Also wird das Objekt Auto freiigegegeben, wenn das Formular freigegeben wird. Bei FreeAndNil(); würde ich Auto als Parameter übergeben. Denn wenn du FreeAndNil(Self); in den Destructor von Autoschreibst wird dadurch der Destructor wieder aufgerufen. ;) Das ist sowieso recht tricky, was du da machst. An welcher Stelle steht dein FreeAndNil(Self);?
MfG
freak
covel - Mo 24.07.06 10:00
Delphi-Quelltext
1: 2: 3: 4: 5:
| destructor TAuto.Destroy; begin inherited Destroy; end; |
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: 81: 82:
| unit objekte;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, unit1, Dialogs, ExtCtrls, StdCtrls;
const WM_KILL_CONTROL = WM_USER+ 66;
type TAuto= class(TPanel) private btn_close:TButton; procedure BtnCloseClick(Sender:TObject); procedure ControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;X, Y: Integer); procedure ControlMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure ControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
public procedure WMKillControl(var msg:TMessage); message WM_KILL_CONTROL; constructor Create(AOwner: TComponent); override; destructor Destroy; override; end;
implementation var inReposition : boolean; oldPos : TPoint;
procedure TAuto.WMKillControl(var msg: TMessage); var c : TControl; i : Integer; begin c := TControl(msg.LParam); if not Assigned(c) then Exit; c.Free; windows.MessageBeep($FFFFFFFF); end;
constructor TAuto.Create(AOwner: TComponent); begin inherited Create(AOwner); Parent := TWinControl(AOwner); Visible := true; left:=10; top:=10; Width := 100; Height := 100; OnMouseDown:=ControlMouseDown; OnMouseUp:=ControlMouseUp; OnMouseMove:=ControlMouseMove;
btn_close := TButton.Create(Self); with btn_close do begin parent:=Self; width:=10; height:=10; caption:='x'; top:=0; left:=90; OnClick:=BtnCloseClick; end; end;
destructor TAuto.Destroy; begin inherited Destroy; end;
procedure TAuto.BtnCloseClick(Sender:TObject); begin PostMessage(Self.Handle, WM_KILL_CONTROL, 0, Integer((Sender as TButton).Parent)); end; |
freak4fun - Mo 24.07.06 10:08
Ich denke es reicht, wenn du deine Atoobjekte im Destructor des Formulars frei gibst. :)
covel - Mo 24.07.06 10:22
Wenn ich das richtig verstehe soll ich Auto1,Auto2... löschen wenn ich die Form1 schließe. Das ist jedoch nicht das was ich suche. ich will später beliebig viele Objekte (zb. Auto1,..Auto99) erstellen, die einzeln gelöscht werden können.
crowley - Mo 24.07.06 10:29
hallo covel...
da meld ich mich doch auch nochmal zu wort... dieses problem hast du seeehr oft bei allen möglichen klassen/komponenten/objekten...
und zwar legst du dir ein objekt/klasse/etc im hauptformular an... gibst es später frei... aber der zeiger des hauptformulars zeigt immer noch auf diese stelle im speicher (auch wenn er schon lange nicht mehr reserviert ist).
der ansatz von dir ist da nicht gut zu gebrauchen... wenn das objekt sich selber frei gibt, kriegt davon doch das hauptform nichts mit und kann folglich den zeiger auf das objekt nicht zurücksetzen.
besser wäre nun an dieser stelle, wenn du deinem Objekt zwar ein ButtonClick- Ereignis spendierst, dieses aber nach aussen hin sichtbar machst... dann kannst du im MainForm bei Auto.CloseButtonClick einfach dein
Delphi-Quelltext
1:
| FreeAndNil(TAuto(Sender)) |
machen
freak4fun - Mo 24.07.06 10:31
Das kannst du ja auch machen. Du kannst aber nicht ein Objekt im Objekt selbst freigeben. Mir fehlt ehrlich gesagt das Gesamtbild. Wir reden hier über Einzelprobleme. Vielleicht gibt es ja eine andere Möglichkeit. KAnnst du mir vielleicht mal schreiben was du überhaupt machen willst? :)
Ansonsten bin ich mit meinem Wissen jetzt auch am Ende. :(
covel - Mo 24.07.06 10:37
So ich habe mal das Programm gepostet. Ich will beliebig viele Objekt erstellen, die ich dann einzeln löschen kann.
freak4fun - Mo 24.07.06 11:12
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:
| var Autos: Array[0..10] of TAuto;
procedure TForm1.Button1Click(Sender: TObject); var i: Integer; begin for i := Low(Autos) to High(Autos) do if not Assigned(Autos[i]) then begin Autos[i] := TAuto.Create(Self); Autos[i].Tag := i; break; end; end;
procedure TForm1.Button2Click(Sender: TObject); var i: Integer; begin for i := Low(Autos) to High(Autos) do FreeAndNil(Autos[i]); end;
procedure TForm1.Button3Click(Sender: TObject); begin FreeAndNil(Autos[Self.Tag]); end;
unit: objects
procedure TAuto.ControlMouseClick(Sender: TObject); begin (Self.Owner as TObject).Tag := Self.Tag; end; |
Ich würde das Array noch in den Public-Teil verschieben.
Ich hoffe das Hilft dir weiter. :)
covel - Mo 24.07.06 12:34
Das hat mir weiter geholfen. Aber der button3 war nur zu testzwecken. Den Button2 wird soll es später auch nicht geben.
Delphi-Quelltext
1: 2: 3: 4:
| procedure TForm1.Button3Click(Sender: TObject); begin FreeAndNil(Autos[Self.Tag]); end; |
dieser Code sollte bei dem Btn_close der sich auf dem Panel befindet ausgelöst werden.
Ich weiß aber nicht wie ich den Namen des Panels übermitteln muss/soll.
freak4fun - Mo 24.07.06 12:50
Also:
Mit
Delphi-Quelltext
1: 2: 3: 4:
| procedure TAuto.BtnCloseClick(Sender:TObject); begin PostMessage(Self.Handle, WM_KILL_CONTROL, 0, Integer((Sender as TButton).Parent)); end; |
rufst du ja
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TAuto.WMKillControl(var msg: TMessage); var c : TControl; begin c := TControl(msg.LParam); if not Assigned(c) then Exit;
c.Free; windows.MessageBeep($FFFFFFFF); end; |
auf.
In msg.LParam steht das Handle (vermute ich mal, zumindest eine IdentifikationsID) des entsprechenden Autos. Also wird für das Auto Free aufgerufen. c.Free = Auto.Free. Das machen wir, weil sich ein Objekt nicht selbst zerstören und freigeben kann.
//Edit: (Sender as TButton).Parent) = Panel = Autos[i]
covel - Mo 24.07.06 13:42
So werde es nun wie folgt machen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| procedure TAuto.BtnCloseClick(Sender:TObject); begin (Self.Owner as TObject).Tag := Self.Tag; form1.Button3.Visible :=true;
end; |
button3:
Delphi-Quelltext
1: 2: 3: 4: 5:
| procedure TForm1.Button3Click(Sender: TObject); begin FreeAndNil(Autos[Self.Tag]); button3.Visible := false; end; |
ist zwar nicht ganz das was ich machen wollte..aber nunja man kann nicht alles haben :-) Besten Dank @ freak4fun und crowley
freak4fun - Mo 24.07.06 13:56
Und was willst du mit dem Visible jetzt bewirken? Tut mir leid, kann ich nicht nachvollziehen. Aber du wirst schon wissen was du machst ... 8)
Ich würd dann am Ende auch gern mal das fertige Programm sehen, wenn du nichts dagegen hast. ;)
MfG
freak
covel - Mo 24.07.06 14:05
Die Panels und der dazu gehörige Name der Variable sollte per Btn_click gelöscht werden. Da dies nicht so einfach möglich ist, habe ich nun den Button3 zur hilfe genommen. Dieser Button wird nur sichtbar wenn der Btn_close gedrückt wird.
Wenn das Programm fertig ist, werde ich mich bei dir melden.
Grüße Michael
freak4fun - Mo 24.07.06 14:38
Aber es funktioniert doch, oder nicht. Wen man auf erstellen clickt kommt ein Panel und wenn man auf den 'x'-Button clickt verschwindet es wieder. Ist es nicht das was du wolltest? Wenn du jetzt mit dem butto3 arbeitest und damit das Panel löscht kannst du dir den 'x'-Button und das PostMessage + Anhang sparen. :roll:
MfG
freak
covel - Mo 24.07.06 14:42
genau das passiert das problem ist nur das dann die Variable Auto1 usw. nicht freigegeben werden.
freak4fun - Mo 24.07.06 14:45
covel hat folgendes geschrieben: |
das problem ist nur das dann die Variable Auto1 usw. nicht freigegeben werden. |
Was verstehtst du denn unter "freigegeben"? Weißt du was c.Free; in meinem/deinem Code macht? :) Ich würde dir gern weiterhelfen, aber ich seh dein Problem leider nicht. :(
MfG
freak
crowley - Mo 24.07.06 15:52
@freak
C.free bewirkt zwar, dass der Speicher freigegeben wird, aber Auto1 noch immer auf dieser Speicherbereich zeigt... da fehlt an der Stelle ein Auto1 := nil
@covel
ich habe gerade die große befürchtung, dass du dir damit überhaupt keinen gefallen tust, wie du das machst. von hinten durch die brust ins auge würd man dazu wohl sagen. bitte nimmer nicht wieder in deine auto-klasse das fixe form1 rein und mach es dir doch nicht so unnötig schwer...
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| unit objekte;
type TAuto = class(TPanel) private FCloseClick: TNotifyEvent; procedure BtnCloseClick(Sender:TObject); published property OnCloseClick: TNotifyEvent read FCloseClick write FCloseClick; end;
procedure TAuto.BtnCloseClick(Sender:TObject); begin if Assigned(FCloseClick) then FCloseClick(Self); end; |
das ist das, was du in deiner objekte.pas machen musst... nun noch Form1
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| type TForm1 = class(TForm) procedure CloseButtonClick(Sender:TObject); private public end;
procedure TForm1.CloseButtonClick(Sender:TObject); begin FreeAndNil(Autos[TAuto(Sender).Tag)]); end; |
ist in jedem falle eine "schönere" lösung...
crowley - Mo 24.07.06 15:53
aus versehen doppeltes posting
covel - Mi 26.07.06 11:17
Moin, leider klappt es noch immer nicht. Habe den Quellcode von crowley übernohmen. Jedoch tretten Fehler beim Löschen der einzelnen Panels auf.
Das Programm liegt als Anhang bei. Wäre schön wenn jemand mal drüber gucken könnte
Grüße Michael
Softchaos67 - Mi 26.07.06 11:30
Wann tritt denn ein Fehler auf?
Bei mir läuft das Proggi einwandfrei.
freak4fun - Mi 26.07.06 11:39
Wenn ich alle 3 Panels erstelle und dann das in der Mitte lösche bekomm ich ne AV. :oops:
covel - Mi 26.07.06 11:46
Der Fehler tritt beim löschen der Panels über den X-Button auf. Über den Löschen-Button werden bei mir auch alle panels wieder gelöscht.
Der Fehler tritt immer auf wenn die das zweite Panel löschen will, ebal wie viele ich erstelle...
Softchaos67 - Mi 26.07.06 11:55
Ok, hab den Fehler jetzt auch. Immer wenn man das Panel Nummer 1 löscht, aber nur einmal, dann klappts.
Vielleicht hat das was mit dem Harakiri deiner Komponente zu tun.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!