2009-12-29 2 views
1

가 나는 두 가지 표시하려는 윈폼 제어있는 개체 :겹치는 System.Drawing.Graphics가

  1. 고심 비트 별 외부 입력 장치로부터로드 된 기본 이미지;
  2. 이미지 위에 시각적 패턴을 만드는 일련의 DrawLine 호출.

우리의 목적을 위해, # 1, 우리의 목적을 위해, 변경되지 않으며, 나는 그것을 다시 그리지 않아도 좋겠다.

# 2는 사용자가 다른 컨트롤을 돌릴 때 상대적으로 빨리 다시 그려야합니다.

환상으로, 각각의 Thing을 자신의 Graphics 객체에 넣고 # 2에 투명 배경을 넣고 # 2의 회전 변환을 사용하여 사용자 정의 컨트롤 설정과 일치시킵니다. 그러나 Graphics 객체를 투명하게 만드는 방법이나 이미 이미 그려져있는 것을 회전시키는 방법은 없습니다. 그래서 나는 그래픽을 위해 설계되지 않은 것을 할 것을 아마 요청할 것입니다.

여기 내 질문이 있습니다. 설정하는 가장 좋은 방법은 무엇입니까? 내 Graphics 객체를 겹치게해야합니까, 아니면 전혀 다른 방식으로이 방법을 사용하는 것이 좋을까요?

답변

1

Windows 그림 모델은 요구 사항에 잘 맞습니다. 배경 (OnPaintBackground)을 전경 (OnPaint)에서 분리합니다. 그렇다고해서 배경을 한 번만 페인트하고 끝낼 수는 없습니다. 창 표면 무효화는 두 가지 모두를 호출합니다. 무엇보다도 앤티 앨리어스 효과를 제대로 작동시키는 데 필요한 것이므로 알려진 배경색에만 잘 어울립니다.

여기에 펀치하고 OnPaintBackground() 무시에서 이미지를 그립니다. BackgroundImage 속성을 할당하여 Control이 자동으로이 작업을 수행하도록 할 수 있습니다.배경을 그릴 때 나타나는 깜박 거림을 피하고 일시적으로 전경 픽셀을 지우려면 DoubleBuffer 속성을 true로 설정해야합니다. 전경을 업데이트해야하는 경우 Invalidate()를 호출하십시오.

완성하려면 환상이 실제로 가능합니다. 이미지를 최상위 계층 창에 오버레이해야합니다. TransparencyKey 속성이 설정된 Form을 사용하면 쉽게 얻을 수 있습니다. 다음은 샘플 구현입니다.

using System; 
using System.Drawing; 
using System.Windows.Forms; 

class OverlayedPictureBox : PictureBox { 
    private Form mOverlay; 
    private bool mShown; 
    public event PaintEventHandler PaintOverlay; 
    public OverlayedPictureBox() { 
     mOverlay = new Form(); 
     mOverlay.FormBorderStyle = FormBorderStyle.None; 
     mOverlay.TransparencyKey = mOverlay.BackColor = Color.Magenta; 
     mOverlay.ShowInTaskbar = false; 
    } 
    protected void OnPaintOverlay(PaintEventArgs e) { 
     // NOTE: override this or implement the PaintOverlay event 
     PaintEventHandler handler = PaintOverlay; 
     if (handler != null) handler(this, e); 
    } 
    public void RefreshOverlay() { 
     // NOTE: call this to force the overlay to be repainted 
     mOverlay.Invalidate(); 
    } 
    protected override void Dispose(bool disposing) { 
     if (disposing) mOverlay.Dispose(); 
     base.Dispose(disposing); 
    } 
    protected override void OnVisibleChanged(EventArgs e) { 
     if (!mShown && !this.DesignMode) { 
      Control parent = this.Parent; 
      while (!(parent is Form)) parent = parent.Parent; 
      parent.LocationChanged += new EventHandler(parent_LocationChanged); 
      mOverlay.Paint += new PaintEventHandler(mOverlay_Paint); 
      mOverlay.Show(parent); 
      mShown = true; 
     } 
     base.OnVisibleChanged(e); 
    } 
    protected override void OnLocationChanged(EventArgs e) { 
     mOverlay.Location = this.PointToScreen(Point.Empty); 
     base.OnLocationChanged(e); 
    } 
    protected override void OnSizeChanged(EventArgs e) { 
     mOverlay.Size = this.Size; 
     base.OnSizeChanged(e); 
    } 
    void parent_LocationChanged(object sender, EventArgs e) { 
     mOverlay.Location = this.PointToScreen(Point.Empty); 
    } 
    private void mOverlay_Paint(object sender, PaintEventArgs e) { 
     OnPaintOverlay(e); 
    } 
} 

흥미로운 아티팩트 중 하나 : 양식을 최소화하고 다시 복원합니다. erm, special.

1

GDI +는 유지 모드가 아니므로 모든 그림판에 전체 컨트롤을 다시 그려야합니다. 그래서 불행히도 당신은 단지 두 가지 "물건"을 가질 수없고 그들 중 하나에 회전을 적용 할 수 없습니다. GDI +를 사용하는 것이 가장 좋습니다 :

  • Image 개체에 # 1을 저장하십시오. Graphics.FromImage를 사용하거나 사전 구성된 비트 맵을 사용하여 이미지에 요소를 미리 렌더링 할 수 있습니다.
  • # 2를 좌표 쌍 집합으로 저장합니다.

그런 다음 Graphics.DrawImage를 사용하여 # 1을 빠르게 다시 그리는 Paint 핸들러에서 Graphics.RotateTransform을 사용하여 회전 변환을 설정하고 선을 그립니다. 이중 버퍼링 (ControlStyles.DoubleBuffer)을 사용하여 부드럽게 나타낼 수 있어야합니다.

이 작업을 수행하는 "완전히 다른"방법은 "Windows Presentation Foundation"이라고 불리는 "환상"입니다. WPF는 보유 모드 그래픽 시스템을 가지고 있으며 "다른 상수를 유지하면서 한 레이어 회전"을보다 편리하게 처리 할 수 ​​있습니다. 또한 ElementHost 컨트롤을 사용하여 WinForms에서 WPF를 호스팅 할 수 있습니다. 대략적인 아이디어는 이미지에서 캔버스를 오버레이하고, 캔버스에 Line 객체를 추가하고, 캔버스의 RenderTransform을 RotateTransform으로 설정하고, RotateTransform의 각도를 다른 컨트롤의 값에 바인딩하는 것입니다. 그러나 이것은 프로젝트 고려 사항 (대상 플랫폼, 학습 곡선) 및 기술 요소 (WPF DLL을로드하는 초기 오버 헤드, interop 제약 조건)를 높입니다.

+0

두 답변 모두 훌륭했습니다. 나는 하나를 골라야했다. :-( – catfood