Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > API de Windows
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 27-10-2006
Cheerpipe Cheerpipe is offline
Miembro
 
Registrado: oct 2006
Posts: 46
Poder: 0
Cheerpipe Va por buen camino
Corrección del menu de sistema (en aplicaciones delphi)

Bueno, hace tiempo que vengo leyendo temas en el foro pero no habia tenido la oportunidad de participar.

He estado buscando una forma de corregir el menu de la barra de tareas de las aplicacioens delphi (agregar tamaño, mover y maximizar) sin encontrar forma sencilla. (si es que estuviese posteado en el foro, pido disculpas).

arme este unit que soluciona el problema

Código Delphi [-]
unit FixSystemMenu;

interface
uses ComObj, windows, forms;

type
  ITaskbarList = interface
    ['{56FDF342-FD6D-11d0-958A-006097C9A090}']
       function HrInit: HResult; stdcall;
       function AddTab(hwnd: Cardinal): HResult; stdcall;
       function DeleteTab(hwnd: Cardinal): HResult; stdcall;
       function ActivateTab(hwnd: Cardinal): HResult; stdcall;
       function SetActiveAlt(hwnd: Cardinal): HResult; stdcall;
  end;

procedure SetFixSystemMenu();

implementation

procedure SetFixSystemMenu();
const
  CLSID_TaskBarList: TGUID ='{56FDF344-FD6D-11D0-958A-006097C9A090}';
  IID_ITaskBarList: TGUID ='{56FDF342-FD6D-11D0-958A-006097C9A090}';

var
  FTaskbarList: ITaskBarList;
begin
  if (Application.ActiveFormHandle <> 0) then
  begin
     FTaskbarList := CreateComObject(CLSID_TaskbarList) as ITaskbarList;
     FTaskbarList.HrInit;
     FTaskbarList.HrInit;
     FTaskbarList.AddTab(Application.ActiveFormHandle);
  end;

end;
INITIALIZATION
  SetWindowLong(Application.Handle, GWL_EXSTYLE, GetWindowLong(Application.Handle,GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
end.


basta con hacerle un include desde el formulario principal del proyecto, y en el oncreate del formulario principal llamar la funcion SetFixSystemMenu.

Por otro lado, estoy intentando crear ventanas MDI hijas en estado maximizado, hasta el momento no obtengo el efecto exacto que deseo, por lo que si hay alguien mas intereraso, me contacta y trabajamos junto en ese problema.

PD: no puse en la parte de trucos porque prefiero que se pruebe primero.
Responder Con Cita
  #2  
Antiguo 27-10-2006
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
He estado probando tu código y no termina de convencerme. El botón en la barra de tareas se comporta de forma extraña:

- nunca queda presionado cuando la aplicación está activa
- al minimizar, el formulario principal se iconiza como si se tratase de un formulario secundario
- si un formulario secundario se activa, al presionar el botón de la barra, vuelve a activarse el principal, lo que no debe ocurrir.

Según leí alguna vez, la razón por la que Delphi no usa un menú "estandar" en el botón de la barra de tareas es porque dicho menú corresponde al menú de sistema, no del formulario principal, sino de la ventana de la aplicación, que es una ventana oculta. Los comandos minimizar y cerrar se aplican a toda la aplicación: minimizar oculta todos los formularios activos y cerrar cierra la aplicación. Pero un comando como maximizar es distinto pues no se maximiza una aplicación, sino uno de sus formularios, y lo mismo el comando mover.

El punto es: ¿a qué ventana se tendrían que aplicar esas acciones? ¿a la principal? ¿a la activa?

La razón quizá no es muy convincente pues pudieron optar por aplicarlos a una de estas dos ventanas, tal como lo hace tu código. Pero el problema, hasta donde he visto, es que el comportamiento es extraño.

Haciendo pruebas, creo que he logrado algo añadiendo items directamente al menú de sistema de la aplicación, por ejemplo:

Código Delphi [-]
procedure AddSysItem(Handle: HWND; Command: Integer; Caption: String);
var
  SysMenu: HMENU;
  Item: TMenuItemInfo;

begin
  SysMenu := GetSystemMenu(Handle, false);

  Item.cbSize := SizeOf(Item);
  Item.fMask := MIIM_FTYPE or MIIM_STRING or MIIM_ID;
  Item.fType := MFT_STRING;
  Item.dwTypeData := PChar(Caption);
  Item.wID := Command;

  Windows.InsertMenuItem(SysMenu, 1, true, Item);
end;

Esta función inserta un item en el menú de sistema de la ventana identificada por Handle. El parámetro Command es el identificador del comando a ejecutar, que corresponde al parámetro WPARAM del mensaje WM_SYSCOMMAND. No sirve que pasemos directamente un comando como SC_MOVE, precisamente porque la ventana de la aplicación no es la que deseamos mover, sino, por ejemplo, la ventana principal. Entonces debemos pasar un comando personalizado:

Código Delphi [-]
const
  // alguna costante que no entre en conflicto con otros comandos
  // para que sea compatible con otros comandos, hay que recorrerlo 4 bits
  SC_MENEAR = 84 shl 4;

...

AddSysItem(Application.Handle, SC_MENEAR, 'Menear');

Para captar este comando podemos usar el evento OnMessage del objeto Application o de un objeto ApplicationEvents, da lo mismo:

Código Delphi [-]
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
begin
  if (Msg.message = WM_SYSCOMMAND) then
    case Msg.wParam and $FFF0 of
      SC_MENEAR:
        Application.MainForm.Perform(WM_SYSCOMMAND, SC_MOVE, 0);
    end;
end;

Esto es, traspasamos el comando personalizado SC_MENEAR que llega a la aplicación, al formulario principal como SC_MOVE.

Con esto básicamente funciona, pero debemos cuidar otros detalles como el habilitar o inhabilitar el item cuando sea necesario. El comando SC_MENEAR debe inhabiltarse si la aplicación se minimiza o si el formulario principal se maximiza. Y debe habilitarse de vuelta, cuando se restaure la aplicación o el formulario principal.

Para empezar, complementamos el evento OnMessage dela aplicación:

Código Delphi [-]
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
begin
  if (Msg.message = WM_SYSCOMMAND) then
    case Msg.wParam and $FFF0 of
      SC_MENEAR:
        Application.MainForm.Perform(WM_SYSCOMMAND, SC_MOVE, 0);

      SC_MINIMIZE:
        // inhabilitar el item cuando se minimiza la aplicación
        EnableSysItem(Application.Handle, SC_MENEAR, false);

      SC_RESTORE:
        // al restaurar la aplicación, rehabilitamos el item pero sólo si la ventana
        // principal no está maximizada
        if Application.MainForm.WindowState <> wsMaximized then
          EnableSysItem(Application.Handle, SC_MENEAR, true);
    end;
end;

donde EnableSysItem es:

Código Delphi [-]
procedure EnableSysItem(Handle: HWND; Command: Integer; Enable: Boolean);
const
   Flags: array[Boolean] of Integer = (MF_GRAYED, MF_ENABLED);

var
  SysMenu: HMENU;

begin
  SysMenu := GetSystemMenu(Handle, false);
  Windows.EnableMenuItem(SysMenu, Command, MF_BYCOMMAND or Flags[Enable]);
end;

Pero también hay que actuar cuando se maximice o restaure el formulario principal. Para ello podemos crear un manejador para el mensaje WM_SYSCOMMAND del formulario:

Código Delphi [-]
type
  TForm1 = class(TForm)
  private
    procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
  end;

implementation

procedure TForm1.WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
begin
  inherited;

  case Msg.CmdType and $FFF0 of
    SC_RESTORE: EnableSysItem(Application.Handle, SC_MENEAR, true);
    SC_MAXIMIZE: EnableSysItem(Application.Handle, SC_MENEAR, false);
  end;
end;

Adjunto un ejemplo ya hecho al cual le he añadido el comando SC_ESTRUJAR para cambiar de tamaño el formulario principal. Quedaría agregar el comando SC_INFLAR para maximizarlo. El ejecutable que está en el zip sólo correrá si se tiene Delphi 7 instalado.

// Saludos
Archivos Adjuntos
Tipo de Archivo: zip AppSysMenu.zip (8,8 KB, 49 visitas)
Responder Con Cita
  #3  
Antiguo 27-10-2006
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Otra forma, mucho más elegante y mucho más completa de alterar el menú de sistema de la aplicación, es usando la componente TTaskbarMenu de Zarco Gajic, que recién descubro.

// Saludos
Responder Con Cita
  #4  
Antiguo 27-10-2006
Avatar de Neftali [Germán.Estévez]
Neftali [Germán.Estévez] Neftali [Germán.Estévez] is offline
[becario]
 
Registrado: jul 2004
Ubicación: Barcelona - España
Posts: 18.285
Poder: 10
Neftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en bruto
Cita:
Empezado por roman
...Haciendo pruebas, creo que he logrado algo
...tú también te lo pasas bien con los ejempillos, ehhhh Román...
__________________
Germán Estévez => Web/Blog
Guía de estilo, Guía alternativa
Utiliza TAG's en tus mensajes.
Contactar con el Clubdelphi

P.D: Más tiempo dedicado a la pregunta=Mejores respuestas.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Una pequeña corrección Faust Varios 1 07-07-2006 07:10:39
Ayuda en correccion de ejercicios sql fede7 SQL 3 21-06-2005 12:46:44
Desplegar por código el menú de sistema de una ventana Jan_polero API de Windows 7 06-05-2005 12:35:25


La franja horaria es GMT +2. Ahora son las 20:49:14.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi