2016-09-08 10 views
1

정수 배열과 비트 맵이 빠른 PictureBox 편집을 위해 (느린 SetPixel 명령을 사용하지 않고) C# winforms 프로젝트의 일부로 조화롭게 작동하려고합니다.C# 컴퓨터 게임 (WinForms)을위한 간단하고 빠른 실시간 그래픽

나는 Button과 PictureBox, aformentioned 버튼의 클릭 이벤트와 Form의 closing 이벤트를 추가했습니다. 양식에 대한

코드과 같이 지금 : 실행하면 예상대로 검은 색 이미지가 처음에 존재

public partial class Form1 : Form 
{ 
    uint[] _Pixels { get; set; } 

    Bitmap _Bitmap { get; set; } 

    GCHandle _Handle { get; set; } 

    IntPtr _Addr { get; set; } 


    public Form1() 
    { 
     InitializeComponent(); 

     int imageWidth = 100; //1920; 

     int imageHeight = 100; // 1080; 

     PixelFormat fmt = PixelFormat.Format32bppRgb; 

     int pixelFormatSize = Image.GetPixelFormatSize(fmt); 

     int stride = imageWidth * pixelFormatSize; 

     int padding = 32 - (stride % 32); 

     if (padding < 32) 
     { 
      stride += padding; 
     } 

     _Pixels = new uint[(stride/32) * imageHeight + 1]; 

     _Handle = GCHandle.Alloc(_Pixels, GCHandleType.Pinned); 

     _Addr = Marshal.UnsafeAddrOfPinnedArrayElement(_Pixels, 0); 

     _Bitmap = new Bitmap(imageWidth, imageHeight, stride/8, fmt, _Addr); 

     pictureBox1.Image = _Bitmap; 

    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     for (int i = 0; i < _Pixels.Length; i++) 
     { 
      _Pixels[i] = ((uint)(255 | (255 << 8) | (255 << 16) | 0xff000000)); 

     } 

    } 

    private void Form1_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     _Addr = IntPtr.Zero; 

     if (_Handle.IsAllocated) 
     { 
      _Handle.Free(); 

     } 

     _Bitmap.Dispose(); 

     _Bitmap = null; 

     _Pixels = null; 

    } 

} 

.

버튼을 클릭 할 때 이미지가 흰색으로 바뀌지 만 항목이 누락되었습니다.

나는 무엇을 잊는가?

답변

1

솔루션

_Pixels 배열을 업데이트 한 후 pictureBox1.Refresh()를 추가합니다.

매우 빠르게 업데이트되며 고해상도에서 부드러운 비디오를 렌더링 할 수 있습니다. 나는 부드러운 비디오를 렌더링 할만큼 빠른 것이 있는지 확인하기 위해이 방법의 성능을 테스트하고 싶었

당연히

public partial class Form1 : Form 
{ 
    uint[] _Pixels { get; set; } 

    Bitmap _Bitmap { get; set; } 

    GCHandle _Handle { get; set; } 

    IntPtr _Addr { get; set; } 


    public Form1() 
    { 
     InitializeComponent(); 

     int imageWidth = 100; //1920; 

     int imageHeight = 100; // 1080; 

     PixelFormat fmt = PixelFormat.Format32bppRgb; 

     int pixelFormatSize = Image.GetPixelFormatSize(fmt); 

     int stride = imageWidth * pixelFormatSize; 

     int padding = 32 - (stride % 32); 

     if (padding < 32) 
     { 
      stride += padding; 
     } 

     _Pixels = new uint[(stride/32) * imageHeight + 1]; 

     _Handle = GCHandle.Alloc(_Pixels, GCHandleType.Pinned); 

     _Addr = Marshal.UnsafeAddrOfPinnedArrayElement(_Pixels, 0); 

     _Bitmap = new Bitmap(imageWidth, imageHeight, stride/8, fmt, _Addr); 

     pictureBox1.Image = _Bitmap; 

    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     for (int i = 0; i < _Pixels.Length; i++) 
     { 
      _Pixels[i] = ((uint)(255 | (255 << 8) | (255 << 16) | 0xff000000)); 

     } 

     pictureBox1.Refresh(); 

    } 

    private void Form1_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     _Addr = IntPtr.Zero; 

     if (_Handle.IsAllocated) 
     { 
      _Handle.Free(); 

     } 

     _Bitmap.Dispose(); 

     _Bitmap = null; 

     _Pixels = null; 

    } 

} 

테스트 :

형태의 코드는 지금과 같이이다 .

타이머 버튼을 클릭 지금까지

내 시험을 선택합니다 바꾸기로 시작하는 간단한 하나입니다. 나는 button click event을 밀리 세컨드에 한 번씩 발생하는 timer tick event으로 바꿨고 임의의 색상 값으로 _Pixels 어레이를 채웠습니다.

PictureBox이 현재 새로 고침이 완료 될 때까지 새로 고침을 시도하지 않으려면 하나의 bool IsRefreshing 변수를 사용합니다. 제 2 계산 당

프레임

I는 각 리프레시 사이에 경과 된 시간을 측정하는 하나의 변수를 증분 int HzCountPictureBox 리프레시 시작 부분이 변수를 0으로 재설정. HzCount *을 재설정하기 직전에 TextBox에 값을 표시합니다.

16.0 GB의 RAM 결과와

인텔 (R) 코어 (TM) i7-5600U CPU에서 @의 2.60GHz에서 2.60GHz :

72Hz @ 2560x1440

* 헤르츠 또는 Hz에서 초당 프레임 (또는 몇 번 무언가)이 경과했음을 의미합니다.이를 통해 메가 헤르츠는 1 초당 수백만 번 번역되고, 기가 헤르츠는 1 초당 천만 번 (수십억)으로 변환된다는 것을 의미합니다.

0

WinForms 컨트롤은 "단지"때문에 다시 그리지 않습니다. 이유가 있어야합니다.

일부 데이터 원본에는 컨테이너가 업데이트되었음을 ​​알리는 기능이 있습니다. Bitmap 클래스는 그렇지 않습니다. PictureBox가 업데이트되었음을 ​​알리기 위해 PictureBox (또는이 컨트롤을 표시하는 데 사용하는 컨트롤)를 나타내는 방법이 없습니다. SetPixel()을 호출하여 단일 픽셀을 설정하거나 BitmapData 인스턴스를 조작 한 후에 UnlockBits()을 호출 할 수 있지만, Bitmap 클래스를 완전히 제어 할 수없는 고정 배열을 사용하여 비트 맵을 구성한 경우에는이를 수행 할 수 없습니다.

따라서 Bitmap 클래스에는 해당 컨테이너에 업데이트를 알리는 이벤트 나 다른 방법이 없습니다.

이것은 컨트롤이 자체를 다시 그릴 수 있도록 데이터 소스가 업데이트되었음을 ​​포함하는 컨트롤에 알려야 함을 의미합니다.

How to refresh PictureBox에서 설명한대로 pictureBox.Refresh()을 사용할 수 있습니다. 이로 인해 PictureBox 컨트롤이 자체를 무효화하고 다음 (즉시) 다시 칠 때 변경된 비트 맵 데이터를 다시 읽습니다.

도 참조하십시오. MSDN Blogs: Whats the difference between Control.Invalidate, Control.Update and Control.Refresh?.