Domanda

Sono personalizzato dipingere la mia barra di didascalia in un'applicazione piuttosto ampia con molte forme e ha deciso di provare a farlo il modo vecchio stile maneggiando alcuni messaggi e dong il disegno quando sto maneggiando wm_ncpaint. .

Il dipinto stesso sta andando abbastanza bene ed essenzialmente funziona. Una cosa che non funzionerà però sta dipingendo il Tmainmenu. Opponi il gestore WM_NCACTIVATE predefinito Disegna l'intera area non Asclient (devo eseguire un messaggio WM_NCACTIVATE all'interno del mio gestore WM_NCPaint) prima di dipingere su di esso, il che causa tremolante che apparentemente non può essere aiutato. Oppure posso provare ad avere il gestore predefinito di wm_ncpaint dipingere solo il retto contenente il tmainmenu, che provoca un risultato regolare, ma non ridimensiona il menu.

La mia domanda è:

    .
  • Come posso avere un tmainmenu e solo un tmainmenu ridipinto quando sto maneggiando wm_ncpaint me stesso?

L'ho dato alcuni vai e penso di essere nel modo giusto, ma sto colpendo un muro; Non ho abbastanza conoscenza su ciò che sto facendo e non riesco a trovare una chiara documentazione a riguardo. La parte più importante del mio codice è:

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

E penso che sia esattamente che ciò che va storto. (o meglio, il codice in cui calcolò 'menuregion'. Non ho alcun indizio se sta andando male perché sto usando il sistema di coordinate sbagliato o se è perché sto andando su questo completamente il modo sbagliato.

Ecco una versione ridotta del mio codice che si compilerà ed eseguirà 'come è' in 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.
.

È stato utile?

Soluzione

"Come posso avere un tmainmenu e solo un tmainmenu ridipinto quando sto maneggiando wm_ncpaint me stesso?"

In teoria è possibile modificare la regione WM_NCPAINT. Definire una regione che corrisponde all'area della barra dei menu, lascia il resto. La seguente è una prova del concetto:

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;
.



In pratica, alla fine avrai abbandonato questa rotta. Nota il test per '1' nel campione di cui sopra. Una maniglia pseudo per la regione di aggiornamento non è menzionata nel Documentazione . Eppure la maniglia della regione è sempre '1' per una finestra normale. In effetti la gestione non client non è mai stata correttamente documentata. La mia ipotesi è, per questo perché il sistema operativo stesso non gioca per le regole. Prendiamo ad esempio il fatto che l'area NC viene dipinta durante la gestione predefinita di WM_NCACTIVATE. Che cosa ha nulla a che fare con la pittura NC. Perché il sistema operativo dipinge dietro la schiena?

Il mio suggerimento è, prendere il percorso che gli stili VCL hanno preso. Una volta che sei nel disegno dell'area NC, disegna tutto. L'area della barra dei menu è parte dell'area non client.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top