Как сделать снимок экрана активного окна в Delphi 10? [Дубликат]

Вместо обратных вызовов, которые не существуют в CSS, мы можем использовать свойство transition-delay.

#selector {
    overflow: hidden; // hide the element content, while height = 0
    height: 0; opacity: 0;
    transition: height 0ms 400ms, opacity 400ms 0ms;
}
#selector.visible {
    height: 100%; opacity: 1;
    transition: height 0ms 0ms, opacity 600ms 0ms;
}

Итак, что здесь происходит?

  1. Когда добавлен класс visible, обе height и opacity запускают анимацию без задержки (0 мс), хотя height принимает 0 мс для завершения анимации (эквивалент display: block), а opacity занимает 600 мс.
  2. Когда класс visible удален, opacity запускает анимацию (0 мс задержка, 400 мс), а высота ждет 400 мс и только затем мгновенно восстанавливает начальное значение (эквивалент display: none в обратном вызове анимации) .

Обратите внимание, что этот подход лучше, чем при использовании visibility. В этом случае элемент все еще занимает пространство на странице, и это не всегда удобно.

Для получения дополнительных примеров обратитесь к этой статье .

9
задан Josh Crozier 22 November 2015 в 23:37
поделиться

8 ответов

  1. Прежде всего, вы должны получить правильное окно. Как уже отмечалось выше, вы должны использовать GetForegroundWindow вместо GetDesktopWindow. Вы сделали это прямо в своей улучшенной версии .
  2. Но тогда вы должны изменить размер растрового изображения на фактический размер DC / Window. Вы еще не сделали этого.
  3. И затем убедитесь, что вы не захватили какое-то полноэкранное окно!

Когда я выполнил ваш код, моя IDE Delphi была захвачена и по умолчанию это полноэкранный режим, он создал иллюзию полноэкранного снимка экрана. (Несмотря на то, что ваш код в основном правильный)

Учитывая вышеописанные шаги, я смог создать скриншот с одним окном с вашим кодом.

Просто подсказка: вы можете GetDC вместо GetWindowDC, если вас интересует только клиентская область. (Нет границ окна)

EDIT: Вот что я сделал с вашим кодом:

Вы не должны использовать этот код! Посмотрите на улучшенную версию ниже.

procedure TForm1.Button1Click(Sender: TObject);
const
  FullWindow = True; // Set to false if you only want the client area.
var
  hWin: HWND;
  dc: HDC;
  bmp: TBitmap;
  FileName: string;
  r: TRect;
  w: Integer;
  h: Integer;
begin
  form1.Hide;
  sleep(500);
  hWin := GetForegroundWindow;

  if FullWindow then
  begin
    GetWindowRect(hWin,r);
    dc := GetWindowDC(hWin) ;
  end else
  begin
    Windows.GetClientRect(hWin, r);
    dc := GetDC(hWin) ;
  end;

  w := r.Right - r.Left;
  h := r.Bottom - r.Top;

  bmp := TBitmap.Create;
  bmp.Height := h;
  bmp.Width := w;
  BitBlt(bmp.Canvas.Handle, 0, 0, w, h, DC, 0, 0, SRCCOPY);
  form1.Show ;
  FileName := 'Screenshot_'+FormatDateTime('mm-dd-yyyy-hhnnss',now());
  bmp.SaveToFile(Format('C:\Screenshots\%s.bmp', [FileName]));
  ReleaseDC(hwin, DC);
  bmp.Free;
end;

РЕДАКТИРОВАТЬ 2: По просьбе я добавляю лучшую версию кода, но я сохраняю старую ссылку в качестве ссылки. Вы должны серьезно подумать об использовании этого вместо исходного кода. В случае ошибок он будет намного лучше. (Ресурсы очищены, ваша форма будет снова видна, ...)

procedure TForm1.Button1Click(Sender: TObject);
const
  FullWindow = True; // Set to false if you only want the client area.
var
  Win: HWND;
  DC: HDC;
  Bmp: TBitmap;
  FileName: string;
  WinRect: TRect;
  Width: Integer;
  Height: Integer;
begin
  Form1.Hide;
  try
    Application.ProcessMessages; // Was Sleep(500);
    Win := GetForegroundWindow;

    if FullWindow then
    begin
      GetWindowRect(Win, WinRect);
      DC := GetWindowDC(Win);
    end else
    begin
      Windows.GetClientRect(Win, WinRect);
      DC := GetDC(Win);
    end;
    try
      Width := WinRect.Right - WinRect.Left;
      Height := WinRect.Bottom - WinRect.Top;

      Bmp := TBitmap.Create;
      try
        Bmp.Height := Height;
        Bmp.Width := Width;
        BitBlt(Bmp.Canvas.Handle, 0, 0, Width, Height, DC, 0, 0, SRCCOPY);
        FileName := 'Screenshot_' + 
          FormatDateTime('mm-dd-yyyy-hhnnss', Now());
        Bmp.SaveToFile(Format('C:\Screenshots\%s.bmp', [FileName]));
      finally
        Bmp.Free;
      end;
    finally
      ReleaseDC(Win, DC);
    end;
  finally
    Form1.Show;
  end;
end;
17
ответ дан Daniel Rikowski 28 August 2018 в 00:29
поделиться

Благодарим вас за это полезное представление. Я думал, что могу сделать код, предлагаемый в единицу для использования по всему моему приложению, вот код, который я использую в DX10.2 Tokyo. Обратите внимание на пример, обратите внимание на утечки памяти.

unit ScreenCapture;
interface

uses Windows, Vcl.Controls, Vcl.StdCtrls, VCL.Graphics,VCL.Imaging.JPEG, VCL.Forms;

function getScreenCapture(  FullWindow: Boolean = True ) : TBitmap;

implementation

function getScreenCapture( FullWindow: Boolean ) : TBitmap;
var
  Win: HWND;
  DC: HDC;

  WinRect: TRect;
  Width: Integer;
  Height: Integer;

begin
  Result := TBitmap.Create;

  //Application.ProcessMessages; // Was Sleep(500);
  Win := GetForegroundWindow;

  if FullWindow then
  begin
    GetWindowRect(Win, WinRect);
    DC := GetWindowDC(Win);
  end
    else
  begin
    Windows.GetClientRect(Win, WinRect);
    DC := GetDC(Win);
  end;
  try
    Width := WinRect.Right - WinRect.Left;
    Height := WinRect.Bottom - WinRect.Top;

    Result.Height := Height;
    Result.Width := Width;
    BitBlt(Result.Canvas.Handle, 0, 0, Width, Height, DC, 0, 0, SRCCOPY);
  finally
    ReleaseDC(Win, DC);
  end;
end;
end.

Пример:

//Any event or button click, screenCapture is a TBitmap
screenCapture := getScreenCapture();
try
  //Do some things with screen capture
  Image1.Picture.Graphic := screenCapture; 
finally 
  screenCapture.Free;
end;
1
ответ дан Andre Van Zuydam 28 August 2018 в 00:29
поделиться

Ваш код может быть намного проще. Когда вы решите, какую форму вы хотите сохранить, попробуйте использовать код, который я использую:

procedure SaveFormBitmapToBMPFile( AForm : TCustomForm; AFileName : string = '' );
// Copies this form's bitmap to the specified file
var
  Bitmap: TBitMap;
begin
  Bitmap := AForm.GetFormImage;
  try
    Bitmap.SaveToFile( AFileName );
  finally
    Bitmap.Free;
  end;
end;
15
ответ дан Brian Frost 28 August 2018 в 00:29
поделиться

Самая короткая версия кода Брайана Мороза:

Screen.ActiveForm.GetFormImage.SaveToFile(Screen.ActiveForm.Caption+'.bmp');

Только одна строка кода (Снимок экрана активного окна в приложении MDI).

-3
ответ дан Jan Kirchner 28 August 2018 в 00:29
поделиться

Это объединяет все подходы, описанные до сих пор. Он также обрабатывает сценарии с несколькими мониторами.

Передайте вид скриншота, который вы хотите, и TJpegImage, и он присвоит ваш запрошенный снимок экрана этому изображению.

///////////
uses
  Jpeg;

type  //define an ENUM to describe the possible screenshot types.
  TScreenShotType = (sstActiveWindow, sstActiveClientArea,
    sstPrimaryMonitor, sstDesktop);
///////////

procedure TfrmMain.GetScreenShot(shotType: TScreenShotType;
  var img: TJpegImage);
var
  w,h: integer;
  DC: HDC;
  hWin: Cardinal;
  r: TRect;
  tmpBmp: TBitmap;
begin
  hWin := 0;
  case shotType of
    sstActiveWindow:
      begin
        //only the active window
        hWin := GetForegroundWindow;
        dc := GetWindowDC(hWin);
        GetWindowRect(hWin,r);
        w := r.Right - r.Left;
        h := r.Bottom - r.Top;
      end;  //sstActiveWindow
    sstActiveClientArea:
      begin
        //only the active client area (active window minus title bars)
        hWin := GetForegroundWindow;
        dc := GetDC(hWin);
        GetWindowRect(hWin,r);
        w := r.Right - r.Left;
        h := r.Bottom - r.Top;
      end;  //sstActiveClientArea
    sstPrimaryMonitor:
      begin
        //only the primary monitor.  If 1 monitor, same as sstDesktop.
        hWin := GetDesktopWindow;
        dc := GetDC(hWin);
        w := GetDeviceCaps(DC,HORZRES);
        h := GetDeviceCaps(DC,VERTRES);
      end;  //sstPrimaryMonitor
    sstDesktop:
      begin
        //ENTIRE desktop (all monitors)
        dc := GetDC(GetDesktopWindow);
        w := Screen.DesktopWidth;
        h := Screen.DesktopHeight;
      end;  //sstDesktop
    else begin
      Exit;
    end;  //case else
  end;  //case

  //convert to jpg
  tmpBmp := TBitmap.Create;
  try
    tmpBmp.Width := w;
    tmpBmp.Height := h;
    BitBlt(tmpBmp.Canvas.Handle,0,0,tmpBmp.Width,
      tmpBmp.Height,DC,0,0,SRCCOPY);
    img.Assign(tmpBmp);
  finally
    ReleaseDC(hWin,DC);
    FreeAndNil(tmpBmp);
  end;  //try-finally
end;
6
ответ дан JosephStyons 28 August 2018 в 00:29
поделиться

Используйте GetForegroundWindow () вместо GetDesktopWindow ().

Вам нужно сохранить дескриптор, возвращаемый GetForegroundWindow () и передать сохраненное значение в ReleaseDC () - чтобы убедиться, что GetWindowDC () и ReleaseDC () называются точно для одного и того же окна, если активное окно изменяется между вызовами.

0
ответ дан sharptooth 28 August 2018 в 00:29
поделиться

Никто здесь не написал хороший ответ. Решение, которое до сих пор предлагало сделать снимок экрана, который «обрезается» в позиции целевого окна. Что, если это окно находится за другим и в настоящее время не отображается операционной системой? Вот почему вам нужно использовать эту функцию , введенную в Windows XP.

После быстрого Google вот пример кода: http://delphi.about.com/ од / delphitips2008 / кварты / print_window.htm

3
ответ дан user 28 August 2018 в 00:29
поделиться

JCL снова приходит на помощь ..

    hwnd := GetForegroundWindow;
    Windows.GetClientRect(hwnd, r);
    JclGraphics.ScreenShot(theBitmap, 0, 0, r.Right - r.Left, r.Bottom - r.Top, hwnd);

    // use theBitmap...
4
ответ дан utku_karatas 28 August 2018 в 00:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: