Dodawanie obsługi nowych komunikatów w komponencie (TImage).

0

Witam,

Nie potrafię sobie poradzić z dodaniem obsługi nowych komunikatów np do komponentu dziedziczonego po TImage.

Unit komponentu wygląda następująco:

unit NewImage;

interface

uses Vcl.ExtCtrls, Winapi.Messages, Vcl.Graphics, System.Types, System.Classes;

const
  CM_DOSTH = WM_APP + 500;

type
  TNewImage=class(TImage)
    protected
      procedure CmDoSth(var Msg: TMessage); message CM_DOSTH;
    public
      constructor Create(AOwner: TComponent); override;
      destructor Destroy;override;
  end;


implementation

procedure TNewImage.CmDoSth(var Msg: TMessage);
begin
  Picture.Bitmap.Canvas.Brush.Color:=Msg.LParam;
  Picture.Bitmap.Canvas.FillRect(TRect.Create(0,0,Width-1,Height-1));
end;

constructor TNewImage.Create(AOwner: TComponent);
begin
  inherited;
end;

destructor TNewImage.Destroy;
begin
  inherited;
end;

end.

Natomiast kod formy tak:

unit CompMsgT;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,NewImage;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    NewImage1: TNewImage;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  PostMessage(Handle,CM_DOSTH,0,random($FFFFFF));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  NewImage1:=TNewImage.Create(Self);
  with NewImage1 do
  begin
    Width:=200;
    Height:=200;
    Top:=50;
    Left:=100;
    Parent:=Self;
    Visible:=true;
    Picture.Bitmap.SetSize(200,200);
    Picture.Bitmap.Canvas.Brush.Color:=$FF00FF;
    Picture.Bitmap.Canvas.FillRect(TRect.Create(0,0,Width-1,Height-1));
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  NewImage1.Destroy;
end;

end.

Co należałoby zrobić aby wywołana została procedury obsługi komunikatu CM_DOSTH po kliknięciu buttonem?

1

Słać komunikat do tego obiektu dziedziczącego po TImage, a nie do formatki. O ile posiada ona uchwyt, bo nie mam jak się upewnić, ale z TImage jest chyba jak z TLabel. Albo jeżeli już ślesz komunikat do formatki to subclassować jej obsługę komunikatów. I tam obsłużyć, to co potrzebujesz, po swojemu. A i nie jestem też do końca pewien, jak to jest z komunikatami CM, czy tak jak z WM i własnymi WM_USER + Liczba.

0

Obsługiwać komunikaty na formie akurat potrafię, jednak jaki uchwyt powinienem podesłać by bezpośrednio komunikat poszedł do komponentu NewImage? Sam TImage nie widzę by miał jakąś właściwość Handle czy coś.

Chodzi o to, że planuję potem pod ten dziedziczony komponent podpiąć wątek z własną bitmapą na której generowałby grafikę, a wynik przesyłałby komunikatem i odświeżała by się zawartość tego NewImage poprzez Bitmap.Assign. Chciałbym uniknąć obsługiwania poprzez formę.

0

Nie mam jak się upewnić, ale kontrolki VCL nie będące pochodnymi kontrolek znanych z WinAPI, nie posiadają uchwytu. Może ktoś tutaj doradzi Tobie coś lepszego, ale ja bym spróbował stworzyć komponent bazujący na staticu z ownerdrawnem. Jednak to sporo roboty. Ewentualnie trzeba było by zagłebić się w kod VCL by przerobić tę kontrolkę, jaką jest standardowe TImage. Jeszcze inne rozwiązanie jakie orzyszło mi do głowy to wysyłać własny komunikat do formatki ale w WParam przekazywać na przykład rzutowane TImage i w kodzie formatki to obsłużyć dla przekaznego TImage, co trzeba. Jednak takie rozwiązanie nie będzie za bardzo uniwersalne poza Delphi.

0

Tak przeglądałem kod rodziców tego TImage i nie wiem, może jakoś dałoby się dodać ten komunikat do obsługi w procedurze WndProc.
Tylko jak to zrobić o ile się da.

3

We własnej aplikacji można tak:

  NewImage1.Perform(CM_DOSTH,0,random($FFFFFF));

ale też nie wiem jak (i czy się da) pobrać uchwyt

0

Tą drogą tylko bezpiecznie będzie jeśli wszystko jest w jednym wątku, a mi chodzi o to by obsłużyć ten komunikat wysłany przez inny wątek w ramach tego samego procesu (docelowy plan) więc tylko PostMessage.

Udało mi się dodać obsługę do WndProc w ten sposób:

type
  TNewImage=class(TImage)
  private
    fCount: integer;
///
  protected
     procedure WndProc(var Message:TMessage); override;
///
///
end;

///

procedure TNewImage.WndProc(var Message: TMessage);
begin
  if Message.Msg=CM_DOSTH then
     begin
       CmDoSth(Message);
     end;
  if Message.Msg=WM_MOUSEMOVE then
     begin
       inc(fCount);
     end;
  inherited;
end;

Po najechaniu myszką i ustawieniu breakpointa w debuggerze wyłapuje WM_MOUSEMOVE, ale jak przekazać to CM_DOSTH to nie wiem...
Opcja z Perform działa wyśmienicie.

3

@szopenfx napisał jak wysłać komunikat a jak się upierasz na PostMessage to musisz mieć uchwyt tego image a ponieważ ta kontrolka nie dziedziczy po TWinControl to "normalnie" go nie uzyskasz więc musisz użyć funkcji AllocateHWnd :

const
  CM_DOSTH = WM_APP + 500;

type
  TNewImage=class(TImage)
    private
      fHandle: THandle;
      procedure WndProc(var Msg: TMessage);
    protected
     // procedure CmDoSth(var Msg: TMessage); message CM_DOSTH;
    public
      property Handle: THandle read fHandle;
      constructor Create(AOwner: TComponent); override;
      destructor Destroy;override;
  end;

//.....

procedure TNewImage.WndProc(var Msg: TMessage);
begin
  case Msg.Msg of
  CM_DOSTH: begin
             //tu cos
            end;
  end;
  Msg.Result:= DefWindowProc(fHandle, Msg.Msg, Msg.wParam, Msg.lParam);
end;


{procedure TNewImage.CmDoSth(var Msg: TMessage);
begin
  Picture.Bitmap.Canvas.Brush.Color:=Msg.LParam;
  Picture.Bitmap.Canvas.FillRect(Rect(0,0,Width-1,Height-1));
end; }

constructor TNewImage.Create(AOwner: TComponent);
begin
  inherited;
  fHandle:= AllocateHWnd(WndProc);
end;

destructor TNewImage.Destroy;
begin
  DeallocateHWnd(fHandle);
  inherited;
end;

i teraz możesz wysłać komunikat :

PostMessage(NewImage1.Handle,CM_DOSTH,0,random($FFFFFF));

1 użytkowników online, w tym zalogowanych: 0, gości: 1