Entwickler-Ecke

Windows API - Handle für SendMessage reservieren


freedy - Fr 30.03.07 10:04
Titel: Handle für SendMessage reservieren
Hallo!

Ich habe folgenden Codeausschnitt:

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:
const
  WM_LINE_ADD = WM_USER + 1;

type  
  TLines = class(TObject)
  private
    FLines : array of TLine;
  [...]
  public
    [...]
    function Add : TLine;
    [...]
  end;


  TEditor = class(TCustomControl)
  private
    Lines : TLines;
    [...]
    procedure WMLineAdd(var Msg: TMessage); message WM_LINE_ADD;
    [...]
  end;
  
[...]

function TLines.Add : TLine;
var
  Handle: Hwnd;
begin
  Handle := Application.Handle;
  [...]
  SendMessage(Handle, WM_LINE_ADD, Integer(FLines[Length(FLines) - 1]), 0);
  Result := FLines[Length(FLines) - 1]; 
end;

[...]

procedure TEditor.WMLineAdd(var Msg: TMessage);
 var
  Line : TLine;
begin
  Line := TLine(Msg.WParam);
  if Assigned(FOnLineAdd) then
    FOnLineAdd(Self);
end;



Wie man sieht, soll, wenn die Add-Funktion aufgerufen wird, eine Message versendet werden, die von der Parent-Klasse aufgefangen wird. Leider funktioniert das nicht. Wie reserviere ich beim BS das Handle für die TEditor-Klasse, damit die Message dort ankommt? Bisher gibt es das ja noch gar nicht, oder?

Grüße
Michael


HelgeLange - Fr 30.03.07 14:42

Du musst kein Handle reservieren, sondern das Handle des Empfängers kennen. Oder das Handle des Owners, der dann diue Massage vllt. durchreicht. Aber eigentlich sollten alle visuellen Editor-Komponenten ein Handle haben.


Delete - Fr 30.03.07 14:56

user profile iconHelgeLange hat folgendes geschrieben:
Aber eigentlich sollten alle visuellen Editor-Komponenten ein Handle haben.

Nein nur die von TQWinControl abgeleiteten. TLabel hat zum Beispiel kein Handle, weil es von TGraphicControl abgeleitet ist.

@freedy: Arbeite mit Ereignissen. TLines.Add löst ein Ereignis aus dem in TEditor eine Ereignisbehandlungsroutine zugeordnet ist. Mit SendMessage sendet man Nachrichten an Fenster. Eine Klasse ist nun aber mal kein Fenster und kann demnach auch keine Nachrichten empfangen.

Demo

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:
type
  TOnAdd = procedure(Sender: TObject) of object;

  TLine = class(TObject)
  private
    FStringList: TStringList;
    FOnAdd: TOnAdd;
  public
    constructor Create;
    destructor Destroy; override;
    property OnAdd: TOnAdd read FOnAdd write FOnAdd;
    procedure Add(s: String);
  end;

  TEditor = class(TObject)
  private
    FLine: TLine;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Add(s: String);
    procedure OnAdd(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TLine }

procedure TLine.Add(s: String);
begin
  FStringList.Add(s);
  if Assigned(OnAdd) then
    OnAdd(Self);
end;

constructor TLine.Create;
begin
  FStringList := TStringList.Create;
end;

destructor TLine.Destroy;
begin
  FStringList.Free;
  inherited;
end;

{ TEditor }

procedure TEditor.Add(s: String);
begin
  FLine.Add(s);
end;

constructor TEditor.Create;
begin
  FLine := TLine.Create;
  FLine.OnAdd := OnAdd;
end;

destructor TEditor.Destroy;
begin
  FLine.Free;
  inherited;
end;

procedure TEditor.OnAdd(Sender: TObject);
begin
  ShowMessage('OnAdd');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  edit: TEditor;
begin
  edit := TEditor.Create;
  try
    edit.Add('Test');
  finally
    edit.Free;
  end;
end;


freedy - Fr 30.03.07 15:31

user profile iconLuckie hat folgendes geschrieben:

Mit SendMessage sendet man Nachrichten an Fenster. Eine Klasse ist nun aber mal kein Fenster und kann demnach auch keine Nachrichten empfangen.


Das sehe ich etwas anders. Wenn man sich den Quellcode der VCL ansieht, findet man des öfteren "SendMessage" innerhalb der Komponenten. Ein Ereignis wollte ich nicht belegen, da auch mein TLine nach aussen sichtbar ist. Ich möchte einen späteren Programmierer nicht verwirren, wenn die Komponente nach Überschreiben des Ereignisses nicht mehr reagiert.

Inzwischen habe ich das Handle-Problem auch in den Griff bekommen. Die einzelnen untergeordneten Klassen kennen nun das Handle ihrer Vater-Instanz.

Trotzdem vielen Dank und ein schönes Wochenende.


HelgeLange - Fr 30.03.07 15:33

mmit Editor-Komponenten haben ich eigentlich die ausschliessen wollen, die sich nicht zur Laufzeit editieren lassen (zum Bsp: TLabel) ;)

Was Du machen kannst : mit Dispatch eine Nachricht senden, direkt an die Komponente. Das versteht jedes Object von Delphi


Delete - Fr 30.03.07 15:51

user profile iconfreedy hat folgendes geschrieben:
user profile iconLuckie hat folgendes geschrieben:

Mit SendMessage sendet man Nachrichten an Fenster. Eine Klasse ist nun aber mal kein Fenster und kann demnach auch keine Nachrichten empfangen.


Das sehe ich etwas anders. Wenn man sich den Quellcode der VCL ansieht, findet man des öfteren "SendMessage" innerhalb der Komponenten.

Dann nenne mir doch mal das Fensterhandle einer Klasse:

Quelltext
1:
2:
3:
4:
5:
LRESULT SendMessage(          HWND hWnd,
    UINT Msg,
    WPARAM wParam,
    LPARAM lParam
);

Zitat:
hWnd
[in] Handle to the window whose window procedure will receive the message.


Was anderes ist es, wenn du eine Klasse hast, die von TWinControl abgeleitet ist und somit ein Fensterhandle besitzt.