TActionMainMenuBar и TActionToolbar теряют настройки

недавно я наткнулся на очень странное поведение. Когда я использую TActionMainMenuBar (или TActionToolBar) в своей программе, компилирую и запускаю, а затем запускаю Photoshop CS5 или Internet Explorer 9, ActionMainMenuBar (и ActionToolBar) теряет все свои настройки. Цвета, определенные в назначенной цветовой карте, исчезают, а настройки шрифта также теряются. Кто-нибудь видел это раньше и знает обходной путь?

D2007 Pro( все обновления применены), D2010 Pro (все обновления применены), Vista Home Premium 32 бит, NVidia GForce 8600 GT, установлен последний драйвер.

воспроизведение:

  1. отбросьте TActionManager и TActionMainMenuBar в форме
  2. создать Категорию с некоторыми пунктами меню
  3. перетащите категорию на ActionMainMenuBar
  4. назначить TwilightColorMap для ActionMainMenuBar
  5. запустить программу
  6. запустите IE9 или Photoshop CS5
  7. смотреть все предопределенные настройки исчезают (вам нужно снова закрыть IE9, чтобы увидеть эффект)

Если вы сначала запустите Photoshop или IE, а затем программу Delphi, ничего не произойдет. Ошибка также присутствует в режиме разработки в среде IDE. Другой разработчик уже подтвердил описанное поведение для своей системы с Win7 Pro 32bit и Ati Radeon 9800 Pro.

Thx для любых комментариев / решений

Фил

PS: использование Photoshop CS3 не создает эту ошибку

2 ответов


вот еще один способ воспроизведения проблемы:

  • выполните шаги с 1 по 4, как в вопросе (включая удаление TwilightColorMap).
  • добавить кнопку в форму с кодом  Perform(WM_SETTINGCHANGE, 0, 0); в обработчике щелчка.
  • запустите приложение и нажмите кнопку.


Итак, теперь мы знаем, что A WM_SETTINGCHANGE broadcast может вызвать проблему, мы могли бы задаться вопросом, если запуск 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, через несколько секунд ниже появляется в заметке:

0000, Программное Обеспечение\Microsoft\Internet Explorer\SearchScopes

Я понятия не имею, что IE должен сказать нашей форме (и всем другим окнам верхнего уровня) при каждом запуске, и я не знаю, делает ли он это на каждом окне окна на земле или только ваши и мои, но, очевидно,ActionMainMenuBarне хорош в обращении он.


a win control (форма), получение WM_WININICHANGE выполняет CM_WININICHANGE и после получения он передает то же самое всем своим элементам управления. Ниже показано, как он обрабатывается в строке меню:

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

думая, что шрифт системного меню мог быть изменен (код должен был искать раздел "WindowsThemeElement" или "WindowMetrics" в сообщении, но в любом случае..), он переназначается из обновленного Screen.MenuFont. Проблема в том, что мы не были использующий ее.

кроме того, цветовая карта отвечает на CM_WININICHANGE сбросив его цвета, вызвав его UpdateColors метод. Это даже документирована:

UpdateColors вызывается автоматически, когда компонент ActionBand получает сообщение CM_WININICHANGE.


Поэтому решение будет включать в себя решение, что делать, и переопределение обоих действий, я попытался прокомментировать приведенное ниже Решение почему я считаю, что это было бы правильным решением:
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 88FF;
    // 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 := 88FF;
end;

нашли его! Проблема заключалась в том, что свойство Colormap ActionMainMenuBar1 сбрасывается в ActionMainMenuBar1.DefaultColormap каждый раз, когда IE9 или Photoshop CS5 запускается / закрывается. Я приму решение Сертака как ответ, потому что он указал мне в правильном направлении, как решить эту проблему.

вот окончательный код. Он работает безупречно (насколько я могу судить) как с 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.

еще раз спасибо всем за вашу помощь.