Quiero que mi formulario maneje las teclas de flecha, y puedo hacerlo, siempre que no haya ningún botón en el formulario. ¿Por qué es esto?Clave de flecha Delphi XE y Reventado con OnKeyDown
Respuesta
Las teclas de flecha se utilizan para navegar entre los botones de un formulario. Este es el comportamiento estándar de Windows. Aunque puede desactivar este comportamiento estándar, debe pensar dos veces antes de ir contra el estándar de la plataforma. Las teclas de flecha están pensadas para la navegación.
Si quiere obtener el máximo de información sobre cómo una pulsación de tecla se abre camino a través del ciclo de mensajes, le recomiendo leer A Key's Odyssey. Si desea interceptar la tecla presionada antes de que se convierta en una tecla de navegación, debe hacerlo en IsKeyMsg
o anterior. Por ejemplo, el answer de Sertac ofrece una de esas posibilidades.
Peter Below (autor de Key's Odyssey) es un importante miembro de la comunidad Delphi (TeamB) y un gran colaborador de JVCL. Buen articulo. –
Debido a que están prevenidos para tratar de establecer el foco en el próximo WinControl disponible.
(estoy bastante seguro de que si pones un Editar en lugar de un Botón, verás lo mismo).
Si desea manejarlos usted mismo, puede proporcionar a la Aplicación un evento OnMessage que filtre esos antes de que se procesen y los maneje usted mismo allí.
Los mensajes clave son procesados por los propios controles que reciben estos mensajes, es por eso que cuando está en un botón el formulario no recibe el mensaje. Por lo que normalmente tendría que subclase estos controles, pero la VCL es tan amable de pedir a la forma de crianza qué hacer si el formulario está interesado:
type
TForm1 = class(TForm)
..
private
procedure DialogKey(var Msg: TWMKey); message CM_DIALOGKEY;
..
procedure TForm1.DialogKey(var Msg: TWMKey);
begin
if not (Msg.CharCode in [VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT]) then
inherited;
end;
François de edición: para contestar la OP pregunta original, necesita llamar aKeyDown de alguna manera para que su código de evento funcione (siéntase libre de editar; era demasiado largo para un comentario).
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
private
{ Private declarations }
procedure DialogKey(var Msg: TWMKey); message CM_DIALOGKEY;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.DialogKey(var Msg: TWMKey);
begin
case Msg.CharCode of
VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT:
if Assigned(onKeyDown) then
onKeyDown(Self, Msg.CharCode, KeyDataToShiftState(Msg.KeyData));
else
inherited
end;
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
case Key of
VK_DOWN: Top := Top + 5;
VK_UP: Top := Top - 5;
VK_LEFT: Left := Left - 5;
VK_RIGHT: Left := Left + 5;
end;
end;
Creo que necesitas un poco más de explicación en cuanto a lo especial sobre 'CM_DIALOGKEY'. Esta es sin duda la forma elegante de cambiar el comportamiento. Siéntase libre de superponerse con mi respuesta y la eliminaré, ya que una respuesta completa con este código es mejor que lo que hice. –
@David - Me temo que no podrás borrar tu publicación :). No hay mucho que pueda explicar sobre CM_DIALOGKEY, es un mensaje compuesto de VCL usado para transmitir mensajes clave. Esto es lo que dice mi archivo de ayuda al respecto: * "Esto es constante Controls.CM_DIALOGKEY" * :). Actualización: La [documentación] (http://docwiki.embarcadero.com/VCL/2010/en/Controls.CM_DIALOGKEY) ha sido mejorada: * "CM_DIALOGKEY representa un mensaje de control y es usado internamente por el marco VCL." * –
Hmm, pensé que sonaba como si estuviera relacionado con 'TApplication.IsDlgMsg'. De hecho es '' TApplication.IsDlgMsg' incluso relevante aquí o la VCL maneja estas teclas de navegación en lugar de los diálogos de Windows? –
Solo el objeto que tiene el foco puede recibir un evento de teclado.
Para que el formulario tenga acceso al evento de teclas de flecha, declare MsgHandler
en la parte pública del formulario. En la forma crear constructor, asigne Application.OnMessage
a este MsgHandler.
El siguiente código intercepta las teclas de flecha solo si provienen de un descendiente TButton. Se pueden agregar más controles según sea necesario.
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := Self.MsgHandler;
end;
procedure TForm1.MsgHandler(var Msg: TMsg; var Handled: Boolean);
var
ActiveControl: TWinControl;
key : word;
begin
if (Msg.message = WM_KEYDOWN) then
begin
ActiveControl := Screen.ActiveControl;
// if the active control inherits from TButton, intercept the key.
// add other controls as fit your needs
if not ActiveControl.InheritsFrom(TButton)
then Exit;
key := Msg.wParam;
Handled := true;
case Key of // intercept the wanted keys
VK_DOWN : ; // doStuff
VK_UP : ; // doStuff
VK_LEFT : ; // doStuff
VK_RIGHT : ; // doStuff
else Handled := false;
end;
end;
end;
var
KBHook: HHook; {this intercepts keyboard input}
implementation
{$R *.dfm}
function KeyboardHookProc(Code: Integer; WordParam: Word; LongParam: LongInt): LongInt; stdcall;
begin
case WordParam of
vk_Space: ShowMessage ('space') ;
vk_Right:ShowMessage ('rgt') ;
vk_Left:ShowMessage ('lft') ;
vk_Up: ShowMessage ('up') ;
vk_Down: ShowMessage ('down') ;
end; {case}
end;
procedure TForm4.FormCreate(Sender: TObject);
begin
KBHook:=SetWindowsHookEx(WH_KEYBOARD,@KeyboardHookProc,HInstance,GetCurrentThreadId());
end;
Este código funcionará incluso cuando un control se centra (botones, cuadros de lista), así que ten cuidado algunos controles pueden perder sus eventos de teclado (Leer respuesta David haffernans).
eventos de teclado con controles enfocados
por ejemplo: Si usted está teniendo cuadro de texto en su aplicación y desea recive texto (si se centró) también, entonces
añadir un applicationevent1
procedure TForm4.ApplicationEvents1Message(var Msg: tagMSG;var Handled: Boolean);
begin
if Msg.message = WM_KEYFIRST then
KBHook:=SetWindowsHookEx(WH_KEYBOARD,@KeyboardHookProc,HInstance,GetCurrentThreadId());
end;
agregue el siguiente código en la parte inferior de function KeyboardHookProc
UnhookWindowsHookEx(KBHook);
y quitar
KBHook:=SetWindowsHookEx(WH_KEYBOARD,@KeyboardHookProc, HInstance,
GetCurrentThreadId());
del evento alcrear.
- 1. Teclas de flecha de reventado
- 2. Delphi XE: Perdido camino Biblioteca
- 3. Delphi XE + SOAP + SSL
- 4. hash SHA1 en Delphi XE
- 5. Delphi XE TBytes uso correcto
- 6. Delphi XE build events .. globally?
- 7. Delphi XE necesita 20 segundos para comenzar
- 8. Actualización de Delphi de RAD Studio a Delphi XE
- 9. Problema con varios cuadros de diálogo modales usando Delphi XE
- 10. ¿Debo pasar al nuevo Delphi XE Starter?
- 11. Delphi XE - ¿Debería usar String o AnsiString?
- 12. delphi XE multi-unit namespace question
- 13. Cómo autogenerar * _TLB.pas en Delphi XE?
- 14. Delphi XE: ¿Dónde está mi TValue.Equals()?
- 15. POPCNT en Delphi XE/XE2 64bit
- 16. ¿Moviéndose de Delphi7 a Delphi XE o 2010 para Unicode?
- 17. error de desbordamiento de pila cuando abro Delphi XE IDE
- 18. Regex llamado grupos de captura en Delphi XE
- 19. EditText OnKeyDown
- 20. Deshabilitar comprobación automática de actualización de Delphi XE
- 21. ¿Cómo controlar el directorio de archivos en Delphi XE?
- 22. Reventado silencioso NaN
- 23. Códigos clave para las teclas de flecha
- 24. TIdHTTP - la sesión ha caducado mensaje en Delphi XE
- 25. ¿No hay más unidad xercesxmldom en Delphi XE?
- 26. clases "no utilizados" se pondrá a disposición en Delphi XE
- 27. Cómo implementar automáticamente métodos abstractos heredados en Delphi XE
- 28. Delphi 7 se bloquea después de instalar Delphi XE (rutas mixtas BPL)
- 29. Javascript: addEventListener con onkeydown no parece funcionar
- 30. Qué marco de prueba/unidad de prueba utilizar con Delphi XE Starter Edition
Una gran pregunta. Profundizar en las complejidades subyacentes de cosas como esta es lo que separa a los expertos de los turistas. ¡Seguid así! –