2013-01-15 9 views
8

W moim jest miejsce, w którym chcę posłuchać kluczowych zdarzeń i przechwycić klucz ESC i obsłużyć go w moim komponencie, skonsumować/"zjeść" naciśnięcie klawisza, tak że na przykład formularz właściciela nie będzie go obsługiwał na tym etapie. Podobnie jak w TDragObject po uruchomieniu przeciągnij i anuluj, naciskając ESC.W jaki sposób mój TComponent może przechwycić klucz ESC i obsłużyć go?

Problem polega na tym, że TDragObject ma, który jest powiadamiany przez jego właściciela o numerze CN_KEYDOWN. Ale nikt nie powiadamia mojego komponentu.

Czy muszę zastąpić formularz WindowProc moim własnym? Jeśli tak, to jak to zrobić poprawnie "po książce", że tak powiem?


Wystarczy być w 100% jasne:

TMyComponent = class(TComponent) 

zrobiłem mały test i wydaje się działać:

TMyComponent = class(TComponent) 
    private 
    FOldWindowProc: TWndMethod; 
    FParentForm: TCustomForm; 
    procedure FormWindowProc(var Message: TMessage); 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override;  
end; 

... 

constructor TMyComponent.Create(AOwner: TComponent); 
begin 
    if not (AOwner is TWinControl) then 
    raise Exception.Create('TMyComponent.Create: Owner must be a TWinControl'); 
    inherited Create(AOwner); 
    // hook parent form 
    FParentForm := GetParentForm(TWinControl(Owner)); 
    if Assigned(FParentForm) then 
    begin 
    FOldWindowProc := FParentForm.WindowProc; 
    FParentForm.WindowProc := FormWindowProc; 
    end; 
end; 

destructor TMyComponent.Destroy; 
begin 
    // unhook parent form 
    if Assigned(FParentForm) then 
    FParentForm.WindowProc := FOldWindowProc; 
    inherited; 
end; 

procedure TMyComponent.FormWindowProc(var Message: TMessage); 
begin 
    FOldWindowProc(Message); 
    if Message.Msg = CM_CHILDKEY then // CM_CHILDKEY -> CM_DIALOGKEY -> CM_DIALOGCHAR 
    begin 
    OutputDebugString('CM_CHILDKEY'); 
    if Message.WParam = VK_ESCAPE then 
    begin 
     Beep; 
     // do my stuff... 
     Message.Result := 1; // consume keystroke 
    end; 
    end; 
end; 

Zastanawiam się, czy jest to podejście właściwe/tylko.

+0

Przeciąganie obejmuje nową pętlę modalną. To nie jest opcja dla ciebie. Trudno zobaczyć, jak możesz to zrobić bez współpracy z gospodarzem. –

+2

@DavidHeffernan, OP powiedział "jak w TDragObject", to tylko przykład i zakładam, że OP chce tylko klucza ESC, nic więcej, nic mniej. ESC jest klawiszem dialogu. Po prostu nie mam 1 minuty na odświeżenie komunikatu code/API/windows. –

+0

@Cosmin Pętla modalna operacji przeciągania jest właścicielem i pompuje kolejkę. I tak można uzyskać naciśnięcia klawiszy. Ale komponent w formularzu nie ma takiego luksusu. Jak zamierzasz wejść do pętli komunikatów aplikacji? –

Odpowiedz

4

Jednym ze sposobów może być stworzenie obiektu TApplicationEvents wewnątrz komponentu, a następnie użycie jego zdarzenia OnMessage do przeglądania wiadomości z głównej kolejki komunikatów wątku, takich jak naciśnięcia klawiszy, zanim reszta VCL je przetworzy.

+1

Czy komponenty mogą realistycznie to zrobić? Co się stanie, jeśli aplikacja przydzieli OnMessage? Czy to nie będzie konflikt? –

+3

'TApplicationEvents' jest zaprojektowany jako klasa multiemisji. Wiele instancji otrzymuje te same zdarzenia. IOW, kiedy pojedyncza wiadomość dotrze do kolejki, wszystkie przydzielone programy obsługi "TApplicationEvents.OnMessage" otrzymują do niej bazy danych, jeśli wszyscy używają 'TApplicationEvents', to znaczy. Jeśli ktoś używa 'TApplication.OnMessage' bezpośrednio wtedy' TApplicationEvents.OnMessage' może się zepsuć i na odwrót, tak. To nie jest doskonały system, ale jest lepszy niż nic. –

+1

Zdarzenia 'OnMessage' z wielu składników' TApplicationEvents' będą uruchamiane w odwrotnej kolejności, kiedy te komponenty zostaną utworzone. – NGLN

Powiązane problemy