【问题标题】:Screenshot behind a full screen Form results in a black screen全屏表单后面的屏幕截图导致黑屏
【发布时间】:2018-07-14 20:33:18
【问题描述】:

我想捕获一个桌面图像,该图像在捕获时会忽略我的表单。我喜欢this answer,但是一直无法截取桌面内容,只能黑屏

所以,我需要帮助来解决这个问题。

这是我的版本,改动不大:

private
    { Private declarations }
    DesktopBMP: TBitmap;
    procedure WMEraseBkgnd( var Message: TWMEraseBkgnd ); message WM_ERASEBKGND;
  public
    { Public declarations }
    protected
    procedure Paint; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
DesktopBMP := TBitmap.Create;
  DesktopBMP.SetSize( Screen.Width, Screen.Height );
  DoubleBuffered := True;
end;

procedure TForm1.tmr1Timer(Sender: TObject);
begin
  Width := 0;
  Height := 0;
  Width := Screen.Width;
  Height := Screen.Height;
end;

procedure TForm1.Paint;
begin
  inherited;
  //Canvas.Draw( 0, 0, DesktopBMP );
  DesktopBMP.SaveToFile('c:\tela.bmp');
end;

procedure TForm1.WMEraseBkgnd( var Message: TWMEraseBkgnd );
var
  DesktopDC: HDC;
  DesktopHwnd: Hwnd;
  DesktopCanvas: TCanvas;
begin
  DesktopHwnd := GetDesktopWindow;
  DesktopDC := GetDC( DesktopHwnd );
  try
    DesktopCanvas := TCanvas.Create;
    DesktopCanvas.Handle := DesktopDC;
    DesktopBMP.Canvas.CopyRect( Rect( 0, 0, Screen.Width, Screen.Height ), DesktopCanvas, Rect( 0, 0, Screen.Width, Screen.Height ) );
  finally
    DesktopCanvas.Free;
    ReleaseDc( DesktopHwnd, DesktopDC );
  end;
  Message.Result := 1;
  inherited;
end;

【问题讨论】:

  • @TomBrunberg,那么是不是可以擦除 Form 上的这个黑屏? WM_ERASEBKGND 工作正常,但是会生成黑屏(在窗体的背景上)并且看不到桌面的屏幕截图。
  • @TomBrunberg,我的目标是在全屏表单后面看到(已经制作),但这里的问题是,表单的背景不是保持干净,而是生成黑色,这显示在如您在上面看到的屏幕截图。现在我想知道是否有可能删除屏幕截图结果中显示的表单上的这个黑色部分(不再隐藏和显示表单)?
  • 你告诉 Windows 你已经用Message.Result := 1; 擦除了背景,但是你的代码除了将桌面画布复制到你的 bmp 之外没有做任何事情。如果你注释掉那行会发生什么?
  • @nil, What happens if you comment out that line?。什么都没有。
  • 图片出现黑屏的原因可能/很可能是OnTimer:Width := 0; Width := Screen.Width;中的代码(高度也一样)。要确认,请将设置注释为 0。这可能只会给您一个屏幕截图,这不是最终解决方案,但它会确认问题。然后,您将需要找到另一种触发更新屏幕截图的方法。顺便说一句,在表单的每个绘制事件中保存文件似乎不是一个好主意。

标签: delphi screenshot fullscreen vcl


【解决方案1】:

这是基于您提供的代码的解决方案。

覆盖表单是无边框的 (BorderStyle = bsNone),它有两个按钮,一个用于截取底层屏幕的屏幕截图,一个用于终止应用程序(因为我们在标题中没有按钮)。

对代码的主要更改是

表单中的两个私有字段

DoSnapShot: boolean; // to control when to copy the screen
ScreenRect: TRect;   // to hold the rectangle of the overlay

还有一个过程

procedure TakeScreenShot;

TakeScreenShot替换您在代码中的OnTimer 处理程序,并在重置WidthHeight 之前添加设置布尔值DoSnapShot = True

WMEraseBkgnd 被修改为仅在 DoSnapShot = True 时尝试复制底层屏幕。

完整的代码如下

type
  TForm3 = class(TForm)
    ScreenBtn: TButton;
    ExitBtn: TButton;
    procedure FormCreate(Sender: TObject);
    procedure ScreenBtnClick(Sender: TObject);
    procedure ExitBtnClick(Sender: TObject);
  private
    DesktopBMP: TBitmap;
    DoSnapShot: boolean; // to control when to copy the screen
    ScreenRect: TRect;   // to hold the rectangle of the overlay
    procedure TakeScreenShot;
    procedure WMEraseBkgnd( var Message: TWMEraseBkgnd ); message WM_ERASEBKGND;
  protected
    procedure Paint; override;
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.ScreenBtnClick(Sender: TObject);
begin
  TakeScreenShot;
end;

procedure TForm3.ExitBtnClick(Sender: TObject);
begin
  Application.Terminate;
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  Left := 0;
  Top := 0;
  Width := Screen.Width;
  Height := Screen.Height-10;

  ScreenRect := Rect(Left, Top, Width, Height);

  DesktopBMP := TBitmap.Create;
  DesktopBMP.SetSize( Width, Height );
end;

procedure TForm3.Paint;
begin
  inherited;
  Canvas.Draw( 0, 0, DesktopBMP );
end;

procedure TForm3.TakeScreenShot;
begin
  Width := 0;   // will not trigger copying
  Height := 0;  //
  DoSnapShot := True;  // now enable copying the underlying screen
  Width := ScreenRect.Width;    //
  Height := ScreenRect.Height;  // and trigger it in WMEraseBkgnd
end;

procedure TForm3.WMEraseBkgnd(var Message: TWMEraseBkgnd);
var
  DesktopDC: HDC;
  DesktopHwnd: Hwnd;
  DesktopCanvas: TCanvas;
begin
  if DoSnapShot then
  begin
    DoSnapShot := False; // Disable repeated copying
    DesktopHwnd := GetDesktopWindow;
    DesktopDC := GetDC( DesktopHwnd );
    try
      DesktopCanvas := TCanvas.Create;
      DesktopCanvas.Handle := DesktopDC;
      DesktopBMP.Canvas.CopyRect( ScreenRect , DesktopCanvas, ScreenRect );
    finally
      DesktopCanvas.Free;
      ReleaseDc( DesktopHwnd, DesktopDC );
    end;
  end;
  Message.Result := 1;
  inherited;
end;

end.

还有.dfm

object Form3: TForm3
  Left = 0
  Top = 0
  BorderStyle = bsNone
  Caption = 'Form3'
  ClientHeight = 139
  ClientWidth = 225
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object ScreenBtn: TButton
    Left = 8
    Top = 8
    Width = 75
    Height = 25
    Caption = 'ScreenShot'
    TabOrder = 0
    OnClick = ScreenBtnClick
  end
  object ExitBtn: TButton
    Left = 8
    Top = 40
    Width = 75
    Height = 25
    Caption = 'Exit'
    TabOrder = 1
    OnClick = ExitBtnClick
  end
end

【讨论】:

  • 似乎工作:-),但我如何避免每次点击 Screenshot 按钮时表单“闪烁”?有什么想法吗?
  • 我没有看到任何闪烁,除了按钮。 OTOH,如果它随着这些宽度和高度操作而闪烁,我并不感到惊讶。解决这个问题将是另一个挑战。我回答了你问的关于黑屏的问题。
  • 我现在看到闪烁,如果我打开更多的应用程序和窗口。这是一个真正的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-12
  • 1970-01-01
相关资源
最近更新 更多