TActionMainMenuBar和TActionToolbar丢失设置

时间:2012-03-06 03:31:47

标签: delphi internet-explorer-9 photoshop

我最近偶然发现了一个非常奇怪的行为。当我在程序中使用TActionMainMenuBar(或TActionToolBar),编译并运行,然后启动Photoshop CS5或Internet Explorer 9时,ActionMainMenuBar(和ActionToolBar)将丢失其所有设置。指定的色彩映射中定义的颜色消失,字体设置也会丢失。有没有人见过这个并知道解决方法?

D2007 Pro(所有更新均已应用),D2010 Pro(已应用所有更新),Vista Home Premium 32位,NVidia GForce 8600 GT,已安装最新驱动程序。

重现的步骤:

  1. 在表单
  2. 上删除TActionManager和TActionMainMenuBar
  3. 使用某些菜单项创建一个类别
  4. 将类别拖到ActionMainMenuBar
  5. 将TwilightColorMap指定给ActionMainMenuBar
  6. 运行程序
  7. 启动IE9或Photoshop CS5
  8. 观看所有预定义设置消失(您必须再次关闭IE9以查看效果)
  9. 如果先启动Photoshop或IE,再启动Delphi程序,则不会发生任何事情。在IDE中的设计模式下,该错误也存在。一位开发人员已经使用Win7 Pro 32bit和ATI Radeon 9800 Pro确认了他所描述的系统行为。

    任何评论/解决方案的Thx

    菲尔

    PS:使用Photoshop CS3不会产生此错误

2 个答案:

答案 0 :(得分:8)

这是另一种重现问题的方法:

  • 完成问题中的步骤1到4(包括删除TwilightColorMap)。
  • 在表单中添加一个按钮,其单击处理程序中包含代码 Perform(WM_SETTINGCHANGE, 0, 0);
  • 运行应用程序并按下按钮。


现在我们知道WM_SETTINGCHANGE广播可能导致问题,我们可能想知道启动IE会产生相同的问题:

type
  TForm1 = class(TForm)
    ..
  protected
    procedure WMSettingChange(var Message: TWMSettingChange);
      message WM_SETTINGCHANGE;
    ..

procedure TForm1.WMSettingChange(var Message: TWMSettingChange);
begin
  Memo1.Lines.Add(IntToHex(Message.Flag, 4) + ', ' + Message.Section);
  inherited;
end;

在我们运行我们的应用程序然后启动IE之后,几秒钟后,以下内容出现在备忘录中:

  <00> 0000,Software \ Microsoft \ Internet Explorer \ SearchScopes

我不知道IE在每次发布时对我们的表单(以及所有其他顶级窗口)说什么,我不知道它是在地球上的每个Windows机箱上执行此操作还是仅仅是您的而我的,但显然ActionMainMenuBar并不擅长处理它。


获胜控件(表单),接收WM_WININICHANGE,执行CM_WININICHANGE,并在收到后将其广播到其所有控件。以下是菜单栏的处理方式:

procedure TCustomActionMainMenuBar.CMWininichange(var Message: TWMWinIniChange);
begin
  inherited;
  RequestAlign;
  Font.Assign(Screen.MenuFont);
end;

认为系统菜单字体可能已被更改(代码应该在消息中查找&#39; WindowsThemeElement&#39; WindowMetrics&#39;部分,但无论如何..),它从刷新的Screen.MenuFont重新分配。问题是,我们并没有完全使用它。

此外,ColorMap通过调用其CM_WININICHANGE方法重置其颜色来响应UpdateColors。这甚至是documented

  当ActionBand组件收到CM_WININICHANGE消息时,会自动调用

UpdateColors

<小时/> 所以解决方案将涉及决定做什么和覆盖两种行为,我试图评论下面的解决方案,为什么我认为这将是正确的解决方案:

type
  // Derive your own ColorMap that would reset its own colors.
  // This is an interposer for simplicity..
  TTwilightColorMap = class(actncolormaps.TTwilightColorMap)
  public
    procedure UpdateColors; override;
  published
    property Color default clGreen;
    property FontColor default clYellow;
    property MenuColor default $4488FF;
    // reintroduce as many property as necessary, probably all is necessary..
  end;

  TForm1 = class(TForm)
    ..
  private
    FSaveMenuFont: TFont; // will hold initial main menu bar's font settings
  protected
    procedure WMSettingChange(var Message: TWMSettingChange);
      message WM_SETTINGCHANGE;
  end;

..

procedure TForm1.FormCreate(Sender: TObject);
begin
  FSaveMenuFont := TFont.Create;
  FSaveMenuFont.Assign(ActionMainMenuBar1.Font);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FSaveMenuFont.Destroy;
end;

procedure TForm1.WMSettingChange(var Message: TWMSettingChange);
begin
  inherited;
  // The below are the *section*s that really changing system settings
  // would notify that I'm aware of, there may be more...
  if (Message.Section <> 'WindowsThemeElement')
      or (Message.Section <> 'WindowMetrics') then
    ActionMainMenuBar1.Font.Assign(FSaveMenuFont)
  else
    // Develop your logic here. The system menu font might really have been
    // changed. You can get it from Screen.MenuFont. But then if we had been
    // using the system font, the control already applies the change by default.

end;

procedure TTwilightColorMap.UpdateColors;
begin
  inherited;
  // Reset your colors, note that system colors might have been
  // changed or not. If changed, they should be reflected in 'cl..' constants.
  Color := clGreen;
  FontColor := clYellow;
  MenuColor := $4488FF;
end;

答案 1 :(得分:4)

发现它!问题是每次启动/关闭IE9或Photoshop CS5时,ActionMainMenuBar1的Colormap属性都会重置为ActionMainMenuBar1.DefaultColormap。我会接受Sertac的解决方案作为答案,因为它指出了如何解决这个问题的正确方向。

这是最终的代码。现在,IE9和Photoshop CS5都可以完美运行(据我所知)。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ActnMan, ActnColorMaps, ActnList, ToolWin, ActnCtrls, ActnMenus,
  StdCtrls;


type
  TForm1 = class(TForm)
    ActionManager1: TActionManager;
    ActionMainMenuBar1: TActionMainMenuBar;
    Action1: TAction;
    Action2: TAction;
    Action3: TAction;
    Action4: TAction;
    TwilightColorMap1: TTwilightColorMap;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ActionMainMenuBar1GetControlClass(Sender: TCustomActionBar;
      AnItem: TActionClient; var ControlClass: TCustomActionControlClass);
  protected
    procedure WMSettingChange(var Message: TWMSettingChange); message WM_SETTINGCHANGE;
  private
    { Private declarations }
    FSaveMenuFont: TFont; // will hold initial main menu bar's font settings
    FSaveColormap: TTwilightColormap;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


// Fixing paint issue when IE9 was run and closed again

procedure TForm1.ActionMainMenuBar1GetControlClass(Sender: TCustomActionBar;
  AnItem: TActionClient; var ControlClass: TCustomActionControlClass);
begin
  ActionMainMenuBar1.ColorMap.Assign(FSaveColormap);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  FSaveMenuFont := TFont.Create;
  FSaveMenuFont.Assign(ActionMainMenuBar1.Font);
  FSaveColormap := TTwilightColormap.Create(Self);
  FSaveColormap.Assign(ActionMainMenuBar1.Colormap);
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
  FSaveMenuFont.Destroy;
  FSaveColormap.Destroy;
end;


procedure TForm1.WMSettingChange(var Message: TWMSettingChange);
begin
  inherited;
  // Memo1.Lines.Add(IntToHex(Message.Flag, 4) + ', ' + Message.Section);
  ActionMainMenuBar1.Font.Assign(FSaveMenuFont);
  // In case Photoshop CS5 was run and closed before
  ActionMainMenuBar1.ColorMap.Assign(FSaveColormap);
end;

end.

再次感谢大家的帮助。