2013-08-13 8 views
1

C#에서 작업 비트 맵에 Control 또는 Form을 캡처해야하는 프로젝트가 있습니다. 생성자에서 Control 매개 변수를 사용하고 다음 코드 (이 예제에서는 단순화 된)를 실행하여 Control의 비트 맵을 저장하는 클래스가 있습니다.양식 크기를 조정 한 후 비트 맵에 양식 캡처

public MyItem(Control control) 
    { 
     if (control != null) 
     { 
      Control rootParent = control; 
      while (rootParent.Parent != null) 
       rootParent = rootParent.Parent; 

      rootParent.BringToFront(); 

      _bounds = control.Bounds; 
      Rectangle controlBounds; 

      if (control.Parent == null) 
      { 
       _bounds = new Rectangle(new Point(0, 0), control.Bounds.Size); 
       controlBounds = _bounds; 
      } 
      else 
      { 
       _bounds.Intersect(control.Parent.ClientRectangle); 
       _bounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(_bounds.Location)), _bounds.Size); 
       controlBounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(control.Location)), control.Size); 
      } 

      if (_bounds.Height > 0 && _bounds.Width > 0) 
      { 
       IntPtr hDC = IntPtr.Zero; 

       if (control.Parent == null && !Clarity.ClientAreaOnly) 
        // Used for capturing a form including non-client area 
        hDC = Win32.GetWindowDC(control.Handle); 
       else 
        // Used for capturing a form excluding non-client area or a control 
        hDC = control.CreateGraphics().GetHdc(); 

       try 
       { 
        _controlBitmap = new Bitmap(_bounds.Width, _bounds.Height); 
        using (Graphics bitmapGraphics = Graphics.FromImage(_controlBitmap)) 
        { 
         IntPtr bitmapHandle = bitmapGraphics.GetHdc(); 
         Win32.BitBlt(bitmapHandle, 0, 0, _bounds.Width, _bounds.Height, hDC, _bounds.X - controlBounds.X, _bounds.Y - controlBounds.Y, 13369376); 
         bitmapGraphics.ReleaseHdc(bitmapHandle); 
        } 
       } 
       finally 
       { 
        if (hDC != IntPtr.Zero) 
         Win32.ReleaseDC(control.Handle, hDC); 
       } 
      } 
     } 
    } 

I 캡처 할 필요가 각 컨트롤 생성이 클래스의 인스턴스는, 비트 맵 (화면에 그림이 경우) 사용하고, 객체가 더 이상 필요하지 않을 때 처리된다.

http://i.imgur.com/ZizXjNX.png

그러나 나는 Form을 캡처하려고하면, 아래 그림과 같이 이것은 잘 작동하고 나에게 후자의 경우에 비 클라이언트 영역을 포함 지정된 Control 또는 Form의 비트 맵을 제공합니다 다시 나는 문제가있다. 다시 캡처하기 전에 Form의 크기를 조정하면 두 번째 캡처에서 비 클라이언트 영역이 올바르지 않은 것으로 표시됩니다.

아래 그림은이를 설명하기위한 이미지입니다. 왼쪽에는 양식이 화면에 표시되는 방식 (올바른)과 오른쪽에 위의 코드가 캡처하는 방식 (잘못된 방식)이 나와 있습니다.

http://i.imgur.com/y46kFDj.png

난 내 자신의 검색에서 아무것도 와서 누군가가 내가 잘못하고 있지/무엇을 지적 할 수 있는지 너무 궁금 적이 없다?

+0

아마도이 문제를 해결할 코드가 없으므로 주위를 둘러 봐야합니다. 양식 이미지를 캡처하기 전에 타이머 또는 유사한 새 스레드를 사용하여 짧은 시간을 계산하십시오. –

+0

크기 변경 중 또는 크기 조정이 완료된 후에 언제 발생합니까? – DonBoitnott

+0

@DonBoitnott 죄송합니다.이 내용을 명확하게 작성해야합니다. 크기를 조정 한 후에는 언제든지 발생합니다. 예를 들어, 폼의 크기를 조정할 수 있고 크기 조정이 완료되었습니다. 10 초 후에 캡처 한 다음 여전히 잘못된 것으로 나타납니다. 하지만 혼란스럽게도 _client area_의 모든 내용이 정확합니다. _non-client 영역 _이 잘못되었습니다. –

답변

0

기존 캡처 방법을 유지하여 원하는대로이 문제를 해결할 수 없었습니다. 프로토 타입 응용 프로그램과 마찬가지로이 문제를 더 자세히 조사 할 시간이 없습니다. 이 프로토 타입이 선택되거나 다시이 기능을 살펴볼 기회가 있으면 그에 따라이 답변을 업데이트 할 것입니다.

그 동안 나는 다음 방법을 대안으로 사용했습니다. 다른 메커니즘을 사용하여 내용을 캡처하지만 원하는대로 출력을 생성합니다. 그것이 창문과 형태를 "복잡하게 만드는"것을 포함하는 것에 따라 나는 이것을 대단히 좋아하지 않는다. 그러나 내가 원하는 것보다 많은 것이 지금 충분하다.

기본적으로 이제 문제의 창/양식을 맨 앞으로 가져 와서 가장 위에 놓은 다음 창 경계에서 화면 캡처를 수행합니다. 내가 말했듯이, 내가 바라는 것보다 더 난감하지만 실제로 잘 작동한다!

public MyItem(Control control) 
{ 
    if (control != null) 
    { 
     Control rootParent = control; 
     while (rootParent.Parent != null) 
      rootParent = rootParent.Parent; 

     rootParent.BringToFront(); 

     _bounds = control.Bounds; 
     Rectangle controlBounds; 

     if (control.Parent == null) 
     { 
      _bounds = new Rectangle(new Point(0, 0), control.Bounds.Size); 
      controlBounds = _bounds; 
     } 
     else 
     { 
      _bounds.Intersect(control.Parent.ClientRectangle); 
      _bounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(_bounds.Location)), _bounds.Size); 
      controlBounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(control.Location)), control.Size); 
     } 

     if (_bounds.Height > 0 && _bounds.Width > 0) 
     { 
      _controlBitmap = new Bitmap(_bounds.Width, _bounds.Height); 
      using (Graphics bitmapGraphics = Graphics.FromImage(_controlBitmap)) 
      { 
       if (control.Parent == null) 
       { 
        Form form = control as Form; 
        Boolean currentTopMost = form.TopMost; 
        form.TopMost = true; 
        control.BringToFront(); 
        bitmapGraphics.CopyFromScreen(control.Location, Point.Empty, _bounds.Size); 
        form.TopMost = currentTopMost; 
       } 
       else 
       { 
        IntPtr hDC = IntPtr.Zero; 
        try 
        { 
         hDC = control.CreateGraphics().GetHdc(); 
         IntPtr bitmapHandle = bitmapGraphics.GetHdc(); 
         Win32.BitBlt(bitmapHandle, 0, 0, _bounds.Width, _bounds.Height, hDC, _bounds.X - controlBounds.X, _bounds.Y - controlBounds.Y, 13369376); 
         bitmapGraphics.ReleaseHdc(bitmapHandle); 
        } 
        finally 
        { 
         if (hDC != IntPtr.Zero) 
          Win32.ReleaseDC(control.Handle, hDC); 
        } 
       } 
      } 
     } 
    } 
}