4

以前にこの質問をして削除したのは、1) やりたいことよりも多くの作業があったように思えた、2) 質問の仕方が下手で、質問が締め切られた、という理由だけでした。しかし、さらに調査を行った結果、この機能/質問/ハウツーを再検討することにしました。

下の図に示すように、ぼやけたオーバーレイを作成しようとしています/作成したいと考えています。使用する明白な FMX.effect は、'Blur' エフェクトです。私の質問は次のとおりです:オーバーレイがカバーする画像をレンダリングする方法、または効果的な方法で画像をコピーしてオーバーレイをぼかすにはどうすればよいですか?

同じビットマップを 2 つだけ使用することを考えました。1 つは背景用、もう 1 つはぼかし用ですが、元の背景の上にあるコントロールの「ぼかし」やその他のものをキャプチャすることはできません。また、オーバーレイをスクロールして表示したり外したりすると、思ったように表示/表示されないと思います。

上記を考慮すると、オーバーレイがスクロール/表示されるときに背景を動的にキャプチャしてぼかす必要があると私は信じています。Delphi XE6 でこれを実行し、現在表示されている画面コンテンツをキャプチャするにはどうすればよいですか? どこから始めればいいのかわからない。

私は画像を所有していません*

ここに画像の説明を入力

4

2 に答える 2

7

親コントロールの背景をキャプチャする方法について少し調べた後、FMX の TMagnifierGlass クラスに基づいて次のコードを思いつきました (このコードは XE5 で作成したことに注意してください。XE6 の互換性を確認する必要があります)。

TGlass = class(TControl)
private
  FBlur: TBlurEffect;
  FParentScreenshotBitmap: TBitmap;
  function GetSoftness: Single;
  procedure SetSoftness(Value: Single);
protected
  procedure Paint; override;
public
  constructor Create(AOwner: TComponent);
  destructor Destroy; override;
  property Softness: Single read GetSoftness write SetSoftness;
end;


{ TGlass }

constructor TGlass.Create(AOwner: TComponent);
begin

  inherited Create(AOwner);

  // Create parent background
  FParentScreenshotBitmap := TBitmap.Create(0, 0);

  // Create blur
  FBlur := TBlurEffect.Create(nil);
  FBlur.Softness := 0.6;

end;

destructor TGlass.Destroy;
begin

  FBlur.Free;
  FParentScreenshotBitmap.Free;

  inherited Destroy;

end;

function TGlass.GetSoftness: Single;
begin

  Result := FBlur.Softness;

end;

procedure TGlass.SetSoftness(Value: Single);
begin

  FBlur.Softness := Value;

end;

procedure TGlass.Paint;
var
  ParentWidth: Single;
  ParentHeight: Single;

  procedure DefineParentSize;
  begin
    ParentWidth := 0;
    ParentHeight := 0;
    if Parent is TCustomForm then
    begin
      ParentWidth := (Parent as TCustomForm).ClientWidth;
      ParentHeight := (Parent as TCustomForm).ClientHeight;
    end;
    if Parent is TControl then
    begin
      ParentWidth := (Parent as TControl).Width;
      ParentHeight := (Parent as TControl).Height;
    end;
  end;

  function IsBitmapSizeChanged(ABitmap: TBitmap; const ANewWidth, ANewHeight: Single): Boolean;
  begin
    Result := not SameValue(ANewWidth * ABitmap.BitmapScale, ABitmap.Width) or
              not SameValue(ANewHeight * ABitmap.BitmapScale, ABitmap.Height);
  end;

  procedure MakeParentScreenshot;
  var
    Form: TCommonCustomForm;
    Child: TFmxObject;
    ParentControl: TControl;
  begin
    if FParentScreenshotBitmap.Canvas.BeginScene then
      try
        FDisablePaint := True;
        if Parent is TCommonCustomForm then
        begin
          Form := Parent as TCommonCustomForm;
          for Child in Form.Children do
            if (Child is TControl) and (Child as TControl).Visible then
            begin
              ParentControl := Child as TControl;
              ParentControl.PaintTo(FParentScreenshotBitmap.Canvas, ParentControl.ParentedRect);
            end;
        end
        else
          (Parent as TControl).PaintTo(FParentScreenshotBitmap.Canvas, RectF(0, 0, ParentWidth, ParentHeight));
      finally
        FDisablePaint := False;
        FParentScreenshotBitmap.Canvas.EndScene;
      end;
  end;

begin

  // Make screenshot of Parent control
  DefineParentSize;
  if IsBitmapSizeChanged(FParentScreenshotBitmap, ParentWidth, ParentHeight) then
    FParentScreenshotBitmap.SetSize(Round(ParentWidth), Round(ParentHeight));
  MakeParentScreenshot;

  // Apply glass effect
  Canvas.BeginScene;
  try
    FBlur.ProcessEffect(Canvas, FParentScreenshotBitmap, FBlur.Softness);
    Canvas.DrawBitmap(FParentScreenshotBitmap, ParentedRect, LocalRect, 1, TRUE);
  finally
    Canvas.EndScene;
  end;

end;

使用するには、任意のコントロールの上に TGlass をインスタンス化するだけで、探している「ガラスのような」効果が得られます。

于 2014-05-28T00:13:10.903 に答える