PDA

Ver la Versión Completa : CONTROL+TAB en PAGECONTROL dentro de MDI-CHILD


amadis
11-08-2005, 05:03:31
CONTROL+TAB en PAGECONTROL dentro de MDI-CHILD :confused:

El titulo lo dice todo!

Deseo utilizar CONTROL+TAB en un PAGECONTROL que está dentro de MDI-CHILD y en lugar de cambiar de tabsheet cambia se mdi activo (en el caso de que haya 2 mdi creado sino no hace nada)

No he visto nada en el foro sobre esto!

Pero he encontrado un trozo de codigo que no comprendí y no pude usar que segun dice sirve para solucionar mi problema!

Les agradeceria su ayuda
------------------------------------------------------------------------
To get around this one needs to intervene before IsMDIMsg is even called. There is only one opportunity to do this: the Application.OnMessage event. So add a handler for the main form OnCreate event, and add a private method to the form called AppMessage:




procedure TMainForm.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppMessage;
end;

procedure TMainform.Appmessage(var Msg: TMsg; var Handled: Boolean);
var
message: TWMKey;
begin
if (msg.message = WM_KEYDOWN) and (LoWord(msg.wparam) = VK_TAB) and
(GetKeyState(VK_CONTROL) < 0) and Assigned(ActiveMDIChild) then
begin
Move(msg.message, message.msg, 3 * sizeof(Cardinal));
message.result := 0;
Handled := ActiveMDIChild.IsShortcut(message);
end;
end;


This will redirect Ctrl+Tab (and Ctrl+Shift+Tab) to the active MDI childs IsShortcut function. This fires the OnShortcut event, so we can use that event on the child form to further handle the key event:


function IsOnTabsheet(aControl: TWinControl; var pc: TPageControl): Boolean;
begin
while Assigned(aControl) and not (aControl is TTabsheet) do
aControl := aControl.Parent;
Result := Assigned(aControl);
if result then
pc := TTabSheet(aControl).Pagecontrol;
end;

procedure TMDIChild.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
var
pc: TPageControl;
begin
if (msg.CharCode = VK_TAB) and (GetKeyState(VK_CONTROL) < 0) then
begin
if IsOnTabsheet(ActiveControl, pc) then
begin
pc.Perform(CM_DIALOGKEY, msg.CharCode, 0);
Handled := true;
end;
end;
end;


Desde ya Gracias

roman
11-08-2005, 07:51:18
No cabe duda que Peter Below (autor del código que pones) es genial.

No entiendo bien del todo su código pero vamos a intentarlo.

Toda aplicación consiste básicamente de un ciclo:


repeat
obtener_mensaje(msg)
procesar_mensaje(msg)
end


Los mensajes, sean del ratón, del teclado, etc. se van colocando en una cola de mensajes para la aplicación y se van procesando conforme llegan a esta cola.

Según lo que explica Peter Below, procesar_mensaje() lo primero que hace (en una aplicación MDI) es llamar a la función IsMDIMsg que determina si el mensaje es especial para ventanas MDI. En el caso de Ctrl-Tab así es y el mensaje se transforma para hacer el cambio de ventana hija de manera que el mensaje original nunca llega al formulario activo. (Si el mensaje no es MDI entonces el mensaje se redirige al formulario activo)

Tal como él dice, hay un único punto donde se puede interceptar esto y es en el evento OnMessage de una componente TApplicationEvents. Dependiendo de la versión que uses de Delphi, es posible que no dispongas de tal componente. En tal caso procedes como él lo hace asignando el evento al objeto Application en el constructor del formulario principal.

En este evento, él detecta cuando el mensaje corresponde a Ctrl-Tab.

Ahora bien, el parámetro Handled del evento se usa para indicar a la VCL si ha de dejar que el mensaje siga su ruta normal o no. Prueba poniendo Handled := true sin más y verás que el efecto del Ctrl-Tab se deshabilita por completo.

Claro que esto no es lo que quieres pues no sólo evitas que se cambie la ventana activa sino que también inhabilitas el cambio de pestaña.

Lo que Peter Below hace es redirigir el mensaje al evento OnShortCut del formulario activo (la llamada a IsShortCut genera dicho evento).

Si no hay evento asignado IsShortCut devolverá false por lo que el valor de Handled en el evento OnMessage será false y el mensaje proseguirá su ruta normal. De esta forma logra que si se está en cualquier otro formulario, el cambio de ventana activa aún sea posible.

En el formulario con el PageControl debes colocar el evento OnShortcut. En este evento, Peter Below determina si estás parado sobre el PageControl (función IsOnTabSheet). Si no lo estás pone el valor de Handled en false. Aquí Handled es similar al del evento OnMessage y será lo que devuelva la función IsShortCut llamada allá de manera que el Handled de OnMessage será false indicando que se siga la ruta normal y se cambia la ventana activa.

Pero si sí estás parado sobre el PageControl, el código de Peter Below hace el cambio de pestaña (Perform(CM_DIALOGKEY...)) y pone Handled en true que a su vez hará que IsShortCut regrese true y por tanto el Handled de OnMessage sea true indicando que se deje de procesar el mensaje y evitando así el cambio de ventana activa.

// Saludos

roman
11-08-2005, 08:09:40
Revisando un poco más a fondo el código creo que lo puedes reducir.

En el evento OnMessage simplemente pones:


procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
begin
if
(Msg.message = WM_KEYDOWN) and (LoWord(Msg.wparam) = VK_TAB) and
(GetKeyState(VK_CONTROL) < 0) and Assigned(ActiveMDIChild)
then
begin
Handled := Boolean(ActiveMDIChild.Perform(CM_DIALOGKEY, Msg.wParam, Msg.lParam));
end;
end;


y ya no haces uso ni de la función IsOnTabSheet ni del evento OnShortCut del formulario con el PageControl.

// Saludos