Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Labels dynamisch erzeugen......
roka6803 - Mi 14.09.05 14:30
Titel: Labels dynamisch erzeugen......
Hallo alle zusammen,
ich habe ein Problem mit dem dynamischen erzeugen von 6 Labels.
Bemerkung: Der von mir gezeigte Quelltext ist gekürzt und enthält an der "fraglichen Stelle" lediglich Quelltext für das erzeugen von EINEM Label.
Ich habe vor diesen "fraglichen Teil" in eine weitere von der ersten nur durch ein boolschen Wert abhängige For-Do-Schleife zu packen, sodass auch die Captions der Labels sowie die zugehören OnKlick-Ereignisse variabel sein können (captions kommen dann aus einem array und die prozeduren für die onclick ereignisse werden durchnummeriert sein).
Ein besonderes Problem stellt bei mir die Stelle
Delphi-Quelltext
1:
| OnClick := menu_label_click; |
dar, weil mir dort immer Fehler angezeigt werden !
Bemerkung 2 : Es reicht mir wenn hier die Lösung zustande kommt nur ein Label dyn. zu erzeugen, aber wie gesagt unter der beachtung der "weiteren *pas" !
Jetzt meine Frage(n): Wie kann ich den Teil zum Erzeugen der sechs Label in eine weitere *.pas packen, welche dann auch die OnClick-Ereignis-Prozeduren enthält? Wie muss ich dann diese in der ersten unit deklarieren ?
Wie muss in dem "fraglichen Teil" die Zuweisung
Onlick := menu_label_click; richtig aussehen, damit sie funzt ?
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 ...;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, jpeg, ExtCtrls;
type Tform_loading_screen = class(TForm) ....... private public end;
var ...... menu_label : TLabel;
implementation
....
procedure Tform_loading_screen.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var i,n : integer; begin
if loading_boolean = true then begin n := 10; loading_status[1] := ........
for i := 0 to n - 1 do begin loading_status_count := i+1; Label2.Caption := (loading_status[loading_status_count]); label2.Refresh; sleep(400); loading_progress.StepIt; sleep(400); end;
loading_boolean := false;
menu_label := TLabel.Create(Self); with menu_label do begin Parent:=form_loading_screen; Caption:='Beschriftung'; Transparent := true; font.size := 11; font.color := clWhite; Left:=100; Top:=100; OnClick := menu_label_click; end;
end; end;
end. |
ManuelGS - Mi 14.09.05 14:42
Wo ist die Deklaration von menu_label_click?
roka6803 - Mi 14.09.05 14:52
ManuelGS hat folgendes geschrieben: |
Wo ist die Deklaration von menu_label_click? |
Genau diese On-Click-Ereignis-Prozedur soll komplett in einer anderen Unit stehen.
In der ersten Unit soll sozusagen nur die erzeugende Prozedur stehen, die dann für das OnCklick-Ereignis des neu entstandenen Labels auf die zweite Unit "verweist" !
Grishnak - Mi 14.09.05 14:56
Du musst dem OnClick-Property eines TLabel-Objektes ein TNotifyEvent zuweisen. Dies hat folgende Form
Delphi-Quelltext
1:
| type TNotifyEvent = procedure (Sender: TObject) of object; |
D.h. dein menu_label_click muss ebenfalls diese Form haben!
ManuelGS - Mi 14.09.05 15:01
Du könntest eine zweite Unit schreiben, die die gewünschte Prozedur enthält, und dann mittels {$i dateiname.pas} (ich hoffe, ich irre mich nicht) inkludieren.
Oder aber du bindest sie "normal" bei der Uses-Klausel ein.
roka6803 - Mi 14.09.05 15:08
IN welche Uses-Klausel ? Der vor, oder der nach "Implementation" ?
Und: Wie genau und wo genau muss das mit dem "NotifyEvent" hin ?
ManuelGS - Mi 14.09.05 15:24
In diesem Fall würd es im Implementation-Teil ausreichen.
Wenn's nicht klappen sollte, dann halt in den Interface-Teil.
Grishnak - Mi 14.09.05 15:26
Unit, die die Prozedur enthält:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| unit Egal;
interface
[...]
procedure menu_label_click(Sender: TObject);
implementation
[...]
procedure menu_label_click(Sender: TObject); begin [...] end; |
Unit, die die Form mit dem/den Label(s) enthält:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| unit MitLabel;
[...]
implementation
uses Egal[...];
[...]
MeinLabel.OnClick:=menu_label_click; |
So müsste es funktionieren!
roka6803 - Mi 14.09.05 15:37
Also ich würde das jetzt so schreiben:
Unit 1:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| ...
menu_label := TLabel.Create(Self); with menu_label do begin Parent:=form_loading_screen; Caption:='Beschriftung'; Transparent := true; font.size := 11; font.color := clWhite; Left:=100; Top:=100; menu_label.OnClick := menu_label_click; end;
...
end. |
Und Unit 2 wie vorher beschrieben.
OK, werds mal probieren !
roka6803 - Mi 14.09.05 15:45
OK, habe es ausprobiert. Eigentlich funzt alles, doch bei menu_label.OnClick := menu_label_click; haut der den Fehler "[Error] loading_screen.pas(95): Incompatible types: method pointer and regular procedure" rein.
Ansonsten hab ich alles so gemacht wie ihr vorgeschlagen habt !
Grishnak - Mi 14.09.05 15:53
mhhh. Stimmt! Das klappt so leider nicht! :roll:
EDIT: Man kann der OnClick-Property nur Objekt-Methoden zuweisen! Du kannst aber in der Form ein OnClick-Ereignis-Prozedur für dein(e) Label(s) schreiben, in der du dann menu_label_click aufrufst:
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:
| [...]
type Tform_loading_screen = class(TForm) ....... procedure LabelOnClick(Sender: TObject); private public end;
[...]
with menu_label do begin Parent:=form_loading_screen; Caption:='Beschriftung'; Transparent := true; font.size := 11; font.color := clWhite; Left:=100; Top:=100; menu_label.OnClick := form_loading_screen.LabelOnClick; end;
[...]
procedure Tform_loading_screen.LabelOnClick(Sender: TObject); begin menu_label_click; end;
[...] |
Amateur - Mi 14.09.05 16:02
hatte ich auch schon. versuch ma sender:tobject als variable zusätzlich zu deiner eignene procedure zu schreiben. also bei deiner procedure: procedure meineprocedure (sender:tobject);
ich habs net getestet aber das liegt auf jeden fall an den parametern von onclick und deiner procedure. ansonsten ma alle parameter von ner onclick procedure bei deiner eigene procedure übergeben. hat bei mir hingehauen. sollte aber mit sender reichen
roka6803 - Mi 14.09.05 16:04
Grishnak hat folgendes geschrieben: |
mhhh. Stimmt! Das klappt so leider nicht! :roll: |
Wie könnte man das mit dem Notify Event machen ?
roka6803 - Mi 14.09.05 16:07
Amateur hat folgendes geschrieben: |
hatte ich auch schon. versuch ma sender:tobject als variable zusätzlich zu deiner eignene procedure zu schreiben. also bei deiner procedure: procedure meineprocedure (sender:tobject);
ich habs net getestet aber das liegt auf jeden fall an den parametern von onclick und deiner procedure. ansonsten ma alle parameter von ner onclick procedure bei deiner eigene procedure übergeben. hat bei mir hingehauen. sollte aber mit sender reichen |
geht auch nicht dann haut er noch mehr fehler raus wie "expected dass statt dem und expected dort weil da hier und son kram..."
ManuelGS - Mi 14.09.05 17:21
Ist zwar ein hässliches Stück Code, aber reicht wohl zu Demonstrationszwecken.
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:
| unit Unit2;
interface
uses dialogs,stdctrls,classes,unit1;
procedure machdielabelsdrauf;
implementation
procedure klick(sender:tobject); begin showmessage('Eo Captain Jack, Heureka und Quantensprung - es klappt.'); end;
procedure machdielabelsdrauf; var lab:tlabel; ereignisprozedur:tnotifyevent; begin lab:=tlabel.create(form1); lab.Parent:=form1; lab.Caption:='GUTEN TAG - BITTE KLICKEN SIE MICH AN'; @ereignisprozedur:=@klick; lab.onclick:=ereignisprozedur; end;
end. |
In der anderen Unit diese hier im Implementation-Teil einbinden; per Button etc. dann "Machdielabelsdrauf" aufrufen.
Amateur - Mi 14.09.05 17:29
du musst deine procedure ner klasse zuweisen. wenn ich ne procedure als methode von tform1 schreibe kann ich sie so wie du es willst zuweisen. musste ma probieren. jednefalls muss es ne methode ner klasse sein. ganz ohne was gehts wohl net.
könntest also ne klasse machen tmeineklasse und der die procedure zuweisen und dann machste label1.onclick:=meineklasse.click;
wirst auch noch den sender als parameter geben müssen bin aber net sicher
ok das von manuel sollte auch gehn. is sogar noch besser
roka6803 - Mi 14.09.05 18:27
OK, es klappt alles wunderbar.
Ich habe es jetzt so weit, dass dank einer For-Do-Schleife fünf Label erzeugt weren. Alle mit einer anderen Caption.
Jetzt würde ich es gerne so einrichten, dass jedes Label noch eine eigene OnClick-Prozedur besitzt.
Hier mein aktueller (gekürzter) Quelltext:
Unit 1
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:
| unit loading_screen;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, jpeg, ExtCtrls;
type Tform_loading_screen = class(TForm) ... private public end;
var ...
implementation
uses loading_screen_menu_labels; {$R *.DFM}
procedure Tform_loading_screen.FormCreate(Sender: TObject); begin ... end;
procedure Tform_loading_screen.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var i,n : integer; begin if loading_boolean = true then begin n := 10; loading_status[1] := ...
for i := 0 to n - 1 do begin loading_status_count := i+1; Label2.Caption := (loading_status[loading_status_count]); label2.Refresh; sleep(400); loading_progress.StepIt; sleep(400); end;
loading_boolean := false;
menu_label_erzeugen; end; end;
end. |
Unit 2
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:
| unit loading_screen_menu_labels;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, jpeg, ExtCtrls;
procedure menu_label_erzeugen;
var menu_label_caption : Array [1..5] of String;
implementation
uses loading_screen; procedure klick(sender:tobject); begin showmessage('Eo Captain Jack, Heureka und Quantensprung - es klappt.'); end;
procedure menu_label_erzeugen; var menu_label : tlabel; ereignisprozedur : tnotifyevent; i,e : integer;
begin
menu_label_caption[1] := ...
e := 100;
for i := 0 to 4 do begin menu_label := tlabel.create (form_loading_screen); menu_label.Parent := form_loading_screen; menu_label.Caption := menu_label_caption[i+1]; menu_label.Top := e; inc(e,20); menu_label.Left := 100; menu_label.Transparent := true; menu_label.Font.Size := 11; menu_label.Font.Color := clRed; @ereignisprozedur := @klick; menu_label.onclick := ereignisprozedur; end; end;
end. |
Wie kann jetzt jedes Label seine eigene OnKlick-Prozedur bekommen ?
MfG roka6803
PS Was hat das mit dem @ereignisprozedur := @klick; zu bedeute ? Ich weiss nur, dass es ohne nicht geht !
Grishnak - Mi 14.09.05 18:39
Delphi-Quelltext
1:
| @ereignisprozedur := @klick; |
ereignisprozedur ist im var-Block als TNotifyEvent deklariert. Mittels dieser Zuweisung lässt du sie auf die klick-Prozedur zeigen. Das ist zwar sehr schmutzig programmiert, aber es klappt!
Wenn du jedem Label eine eigene OnClick-Prozedur zuweisen willst (z.B. klick0(), klick2(), ... klick4()), dann kannst du einfach statt nur einem TNotifyEvent ein Array davon deklarieren:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| var ereignisprozedur: array[0..4] of TNotifyEvent; begin @ereignisprozedur[0]:=@klick0; @ereignisprozedur[1]:=@klick1; [...] @ereignisprozedur[4]:=@klick4;
[...]
for i:=0 to 4 do begin [..] menu_label[i].OnClick:=ereignisprozedur[i]; [...] end; [...] end; |
roka6803 - Mi 14.09.05 18:45
Danke, Grishnak !
Dieses NotifyEvent, würde das auch mit OnMouseOver statt OnClick funzen ?
MfG roka6803
Edit:
Es hat sich ein neues Problem ergeben: Das mit dem Noti...Array funzt wunderbar nur in der Zeile
@ereignisprozedur := @klick bekomme ich ne Fehlerausgabe !
Ansonsten keine weiteren Fehler.
Hier mein (diesmal ungekürzt) Quelltext von Unit2 (der aus Unit1 ist noch wie in meinem vorigen Post):
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:
| unit loading_screen_menu_labels;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, jpeg, ExtCtrls;
procedure menu_label_erzeugen;
var menu_label_caption : Array [1..5] of String; ereignisprozedur : Array [0..4] of TNotifyEvent;
implementation
uses loading_screen;
procedure klick_newgame(sender:tobject); begin showmessage('Neues Spiel starten...'); end;
procedure klick_loadgame(sender:tobject); begin showmessage('Gespeichertes (lokales) Spiel laden...'); end;
procedure klick_options(sender:tobject); begin showmessage('Optionen öffnen...'); end;
procedure klick_credits(sender:tobject); begin showmessage('Credits : Na wer hat das denn gemacht ?'); end;
procedure klick_close(sender:tobject); begin Application.Terminate; end;
procedure menu_label_erzeugen; var menu_label : tlabel; i,e : integer;
begin
menu_label_caption[1] := 'Neues Spiel'; menu_label_caption[2] := 'Spiel laden'; menu_label_caption[3] := 'Optionen'; menu_label_caption[4] := 'Credits'; menu_label_caption[5] := 'Beenden';
@ereignisprozedur[0] := @klick_newgame; @ereignisprozedur[1] := @klick_loadgame; @ereignisprozedur[2] := @klick_options; @ereignisprozedur[3] := @klick_credits; @ereignisprozedur[4] := @klick_close;
e := 100;
for i := 0 to 4 do begin menu_label := tlabel.create (form_loading_screen); menu_label.Parent := form_loading_screen; menu_label.Caption := menu_label_caption[i+1]; menu_label.Top := e; inc(e,20); menu_label.Left := 100; menu_label.Transparent := true; menu_label.Font.Size := 11; menu_label.Font.Color := clRed; @ereignisprozedur[i] := @klick[i]; menu_label[i].onclick := ereignisprozedur[i]; end; end;
end. |
Christian S. - Mi 14.09.05 18:47
Grishnak hat folgendes geschrieben: |
Delphi-Quelltext 1:
| @ereignisprozedur := @klick; |
ereignisprozedur ist im var-Block als TNotifyEvent deklariert. Mittels dieser Zuweisung lässt du sie auf die klick-Prozedur zeigen. Das ist zwar sehr schmutzig programmiert, aber es klappt! |
Normalerweise ist das Zuweisen von Evenst nicht schmutzig, sondern eigentlich eine Standardvorgehensweise. In diesem Fall wundert es mich, dass das überhaupt funktioniert.
Denn, wie Du selber geschrieben hast, ist ein TNotifyEvent eine Methode, also eine
procedure of object. "Klick" ist jedoch eine einfache Prozedur. Ich denke, dass man deswegen die Klimmzüge mit @.. := @.. machen muss, im Normalfall weist man die Methode einfach zu und fertig.
Ich denke, man fängt sich durch dieses "Zuweisen mit der Brechstange" eine potentielle Fehlerquelle ein, da eine Methode noch einen versteckten Parameter "self" besitzt, den eine Prozedur nicht hat. Ich würde zusehen, es sauber hinzubekommen und keine Prozeduren und Methoden zwangsweise zu verheiraten.
Du findest
hier [
http://www.christian-stelzmann.de/index_delphi_artikel.html] übrigens einen Artikel zu Komponentenarrays von mir, das könnte Dir auch noch weiterhelfen.
Grüße
Christian
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!