Pregunta

Estoy de pintura personalizada de mi barra de título en una gran aplicación con muchas formas y ha decidido intentar y hacerlo a la antigua usanza por el manejo de algunos de los mensajes de mí mismo y dong el dibujo cuando estoy manejando WM_NCPAINT.

La pintura en sí es que va bastante bien y esencialmente funciona.Una cosa que no funciona a pesar de que es la pintura de la TMainMenu.Yo tengo el defecto WM_NCACTIVATE controlador de dibujar todo el área no cliente (tengo que Realizar un WM_NCACTIVATE mensaje dentro de mi WM_NCPAINT controlador) antes de pintar sobre él, lo que provoca el parpadeo de la que aparentemente no puede ser ayudado.O puedo tratar de tener el valor predeterminado del controlador de WM_NCPAINT la pintura sólo el Rectángulo que contiene el TMainMenu, que se traducen en un resultado sin problemas, pero no volver a pintar el menú.

Mi pregunta es:

  • ¿Cómo puedo tener un TMainMenu y sólo un TMainmenu repintado cuando estoy manejando WM_NCPAINT a mí mismo?

He dado un par de va y creo que estoy en el camino correcto, pero estoy golpeando la pared;No tengo suficiente conocimiento acerca de lo que estoy haciendo y parece que no puede encontrar una documentación clara sobre ella.La parte más importante de mi código es:

RedrawWindow(Handle, nil, MenuRegion, RDW_INVALIDATE or RDW_FRAME or RDW_NOERASE or RDW_ALLCHILDREN or RDW_UPDATENOW);

Y creo que es exactamente eso lo que va mal.(o más bien, el código donde puedo calcular 'MenuRegion'.Sólo tengo ni idea de si va mal porque estoy usando el mal sistema de coordenadas o si es porque voy sobre esta completamente el camino equivocado.

He aquí una versión reducida de mi código que se compila y ejecuta 'como es' en delphi (xe3):

unit Unit3;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus;
type
  TForm3 = class(TForm)
  private
    FDrawMenu: Boolean;
    function CalcFrameRegion: HRGN;
    function CalcMenuRegion: HRGN;
    procedure DrawMenu;
    procedure FormFrame(minimal: Boolean = false);
    procedure WMNCActivate(var message: TWMNCActivate); message WM_NCACTIVATE;
    procedure WMNCPaint(var message: TMessage); message WM_NCPAINT;
    procedure WMSIZE(var message : TWMSIZE); message WM_SIZE;
    constructor Create(AOwner: TComponent); override;
  public
    { Public declarations }
  end;
var
  Form3: TForm3;
implementation
{$R *.dfm}
{ TForm3 }
function TForm3.CalcFrameRegion: HRGN;
var
  YCaption, YFrame, XFrame: Integer;
begin
  YCaption := GetSystemMetrics(SM_CYCaption);
  YFrame := GetSystemMetrics(SM_CYFRAME);
  XFrame := GetSystemMetrics(SM_CXFRAME);
  Result :=  CreateRectRgn(0, 0, YCaption + YFrame, Width);
  Result := Result +  CreateRectRgn(0, 0, Height, XFrame);
  Result := Result + CreateRectRgn(0, Height - YFrame, Width, Height);
  Result := Result + CreateRectRgn(Width - XFrame, 0, Width, Height);
end;
function TForm3.CalcMenuRegion: HRGN;
var
  XFrame, YFrame, YCaption, YMenu: Integer;
begin
  XFrame := GetSystemMetrics(SM_CXFRAME);
  YFrame := GetSystemMetrics(SM_CYFRAME);
  YCaption := GetSystemMetrics(SM_CYCAPTION);
  YMenu := GetSystemMetrics(SM_CYMENU);
  Result := CreateRectRgn(XFrame, YFrame + YCaption, Width - XFrame, YFrame + YCaption + YMenu);
end;
constructor TForm3.Create(AOwner: TComponent);
var
  testItem: TMenuItem;
begin
  inherited;
  // Creating a MainMenu and attatching it to the form.
  Menu := TMainMenu.Create(self);
  // The menu need san item.
  testItem := TMenuItem.Create(Menu);
  testItem.Caption := 'test';
  Menu.Items.Add(testItem);
  FDrawMenu := false;
end;
procedure TForm3.FormFrame(minimal: Boolean);
var
  YCaption, YFrame, XFrame: Integer;
begin
  YCaption := GetSystemMetrics(SM_CYCaption);
  YFrame := GetSystemMetrics(SM_CYFRAME);
  XFrame := GetSystemMetrics(SM_CXFRAME);
  Canvas.Handle := GetWindowDC(Handle);
  Canvas.Pen.Style := psClear;
  Canvas.Brush.Style := bsSolid;
  Canvas.Brush.Color := clRed;
  if not minimal then begin
    Canvas.Rectangle(0, 0, Width + 1, YCaption + YFRame + 1);
    Canvas.Rectangle(0, YCaption + YFRame, XFrame + 1, Height + 1);
    Canvas.Rectangle(XFrame, Height - YFrame, Width + 1, Height + 1);
    Canvas.Rectangle(Width - XFrame, YCaption + YFRame, Width + 1, Height - YFrame + 1);
  end;
end;
procedure TForm3.DrawMenu;
var
  MenuRegion: HRGN;
begin
  if Assigned(Menu) then begin
    MenuRegion := CalcMenuRegion;
    FDrawMenu := true; // Make sure the inherited handler gets called.
    // Force a redraw of the region defined by MenuRegion.
    RedrawWindow(Handle, nil, MenuRegion,
                  RDW_INVALIDATE or RDW_FRAME or RDW_NOERASE or RDW_ALLCHILDREN or RDW_UPDATENOW);
    FDrawMenu := false; // Use the FormFrame function again.
  end;
end;
procedure TForm3.WMNCActivate(var message: TWMNCActivate);
begin
  FormFrame;
  message.Result := 1; // This makes sure the message gets handled properly.
end;
procedure TForm3.WMNCPaint(var message: TMessage);
begin
  if FDrawMenu then
    inherited // Gets called when the Menu has to be drawn.
  else
    FormFrame; // Gets called in all other cases.
end;
procedure TForm3.WMSIZE(var message: TWMSIZE);
begin
  inherited;
  DrawMenu;
end;
end.
¿Fue útil?

Solución

"¿Cómo puedo tener un TMainMenu y sólo un TMainmenu repintado cuando estoy manejando WM_NCPAINT a mí mismo?"

En teoría, usted puede modificar la región WM_NCPAINT es pasado.Definir una región que corresponde a la zona de la barra de menú, de dejar fuera el resto.La siguiente es una prueba de concepto:

procedure TForm3.WMNCPaint(var Message: TWMNCPaint);
var
  R: TRect;
  MenubarInfo: TMenuBarInfo;
  MenuRgn: HRGN;
begin
  FormFrame( whatever );

  MenubarInfo.cbSize := SizeOf(MenubarInfo);
  GetMenuBarInfo(Handle, OBJID_MENU, 0, MenubarInfo);

  MenuRgn := CreateRectRgnIndirect(MenubarInfo.rcBar);
  if Message.RGN <> 1 then
    DeleteObject(Message.RGN);
  Message.RGN := MenuRgn;

  inherited;
end;


En la práctica, será en última instancia, abandonar esta ruta.Nota la prueba de '1' en el ejemplo anterior.Un pseudo mango para la actualización de la región es que no se menciona en el documentación.Sin embargo, la región de la manija es siempre " 1 " para una ventana normal.Como cuestión de hecho, no cliente manejo nunca ha sido debidamente documentados.Mi conjetura es que eso es porque el sistema operativo en sí no juega por las reglas.Por ejemplo, el hecho de que el NC del área a ser pintada durante el tratamiento predeterminado de WM_NCACTIVATE.Lo que hace la activación tiene nada que ver con la NC pintura.¿Por qué OS pinturas detrás de su espalda?

Mi sugerencia es, tomar la ruta que VCL estilos han tomado.Una vez que esté en la elaboración de área de carolina de norte, dibujar todo.Barra de menús de la zona es parte de la área de cliente no.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top