Вместо обратных вызовов, которые не существуют в 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;
}
Итак, что здесь происходит?
visible
, обе height
и opacity
запускают анимацию без задержки (0 мс), хотя height
принимает 0 мс для завершения анимации (эквивалент display: block
), а opacity
занимает 600 мс. visible
удален, opacity
запускает анимацию (0 мс задержка, 400 мс), а высота ждет 400 мс и только затем мгновенно восстанавливает начальное значение (эквивалент display: none
в обратном вызове анимации) . Обратите внимание, что этот подход лучше, чем при использовании visibility
. В этом случае элемент все еще занимает пространство на странице, и это не всегда удобно.
Для получения дополнительных примеров обратитесь к этой статье .
GetForegroundWindow
вместо GetDesktopWindow
. Вы сделали это прямо в своей улучшенной версии . Когда я выполнил ваш код, моя 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;
Благодарим вас за это полезное представление. Я думал, что могу сделать код, предлагаемый в единицу для использования по всему моему приложению, вот код, который я использую в 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;
Ваш код может быть намного проще. Когда вы решите, какую форму вы хотите сохранить, попробуйте использовать код, который я использую:
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;
Самая короткая версия кода Брайана Мороза:
Screen.ActiveForm.GetFormImage.SaveToFile(Screen.ActiveForm.Caption+'.bmp');
Только одна строка кода (Снимок экрана активного окна в приложении MDI).
Это объединяет все подходы, описанные до сих пор. Он также обрабатывает сценарии с несколькими мониторами.
Передайте вид скриншота, который вы хотите, и 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;
Используйте GetForegroundWindow () вместо GetDesktopWindow ().
Вам нужно сохранить дескриптор, возвращаемый GetForegroundWindow () и передать сохраненное значение в ReleaseDC () - чтобы убедиться, что GetWindowDC () и ReleaseDC () называются точно для одного и того же окна, если активное окно изменяется между вызовами.
Никто здесь не написал хороший ответ. Решение, которое до сих пор предлагало сделать снимок экрана, который «обрезается» в позиции целевого окна. Что, если это окно находится за другим и в настоящее время не отображается операционной системой? Вот почему вам нужно использовать эту функцию , введенную в Windows XP.
После быстрого Google вот пример кода: http://delphi.about.com/ од / delphitips2008 / кварты / print_window.htm
JCL снова приходит на помощь ..
hwnd := GetForegroundWindow;
Windows.GetClientRect(hwnd, r);
JclGraphics.ScreenShot(theBitmap, 0, 0, r.Right - r.Left, r.Bottom - r.Top, hwnd);
// use theBitmap...