Delphi изменить цвет главного меню

#delphi #menu

#delphi #меню

Вопрос:

Я создаю свой собственный OnAdvancedDrawItem, чтобы изменить цвет основного меню. Это работает хорошо, но я получаю раздражающую белую линию внизу.

строка под главным меню

Он исчезает при наведении курсора мыши на меню, но возвращается при выборе другого приложения. Как я могу избавиться от этого?

Вот мой базовый код для окраски фона.

 unit MenMain;

interface

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, Menus, ImgList, StdCtrls;

type
  TForm1 = class(TForm)
  MainMenu1: TMainMenu;
  File2: TMenuItem;
  Edit1: TMenuItem;
  Window1: TMenuItem;
  procedure Window1AdvancedDrawItem(Sender: TObject; ACanvas: TCanvas; ARect: TRect; State: TOwnerDrawState);
private

public

end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Window1AdvancedDrawItem(Sender: TObject; ACanvas: TCanvas;  ARect: TRect; State: TOwnerDrawState);
begin
  with TMenuItem(Sender) do
  begin
    with ACanvas do
    begin
      Brush.Color := clMoneyGreen;
      Inc(ARect.Bottom,1);
      FillRect(ARect);
      Font.Color := clBlue;
      DrawText(ACanvas.Handle, PChar(Caption),Length(Caption),ARect,          DT_SINGLELINE or DT_VCENTER);
    end;
  end;
end;

end.
 

Комментарии:

1. Это, кажется, доказывает, для чего нужен ‘aRect’, чтобы указать область, которую вы можете нарисовать. То, что вы рисуете снаружи, может быть перерисовано позже. В нижней строке, вероятно, находится область NC за пределами области элементов.

2. Могу я спросить, почему вы не используете TMainActionMenuBar ? Вы можете подключить его TStandardColorMap и добиться желаемого эффекта.

Ответ №1:

ARect Параметр обработчика OnAdvancedDrawItem события rcItem DRAWITEMSTRUCT — это параметр, который передается в WM_DRAWITEM сообщение. В документации есть это, чтобы сказать о прямоугольнике:

Прямоугольник, который определяет границы элемента управления, который нужно нарисовать. Этот прямоугольник находится в контексте устройства, указанном участником hDC. Система автоматически обрезает все, что окно владельца отображает в контексте устройства для полей со списком, списков и кнопок, но не обрезает пункты меню. При рисовании элементов меню окно владельца не должно выходить за границы прямоугольника, определенного элементом rcItem.


Таким образом, хотя контекст устройства не привязан к прямоугольнику, вы несете ответственность за то, чтобы не рисовать за его пределами. Это происходит, когда вы выполняете Inc(ARect.Bottom,1); перед заполнением прямоугольника.

Комментарии:

1. Ваш ответ очень поучителен. Однако это все еще оставляет меня с проблемой предотвращения закрашивания Windows белой строки под строкой меню, когда перерисовка инициируется не действиями меню.

2. @Rudi — Ну, ответ по сути подразумевал «вы не можете от него избавиться». По крайней мере, нелегко. Вы не сможете добиться этого с помощью меню, нарисованных владельцем. Вы должны предположить, что не клиентская область рисуется самостоятельно. Я чувствую, что это сложная тема, которая выходит за рамки этого вопроса. Я, конечно, тоже не рекомендую. Как вы сами видели, ОС вмешивается в процесс рисования NC в довольно странные моменты, например, при деактивации окна.

Ответ №2:

Вы можете изменить цвет серой области. Используйте это в onCreate и OnCanResize

 global var - fMenuBrushHandle: THandle;

var
  lMenuInfo: TMenuInfo;
  lMenuColor: TColor;
begin
  lMenuColor := clRed;

  DeleteObject(fMenuBrushHandle);
  fMenuBrushHandle := CreateSolidBrush(ColorToRGB(lMenuColor));

  FillChar(lMenuInfo, SizeOf(lMenuInfo), 0);

  lMenuInfo.cbSize := SizeOf(lMenuInfo);
  lMenuInfo.hbrBack := fMenuBrushHandle;
  lMenuInfo.fMask := MIM_BACKGROUND;
  SetMenuInfo(MainMenu1.Handle, lMenuInfo);
end;
 

или

 global var - FBrush: TBrush;

var
  lMenuInfo: TMenuInfo;
begin
  if not Assigned(FBrush) then
     FBrush := TBrush.Create;
  FBrush.Color := clRed;
  FBrush.Style := bsSolid;

  lMenuInfo.cbSize := SizeOf(lMenuInfo);
  lMenuInfo.fMask := MIM_BACKGROUND;
  lMenuInfo.hbrBack := FBrush.Handle;
  SetMenuInfo(MainMenu1.Handle, lMenuInfo);
end;
 

или даже нарисовать растровое изображение

 global var
  fMenuHandle:THandle;
  fBitmap:Tbitmap;

var
  lMenuInfo:TMenuInfo;
begin
  if Assigned(fBitmap) then
    fBitmap.Free;
  fBitmap:=TBitmap.Create;
  fBitmap.Width:=21;
  fBitmap.Height:=Form1.Width;

  DeleteObject(fMenuHandle);
  fMenuHandle:=CreatePatternBrush(fBitmap.Handle);
  Fillchar(lMenuInfo,SizeOf(lMenuInfo),0);

  lMenuInfo.cbSize:=SizeOf(lMenuInfo);
  lMenuInfo.fMask:=MIM_BACKGROUND;
  lMenuInfo.hbrBack:=fMenuHandle;
  SetMenuInfo(MainMenu1.Handle,lMenuInfo);
end;