2009-03-19 30 views
9

para capturas de pantalla completo, utilizo este código:¿Cómo tomar una captura de pantalla de la ventana activa en Delphi?

form1.Hide; 
sleep(500); 
bmp := TBitmap.Create; 
bmp.Height := Screen.Height; 
bmp.Width := Screen.Width; 
DCDesk := GetWindowDC(GetDesktopWindow); 
BitBlt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DCDesk, 0, 0, SRCCOPY); 
form1.Show ; 
FileName := 'Screenshot_'+FormatDateTime('mm-dd-yyyy-hhnnss',now()); 
bmp.SaveToFile(Format('C:\Screenshots\%s.bmp', [FileName])); 
ReleaseDC(GetDesktopWindow, DCDesk); 
bmp.Free; 

¿Cómo puedo convertir ese tomar una captura de pantalla de sólo la ventana activa.

+0

Usted debe enviar su versión mejorada (s) aquí, debajo de su original ejemplo, para que otros puedan beneficiarse de su "rastro de aprendizaje" también. –

+0

Aclare: ¿Desea tomar una captura de pantalla de otro formulario en el mismo programa o de cualquier programa que esté visible cuando se oculta Form1? – mghie

+0

Quiero que tome desde la ventana activa una vez que el formulario está oculto. – PuppyKevin

Respuesta

16
  1. Antes que nada, tiene que obtener la ventana derecha. Como sharptooth ya señaló, debe usar GetForegroundWindow en lugar de GetDesktopWindow. Lo ha hecho bien en su improved version.
  2. Pero luego tiene que cambiar el tamaño de su mapa de bits al tamaño real de la ventana DC /. No has hecho esto todavía.
  3. ¡Y luego asegúrese de no capturar ninguna ventana de pantalla completa!

Cuando ejecuté su código, mi Delphi IDE fue capturado y como está en pantalla completa por defecto, creó la ilusión de una captura de pantalla a pantalla completa. (Aunque su código es en su mayoría correcto)

Considerando los pasos anteriores, pude crear con éxito una captura de pantalla de una sola ventana con su código.

Solo una pista: Puede GetDC en lugar de GetWindowDC si solo está interesado en el área de clientes. (No hay bordes de las ventanas)

EDIT: Esto es lo que hice con su código:

Usted no debe utilizar este código! Mira la versión mejorada a continuación.

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; 

EDIT 2: conforme a lo solicitado estoy añadiendo una mejor versión del código, pero me quedo con el anterior como referencia. Deberías considerar seriamente usar esto en lugar de tu código original. Se comportará mucho mejor en caso de errores. (Los recursos se limpian, su formulario será visible de nuevo, ...)

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; 
+0

Ok, este es mi código actual ahora: http://pastebin.com/m43958302 Así es como se ve la imagen: http://i43.tinypic.com/xpcvw1.jpg ¿Alguna sugerencia? – PuppyKevin

+0

Tiene que tener más cuidado :) 1. Está intercambiando la altura y el ancho en BitBlt. 2. Está capturando el área del cliente, pero está dimensionando el mapa de bits de acuerdo con el ancho total. –

+0

DR, ¿podría mostrarme qué hizo con mi código? Creo que puedo aprender mejor si veo el trabajo de otra persona. – PuppyKevin

0

Utilice GetForegroundWindow() en lugar de GetDesktopWindow().

Deberá guardar el manejador que GetForegroundWindow() devolverá y pasará el valor guardado en ReleaseDC() - para asegurarse de que GetWindowDC() y ReleaseDC() se llaman exactamente para la misma ventana en caso de que la ventana activa cambios entre llamadas.

+0

Ok, ahora tengo esto: http://pastebin.com/m2e334a4a Aunque todavía toma la pantalla completa. – PuppyKevin

+0

Comprueba cuál es el valor del identificador. Si es nulo, no hay ventana activa y va a volcar todo el escritorio. – sharptooth

+0

Estoy confundido. ¿Cuál es el valor del mango? Además, ¿cómo lo verifico? – PuppyKevin

15

Su código podría ser mucho más simple. Cuando se haya decidido en qué forma desea guardar, probar el código que utilizo:

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; 
+1

Eso solo funcionaría con formularios que pertenecen a la misma aplicación. Pero en ese caso es mejor que jugar con la API de Windows. –

+0

Muy bien, pero esto solo guarda el área del cliente del formulario – Fr0sT

4

JCL viene al rescate una vez más ..

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

    // use theBitmap... 
3

Nadie aquí ha publicado una buena respuesta. La solución que hasta ahora se ha propuesto es tomar una captura de pantalla que se 'recorta' en la posición de la ventana de destino. ¿Qué sucede si esa ventana está detrás de otra y el sistema operativo no la está procesando actualmente? Es por eso que necesita utilizar la función this introducida en Windows XP.

Después de una búsqueda rápida en Google, aquí hay un código de ejemplo: http://delphi.about.com/od/delphitips2008/qt/print_window.htm

+0

+1 por tener una respuesta más robusta (manejar más casos y un buen enlace a un gran ejemplo). De hecho, estaba buscando algo como esto y encontré esta respuesta para ser la mejor. –

6

Esto combina todos los enfoques descritos hasta ahora. También maneja escenarios de múltiples monitores.

Pase el tipo de captura de pantalla que desee, y una TJpegImage, y le asignará la captura de pantalla solicitada a esa imagen.

/////////// 
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; 
+0

Eché de menos tu biblioteca cuando publiqué la mía, buen trabajo –

-3

La versión más corta del código de Brian heladas:

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

una sola línea de código (Captura de pantalla de la ventana activa en la aplicación MDI).

+5

Una línea de código que filtra el mapa de bits que Brian quería liberar. –

1

Gracias por este útil envío. Pensé que podría hacer que el código ofrecido en una unidad se usara en toda mi aplicación, aquí está el código que tengo en ejecución en DX10.2 Tokyo. Tenga en cuenta el ejemplo, tenga cuidado con las pérdidas de memoria.

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. 

Ejemplo:

//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; 
Cuestiones relacionadas