2

以下代码是关闭我的应用程序。

procedure TfrmMain.btnClose1Click(Sender: TObject);
var
  i : Integer;
begin
  for i := 255 downto 0 do begin
    frmMain.AlphaBlendValue := i;
    application.ProcessMessages;
  end;

  Close;
end;

将 Windows 性能设置为“让 Windows 选择...”</p>

  • 当使用上面的代码关闭我的 Delphi 应用程序时,淡入淡出几乎是瞬间的(最多可能是 ¼ 秒,如果我眨眼我会错过过渡)。

如果我将性能选项设置为“调整以获得最佳性能”</p>

  • 退出同一个应用程序时,淡入淡出需要 12 秒以上。
  • 使用相同的代码但注释掉 AlphaBlendValue 更改可以消除延迟。

我在 Delphi 2010 和 DelphiXE2 上对此进行了测试,结果是一样的。如果这有什么不同的话,这是在 Windows 7 Ultimate 64bit 上测试的。

至少可以说这种行为让我感到困惑。

  • 我认为 forms Alpha 属性由 GPU 处理,因此不会受到旨在最大化 CPU 性能的 Windows 性能设置的影响。

因此,就这一点而言,我不确定这是 Windows 7 错误、Delphi 错误还是只是我缺乏知识。

至于修复...有没有办法判断 Windows 是否在垃圾图形/最大性能模式下运行,以便我可以在我的应用程序中禁用 Alpha 淡入淡出效果?


为清楚起见进行编辑:虽然我想修复淡入淡出,但我真正想要的是一种确定 Windows 性能设置的方法。

我正在寻找如何确定特定的 Windows 设置 - 当您进入 Windows 性能选项时,有 3 个选项卡。在第一个选项卡“视觉效果”上有 3 个预设选项和第 4 个选项用于“自定义”。至少我试图确定选择的选项是否是“调整以获得最佳性能”,如果我可以更好地确定此选项卡上的设置。


感谢任何帮助。

4

2 回答 2

7

您的代码的根本问题是,无论机器的性能特征如何,您都在强制进行 256 次不同的更新。您不必使用 255 和 0 之间的每一个 alpha 混合值。您可以跳过一些值并仍然具有平滑的淡入淡出。

您需要考虑机器的实际图形性能。由于您无法预测,因此您应该在淡入淡出代码中考虑实时。无论您的机器的性能特点如何,这样做都会为您提供一致的褪色率。

所以,这里有一个简单的例子来演示将淡入淡出率与实时联系起来:

procedure TfrmMain.btnClose1Click(Sender: TObject);
var
  Stopwatch: TStopwatch;
  NewAlphaBlendValue: Integer;
begin
  Stopwatch := TStopwatch.StartNew;
  while True do
  begin
    NewAlphaBlendValue := 255-(Stopwatch.ElapsedMilliseconds div 4);
    if NewAlphaBlendValue>0 then
      AlphaBlendValue := NewAlphaBlendValue
    else
      break;
  end;
  Close;
end;

淡入淡出的持续时间为 1 秒。您可以轻松地调整数学以根据您的要求修改持续时间。即使在性能不佳的机器上,此代码也会产生平滑的淡入淡出。

我还要评论说,您不应该drmMainTfrmMain方法中使用全局变量。该TfrmMain方法已经可以访问该实例。它是Self。当然,您可以省略Self. 更ProcessMessages糟糕的是。这允许对排队的输入消息进行重入处理。你不希望这种情况发生。所以删除对ProcessMessages.


您实际上询问是否检测“调整以获得最佳性能”设置。但我认为这是一个错误的问题。首先,您应该修复您的淡入淡出代码,以便淡入淡出持续时间与图形性能无关。

完成此操作后,如果用户要求较低质量的外观设置,您可能仍希望禁用淡入淡出。我认为您不应该寻找您提到的 3 个罐装选项之一。它们很可能是特定于 Windows 版本的。在最小化和最大化设置时,我个人会将行为基于Animate 窗口。我的理由是,如果用户不希望最小化和最大化动画,那么大概他们不希望关闭窗口被淡化。

以下是读取该设置的方法:

function GetWindowAnimation: Boolean;
var
  AnimationInfo: TAnimationInfo;
begin
  AnimationInfo.cbSize := SizeOf(AnimationInfo);
  if not SystemParametersInfo(SPI_GETANIMATION, AnimationInfo.cbSize,
      @AnimationInfo, 0) then
    RaiseLastOSError;
  Result := AnimationInfo.iMinAnimate<>0;
end;

我认为您可能关心的大多数其他设置也可以使用SystemParametersInfo. 您应该能够按照文档了解如何执行此操作。

于 2012-12-17T11:03:20.847 回答
0

对于迟到的后续行动感到抱歉,但我花了一段时间才弄清楚我的问题及其背后的一些问题的有效答案。

首先,感谢 David Heffernan 对处理淡入淡出循环的更好方法以及 Delphi 诊断单元中有关 TStopWatch 功能的信息的深入了解,非常感谢。

关于能够确定 Windows 的性能设置...

使用以下未优化的淡入淡出循环时

procedure TfrmMain.btnFadeNCloseClick(Sender: TObject);
var
  i : Integer;
begin
  for i := 255 downto 0 do 
    frmMain.AlphaBlendValue := i;

  Close;
end;

导致性能问题的实际Windows 性能选项设置是“启用桌面合成”和“在 Windows 和按钮上使用视觉样式”。如果启用了这两个选项,则没有问题,如果未启用任一设置,则循环爬网**(如果表单最大化,我的系统上大约需要 12 秒)。

事实证明,打开或关闭Aero Glass会影响这两个相同的设置。因此,能够检测 Aero Glass 是否打开使我能够确定是否在我的应用程序中启用表单效果,例如过渡淡入淡出和其他吸引眼球的效果。另外,现在我还可以在我的错误报告中捕获这些信息。

**请注意,这似乎是 NVidia 问题/错误,或者至少是在配备 NVidia 显卡的系统上更为严重的问题。在 2 个不同的 NVidia 系统上(如果不是最新的驱动程序的话),我得到了类似的混合形式淡入淡出的结果——如果 Aero Glass 开启,则不到 0.001 秒,如果 Aero Glass 关闭,则大约 12 秒。在带有 Intel 显卡的系统上 - 如果 Aero Glass 开启则少于 0.001 秒,如果 Aero Glass 关闭则大约 3.7 秒。现在允许我的测试样本很小,3 个 NVidia 系统(包括我最初报告问题的客户)和一个非 NVidia 系统,但如果我使用的是像样的 NVidia 显卡,我不会费心关掉 Aero Glass。

下面是检测是否通过 Delphi 启用 Aero Glass 的工作代码: 此功能已在 Windows7 64 位系统上进行了测试,可与 Delphi 2007、2010 和 Xe2(32 和 64 位)一起使用。我在网上找到的所有各种版本的 Delphi 函数都被破坏了 - 以及人们抱怨访问冲突错误的评论。最终揭示修复错误代码的是 Gerry Coll 对Delphi 中的 AccessViolationException - 不可能(检查它,难以置信...)的回应,这是关于尝试修复同一类型函数中的 AV 错误。

function  ISAeroEnabled: Boolean;
type
  _DwmIsCompositionEnabledFunc = function(var IsEnabled: Bool): HRESULT; stdcall;
var
  Flag                       : BOOL;
  DllHandle                  : THandle;
  OsVersion                  : TOSVersionInfo;
  DwmIsCompositionEnabledFunc: _DwmIsCompositionEnabledFunc;
begin
  Result:=False;
  ZeroMemory(@OsVersion, SizeOf(OsVersion));
  OsVersion.dwOSVersionInfoSize := SizeOf(TOSVERSIONINFO);

  if ((GetVersionEx(OsVersion)) and (OsVersion.dwPlatformId = VER_PLATFORM_WIN32_NT) and
      (OsVersion.dwMajorVersion = 6) and (OsVersion.dwMinorVersion < 2)) then //Vista&Win7 only (no Win8)
  begin
    DllHandle := LoadLibrary('dwmapi.dll');
    try
      if DllHandle <> 0 then
      begin
        @DwmIsCompositionEnabledFunc := GetProcAddress(DllHandle, 'DwmIsCompositionEnabled');
        if (@DwmIsCompositionEnabledFunc <> nil) then
        begin
          if DwmIsCompositionEnabledFunc(Flag)= S_OK then
           Result:= Flag;
        end;
      end;
    finally
      FreeLibrary(DllHandle);
    end;
  end;
end;
于 2013-01-03T21:59:45.663 回答