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 アプリを閉じると、フェードはほぼ瞬時に行われます (せいぜい 1/4 秒で、まばたきするとトランジションを見逃してしまいます)。

パフォーマンス オプションを「最高のパフォーマンスに調整する」に設定した場合</p>

  • 同じアプリを終了すると、フェードに 12 秒以上かかります。
  • 同じコードを使用して AlphaBlendValue の変更をコメント アウトすると、遅延が解消されます。

Delphi 2010 と DelphiXE2 の両方でこれをテストしましたが、結果は同じです。これは Windows 7 Ultimate 64 ビットでテストされており、違いが生じる場合があります。

控えめに言っても、この振る舞いは私を当惑させます。

  • フォームの Alpha プロパティは GPU によって処理されるため、CPU パフォーマンスの最大化を目標とする Windows パフォーマンス設定の影響を受けないと考えました。

これに関する限り、これが Windows 7 のバグなのか、Delphi のバグなのか、単に私の知識不足なのかはわかりません。

修正に関しては...アプリでアルファフェード効果を無効にできるように、Windowsががらくたグラフィックス/最大パフォーマンスモードで実行されているかどうかを確認する方法はありますか?


わかりやすくするために編集: フェードを修正したいのですが、本当に探しているのは、Windows のパフォーマンス設定が何であるかを判断する方法です。

特定の Windows 設定を決定する方法を探しています。Windows パフォーマンス オプションに移動すると、3 つのタブがあります。最初のタブ「視覚効果」には、3 つの既定のオプションと「カスタム」の 4 番目のオプションがあります。最低限、選択されたオプションが「最高のパフォーマンスに調整する」であるかどうかを判断しようとしています。このタブの設定がさらに優れているかどうかを判断できるかどうか.


どんな助けにも感謝します。

4

2 に答える 2

7

コードの根本的な問題は、マシンのパフォーマンス特性に関係なく、256 の個別の更新を強制していることです。255 から 0 までのすべてのアルファ ブレンド値を使用する必要はありません。いくつかの値をスキップしても、滑らかなフェードを維持できます。

マシンの実際のグラフィックス パフォーマンスを考慮する必要があります。それを予測することはできないため、フェード コードではリアルタイムを考慮する必要があります。そうすることで、マシンのパフォーマンス特性に関係なく、一貫したフェード率が得られます。

そこで、フェード レートをリアルタイムに結び付ける簡単な例を次に示します。

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 秒です。数学を簡単に調整して、要件に合わせて期間を変更できます。このコードは、パフォーマンスの低いマシンでもスムーズなフェードを生成します。

drmMainまた、TfrmMainメソッドでグローバル変数を使用しないでください。メソッドはTfrmMainすでにインスタンスにアクセスできます。ですSelf。もちろん、 . は省略できますSelf。さらに呼び出しProcessMessagesが悪いです。これにより、キューに入れられた入力メッセージを再入可能に処理できます。あなたはそれが起こることを望んでいません。したがって、への呼び出しを削除しますProcessMessages


あなたは実際に、最高のパフォーマンスを得るために調整する設定を検出することについて質問します。しかし、それは間違った質問だと思います。まず、フェードの持続時間がグラフィックス パフォーマンスに依存しないように、フェード コードを修正する必要があります。

これを行っても、ユーザーが低品質の外観設定を要求した場合は、フェードを無効にしたい場合があります。あなたが言及した3つの缶詰オプションの1つを探すべきではないと思います. それらはおそらく 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

フォローアップが遅れて申し訳ありませんが、私の質問に対する実用的な回答とその背後にあるいくつかの問題を理解するのにしばらく時間がかかりました.

まず、フェード ループを処理するためのより良い方法についての洞察と、Delphi の診断ユニットからの TStopWatch 関数に関する情報について、David Heffernan に感謝します。

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 グラスをオンまたはオフにすると、これらの同じ 2 つの設定に影響することが判明しました。そのため、Aero Glass がオンになっているかどうかを検出できるため、アプリでトランジション フェードやその他の視覚効果などのフォーム エフェクトを有効にするかどうかを決定できます。さらに、バグ レポートでその情報を取得できるようになりました。

**これは NVidia の問題/バグ、または少なくとも NVidia グラフィックス カードを搭載したシステムではより深刻な問題であると思われることに注意してください。2 つの異なる NVidia システム (最新ではないにしても、最新のドライバーを使用) で、混合フォーム フェードで同様の結果が得られました。Aero Glass がオンの場合は 0.001 秒未満、Aero Glass がオフの場合は約 12 秒です。Intel グラフィックス カードを搭載したシステムでは、Aero Glass がオンの場合は 0.001 秒未満、Aero Glass がオフの場合は約 3.7 秒です。3 つの NVidia システム (最初に問題を報告した顧客を数えます) と 1 つの非 NVidia システムのテスト サンプリングが小さいことは認められていますが、適切な NVidia グラフィック カードを使用している場合は、わざわざ Aero Glass をオフにする必要はありません。

以下は、Aero Glass が Delphi 経由で有効になっているかどうかを検出する作業コードです。この機能は、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 に答える