2009-03-19 51 views
9

Đối với ảnh chụp màn hình đầy đủ, tôi sử dụng mã này:Làm cách nào để chụp ảnh màn hình của Cửa sổ Hoạt động trong 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; 

Làm thế nào tôi có thể chuyển đổi đó để có một ảnh chụp màn hình chỉ có cửa sổ hoạt động.

+0

Bạn nên đăng phiên bản của bạn được cải thiện (s) ở đây, bên dưới ví dụ ban đầu của bạn, để những người khác có thể được hưởng lợi từ "kho kiến ​​thức" của bạn là tốt. –

+0

Hãy làm rõ: Bạn có muốn chụp ảnh màn hình của một biểu mẫu khác trong cùng một chương trình hoặc từ bất kỳ chương trình nào hiển thị khi Form1 bị ẩn không? – mghie

+0

Tôi muốn nó lấy từ Cửa sổ Hoạt động khi biểu mẫu bị ẩn. – PuppyKevin

Trả lời

16
  1. Trước hết, bạn phải có cửa sổ bên phải. Như đã được ghi nhận, bạn nên sử dụng GetForegroundWindow thay vì GetDesktopWindow. Bạn đã làm điều đó ngay trong số improved version của mình.
  2. Nhưng sau đó bạn phải thay đổi kích thước bitmap của bạn thành kích thước thực của DC/Window. Bạn chưa làm điều này.
  3. Và sau đó đảm bảo bạn không chụp được một số cửa sổ toàn màn hình!

Khi tôi thực thi mã của bạn, IDE Delphi của tôi đã được chụp và mặc định ở chế độ toàn màn hình, nó tạo ra ảo tưởng về ảnh chụp màn hình toàn màn hình. (Mặc dù mã của bạn chủ yếu là chính xác)

Xem xét các bước trên, tôi đã có thể tạo thành công một ảnh chụp màn hình một cửa sổ với mã của bạn.

Chỉ cần gợi ý: Bạn có thể GetDC thay vì GetWindowDC nếu bạn chỉ quan tâm đến khu vực khách hàng. (Không có đường viền cửa sổ)

EDIT: Đây là những gì tôi đã làm với mã của bạn:

Bạn không nên sử dụng mã này! Nhìn vào phiên bản cải tiến bên dưới.

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: Theo yêu cầu tôi thêm một phiên bản tốt hơn của mã này, nhưng tôi vẫn giữ cái cũ như một tài liệu tham khảo. Bạn nên cân nhắc nghiêm túc việc sử dụng mã này thay vì mã ban đầu của mình. Nó sẽ hoạt động tốt hơn nhiều trong trường hợp lỗi. (Tài nguyên được dọn sạch, biểu mẫu của bạn sẽ hiển thị lại, ...)

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, đây là mã hiện tại của tôi bây giờ: http://pastebin.com/m43958302 Đây là cách hình ảnh diễn ra: http://i43.tinypic.com/xpcvw1.jpg Bất kỳ đề xuất nào? – PuppyKevin

+0

Bạn phải cẩn thận hơn :) 1. Bạn đang trao đổi chiều cao và chiều rộng tại BitBlt. 2. Bạn đang chụp khu vực khách hàng, nhưng bạn đang định cỡ bitmap theo chiều rộng đầy đủ. –

+0

DR, bạn có thể cho tôi biết những gì bạn đã làm từ mã của tôi không? Tôi nghĩ tôi có thể học tốt hơn nếu tôi thấy công việc của người khác. – PuppyKevin

0

Sử dụng GetForegroundWindow() thay vì GetDesktopWindow().

Bạn sẽ phải lưu xử lý mà GetForegroundWindow() trả về và chuyển giá trị đã lưu vào ReleaseDC() - để chắc chắn rằng GetWindowDC() và ReleaseDC() được gọi chính xác cho cùng một cửa sổ trong trường hợp cửa sổ hiện hoạt thay đổi giữa các cuộc gọi.

+0

Ok bây giờ tôi có điều này: http://pastebin.com/m2e334a4a Nó vẫn có toàn màn hình mặc dù. – PuppyKevin

+0

Kiểm tra giá trị xử lý là gì. Nếu nó là null không có cửa sổ đang hoạt động và bạn có hiệu quả đổ toàn bộ máy tính để bàn. – sharptooth

+0

Tôi đang bối rối. Giá trị xử lý là gì? Ngoài ra, làm cách nào để kiểm tra? – PuppyKevin

15

Mã của bạn có thể đơn giản hơn rất nhiều. Khi bạn đã quyết định biểu mẫu nào muốn lưu, hãy thử đoạn code tôi sử dụng:

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

Điều đó sẽ chỉ hoạt động với các biểu mẫu thuộc cùng một ứng dụng. Nhưng trong trường hợp đó, waaay tốt hơn là rối tung với Windows API. –

+0

Rất đẹp nhưng điều này chỉ tiết kiệm khu vực khách hàng của biểu mẫu – Fr0sT

4

JCL đến để giải cứu một lần nữa ..

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

    // use theBitmap... 
3

Noone đây đã đăng một câu trả lời tốt. Các giải pháp đã được cho đến nay đề xuất nó để có một ảnh chụp màn hình đó là 'cắt' ở vị trí của cửa sổ mục tiêu. Điều gì sẽ xảy ra nếu cửa sổ đó nằm sau một cửa sổ khác và hiện không được hệ điều hành trả về? Đó là lý do tại sao bạn cần sử dụng chức năng this được giới thiệu trong Windows XP.

Sau một cách nhanh chóng của Google, đây là một số mã ví dụ: http://delphi.about.com/od/delphitips2008/qt/print_window.htm

+0

+1 để có câu trả lời mạnh mẽ hơn (xử lý nhiều trường hợp hơn và liên kết tốt đẹp đến ví dụ tuyệt vời). Tôi đã thực sự tìm kiếm một cái gì đó như thế này và tìm thấy câu trả lời này là tốt nhất. –

6

này kết hợp tất cả các phương pháp mô tả cho đến nay. Nó cũng xử lý các kịch bản nhiều màn hình.

Chuyển vào loại ảnh chụp màn hình bạn muốn và TJpegImage và nó sẽ chỉ định ảnh chụp màn hình được yêu cầu của bạn cho hình ảnh đó.

/////////// 
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

Tôi đã bỏ lỡ thư viện của bạn khi tôi đăng bài của tôi, công việc tốt –

-3

Phiên bản ngắn nhất của mã Brian Frost:

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

Chỉ cần một dòng mã (Ảnh chụp màn hình của cửa sổ tích cực trong ứng dụng MDI).

+5

Một dòng mã bị rò rỉ bitmap Brian được chăm sóc miễn phí .. –

1

Cảm ơn bạn đã gửi bài này hữu ích Tôi nghĩ rằng tôi có thể làm cho mã được cung cấp vào một đơn vị để sử dụng trên tất cả các ứng dụng của tôi, đây là mã tôi đã chạy trên DX10.2 Tokyo. Xin lưu ý ví dụ, xem ra cho rò rỉ bộ nhớ.

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. 

Ví dụ:

//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; 
Các vấn đề liên quan