2013-05-18 4 views
2

그래서 내가하려는 것은 다른 색상의 패널에서 임의의 이미지를 생성하는 것입니다. 사용자는 원하는 패널 수 (픽셀 수)와 색상 수를 선택할 수 있으며, 프로그램은 자동으로 그 이미지를 생성합니다. 나중에이 그림이 필요하고 모든 단일 픽셀을 수정해야하기 때문에 패널을 사용하고 싶습니다. 패널에 익숙해지기 때문에 다른 것들은 사용하지 말고 보관하고 싶습니다.무작위로 생성 된 패널의 성능 개선

그래서 여기 내가이 패널을 만드는 데 사용하고 코드 : 당신이 상상할 수 있듯이 프로그램이 프로세스를 통해에 루프를 가지고 있기 때문에 99x99의 바둑판을 만들 때

//Creates two lists of panels 
     //Add items to list so that these places in the list can be used later. 
     //nudSizeX.Value is the user-chosen number of panels in x-direction 
     for (int a = 0; a < nudSizeX.Value; a++) 
     { 
      horizontalRows.Add(null); 
     } 
     //nudSizeY.Value is the user-chosen number of panels in y-direction 
     for (int b = 0; b < nudSizeY.Value; b++) 
     { 
      allRows.Add(null); 
     } 

     for (int i = 0; i < nudSizeY.Value; i++) 
     { 

      for (int j = 0; j < nudSizeX.Value; j++) 
      { 
       // new panel is created, random values for background color are assigned, position and size is calculated 
       //pnlBack is a panel used as a canvas on whoch the other panels are shown 
       Panel pnl = new Panel(); 
       pnl.Size = new System.Drawing.Size((Convert.ToInt32(pnlBack.Size.Width))/Convert.ToInt32(nudSizeX.Value), (Convert.ToInt32(pnlBack.Size.Height)/Convert.ToInt32(nudSizeY.Value))); 
       pnl.Location = new Point(Convert.ToInt32((j * pnl.Size.Width)), (Convert.ToInt32((i * pnl.Size.Height)))); 

       //There are different types of panels that vary in color. nudTypesNumber iis the user-chosen value for howmany types there should be. 
       int z = r.Next(0, Convert.ToInt32(nudTypesNumber.Value)); 

       //A user given percentage of the panels shall be free, i.e. white. 
       int w = r.Next(0, 100); 
       if (w < nudPercentFree.Value) 
       { 
        pnl.BackColor = Color.White; 

       } 
       //If a panel is not free/white, another rendom color is assigned to it. The random number determinig the Color is storede in int z. 
       else 
       { 
        switch (z) 
        { 
         case 0: 
          pnl.BackColor = Color.Red; 
          break; 
         case 1: 
          pnl.BackColor = Color.Blue; 
          break; 
         case 2: 
          pnl.BackColor = Color.Lime; 
          break; 
         case 3: 
          pnl.BackColor = Color.Yellow; 
          break; 
        } 
       } 

       //Every panel has to be added to a list called horizontal rows. This list is later added to a List<List<Panel>> calles allRows. 
       horizontalRows[j] = (pnl); 
       //The panel has also to be added to the "canvas-panel" pnl back. The advantage of using the canvas panel is that it is easier to determine the coordinates on this panel then on the whole form. 
       pnlBack.Controls.Add(pnl); 
      } 
      allRows[i] = horizontalRows; 
     } 

, 이것은 매우 느립니다 거의 10000 타임스.

성능을 향상 시키려면 어떻게해야합니까? 나는 패널을 가지고 편안하게 지내기를 원한다고 말했다. 패널을 사용하는 것이 내가 생각했던 것보다 훨씬 바보라면, 나는 다른 옵션을 열어두고있다. 프로그램은 이미 생성 된 패널이 더 느려지고 느려집니다. 나는 그것이 커지면 커지는 목록에 추가하기 때문에 그런 것 같아?

이 출력 지금 모습입니다 : The crossed out parts are not important yet

이것은 내가 나중에 내 "사진"을 수행 할 것입니다 : 나는 기본적으로 Schellings 모델을하고 싶어. 이 모델은 자신의 그룹에 속한 사람들의 특정 비율을 원할 때 다른 그룹의 사람들 (즉, 서로 다른 색상)이 어떻게 분리되는지를 보여줍니다. 즉, 나중에 각 패널/픽셀에 대해 이웃이 무엇인지 확인하고 각 픽셀의 색상을 개별적으로 변경할 수 있어야합니다.

나는 준비된 해결책을 원하지 않는다. 나는 그림 생성 과정의 속도를 향상시키는 방법에 대한 조언만을 원하고있다.

당신 대신 당신이 필요로하는 당신의 색상과 다른 정보를 저장하는 데 사용하는 매트릭스를 Panels를 사용

+6

GDI +를 사용하여 캔버스에 픽셀을 그립니다. –

+0

GDI + (초보자)는 잘 모릅니다 만 튜토리얼을 보았는데 좋았습니다. 그러나 그려진 사각형을리스트에 어떻게 추가 할 수 있습니까? 아니면 (내가 말했듯이, 나는 GDI +를 모른다) 가능하지 않습니까? – tomet

+0

당신은 정말로 * 정말로 * 그런 식으로하고 싶지 않습니다. 각 패널은 자체 핸들이있는 별도의 Windows 컨트롤이며 엄청난 오버 헤드가 있습니다! 당신의 직사각형을위한 작은 클래스 래퍼를 사용하십시오. –

답변

0

잘 난 당신이 그 기반으로 원하는 이미지를 그릴 수 있도록, 당신은 2 차원 배열에 색상을 저장할 수 있습니다 GDI를 사용하여 + 대신 제안 또한이 과정을 반복하면서이 코드와 데모 프로젝트를 살펴볼 수도 있습니다 :

gdi +에 익숙하지 않다고 언급 했으므로 데모 프로젝트가 포함되어있어 직접 확인할 수 있습니다 gdi +에서 어떻게 완료되었는지 확인하십시오 :

데모 프로젝트 :

Color[,] colorsTable; 
    Bitmap b; 
    Graphics g; 
    int size = 80; // size of table 
    int pixelWidth = 5; // size of each pixel 
    Random r = new Random(); 
    int rand; 

    // CMDDraw is my Form button which draws the image 

    private void CMDDraw_Click(object sender, EventArgs e) 
    { 
     colorsTable = new Color[size, size]; 
     pictureBox1.Size = new Size(size * pixelWidth, size * pixelWidth); 
     b = new Bitmap(size * pixelWidth, size * pixelWidth); 
     g = Graphics.FromImage(b); 
     for (int y = 0; y < size; y++) 
     { 
      for (int x = 0; x < size; x++) 
      { 
       rand = r.Next(0, 4); 
       switch (rand) 
       { 
        case 0: colorsTable[x, y] = Color.White; break; 
        case 1: colorsTable[x, y] = Color.Red; break; 
        case 2: colorsTable[x, y] = Color.Blue; break; 
        case 3: colorsTable[x, y] = Color.Lime; break; 
        default: break; 
       } 
       g.FillRectangle(new SolidBrush(colorsTable[x, y]), x * pixelWidth, y * pixelWidth, pixelWidth, pixelWidth); 
      } 
     } 
     pictureBox1.Image = b; 
    } 
1

대단히 감사합니다. GDI+을 사용하여 사각형을 그릴 때이 매트릭스를 사용하면 OnPaint 이벤트가 발생합니다. 드로잉을 할 수

private void myPanel_Paint(object sender, PaintEventArgs e) 
{ 
    for (var y=0; y < matrix.GetUpperBound(0); y++) 
     for (var x=0; x < matrix.GetUpperBound(1); x++) 
     { 
      var Brush = new SolidBrush(matrix[y,x]); 
      e.Graphics.FillRectangle(Brush, new Rectangle(x*10, y*10, 10, 10)); 
     } 
} 
+0

좋습니다. 도움이됩니다. 이미 그려진 사각형의 색상을 변경하려면 어떻게해야합니까? 그럼 내가 새로 만들어야 해? 이전 버전이 자동으로 삭제됩니까? 또는 패널과 같이 색상을 어떻게 든 변경할 수 있습니까?(내 사랑하는 오래된 패널 ;-) – tomet

+0

매트릭스의 색상 값을 변경하고 픽셀을 페인팅하는 패널에서 Invalidate()를 호출하면됩니다. – Dusan

+0

좋아, 내가 필요할 때 그것을 시도해 보겠다. 하지만 어떻게 든 페인트 이벤트를 처리 할 수 ​​없습니다. 단추를 클릭 할 때만 내 그림을 만들고 싶지만, 지금은 양식이로드 될 때 만듭니다. – tomet

1

를 사용하여 A의 PictureBox : 여기

당신은 색상을 포함 행렬이있는 경우 10 × 10 "픽셀"을 그리는 방법에 대한 예입니다. 이미 각 패널의 위치를 ​​확인하는 코드가 있습니다. 각 패널을 변경하여 각 위치에 사각형을 그립니다. 이렇게하면 10.000 GUI 객체로 작업하는 대신 보드에 직사각형을 그릴 수 있습니다.

오, 모델/로직 및 뷰를 분리하여 보관하십시오. 모든 정보가 담긴 하나의 행렬을 유지하고 그리기 위해 "Paint method"를 사용하십시오.

귀하의 모델은이 같은 것을 볼 수 있었다 :

MyPanel[,] panels; 
class MyPanel 
{ 
    Color color; 
} 

은, 패널의 모든 이웃을 확인 단지 패널 매트릭스에서 확인할 쉽게 이런 식으로.

그리고보기는 같이해야합니다 :

class View 
{ 
    Paint(MyPanel[,] panels) 
    { 
    //Draw 
    } 
} 
1

ColorsTableDemoProject 내가 여기 당신의 가장 좋은 방법은 사각형을 그릴 수있는 사용자 정의 컨트롤 클래스를 작성하는 것입니다 생각하고, 사용자 지정 컬렉션 클래스는 사각형을 유지 할 수 있습니다.

스퀘어 컬렉션 클래스는 다음과 같이 수 :

public sealed class ColouredSquareCollection 
{ 
    readonly int _width; 
    readonly int _height; 
    readonly Color[,] _colours; 

    public ColouredSquareCollection(int width, int height) 
    { 
     _width = width; 
     _height = height; 

     _colours = new Color[_width, _height]; 

     intialiseColours(); 
    } 

    public Color this[int x, int y] 
    { 
     get { return _colours[x, y]; } 
     set { _colours[x, y] = value; } 
    } 

    public int Width 
    { 
     get { return _width; } 
    } 

    public int Height 
    { 
     get { return _height; } 
    } 

    void intialiseColours() 
    { 
     for (int y = 0; y < _height; ++y) 
      for (int x = 0; x < _width; ++x) 
       _colours[x, y] = Color.White; 
    } 
} 

그런 다음 당신은 사용자 지정 컨트롤을 작성합니다. 이렇게하려면 Add new item -> Windows Forms -> Custom Control을 통해 새 맞춤 컨트롤을 추가하고 ColouredSquareHolder으로 전화하십시오.

그런 다음 코드를 다음과 같이 변경하십시오. 이 모든 사각형 그리기에 대한 책임을 얼마나주의 :

public sealed partial class ColouredSquareHolder: Control 
{ 
    ColouredSquareCollection _squares; 

    public ColouredSquareHolder() 
    { 
     ResizeRedraw = true; 
     DoubleBuffered = true; 
     InitializeComponent(); 
    } 

    public ColouredSquareCollection Squares 
    { 
     get 
     { 
      return _squares; 
     } 

     set 
     { 
      _squares = value; 
      Invalidate();  // Redraw after squares change. 
     } 
    } 

    protected override void OnPaint(PaintEventArgs pe) 
    { 
     base.OnPaint(pe); 

     if (_squares == null) 
      return; 

     int w = Width; 
     int h = Height; 
     int nx = _squares.Width; 
     int ny = _squares.Height; 

     var canvas = pe.Graphics; 

     for (int yi = 0; yi < ny; ++yi) 
     { 
      for (int xi = 0; xi < nx; ++xi) 
      { 
       int x1 = (xi*w)/nx; 
       int dx = ((xi + 1)*w)/nx - x1; 
       int y1 = (yi*h)/ny; 
       int dy = ((yi+1)*h)/ny - y1; 

       using (var brush = new SolidBrush(_squares[xi, yi])) 
        canvas.FillRectangle(brush, x1, y1, dx, dy); 
      } 
     } 
    } 
} 

지금 당신이 광장 수집을 설정 ColouredSquareHolder에 추가하고 폼에 그를 추가해야합니다.

먼저 ColouredSquareHolder를 테스트 프로그램에 추가하고 컴파일하여 Windows Forms Editor의 도구 상자에 표시되도록합니다.

Form1이라는 새 기본 양식을 만들고 도구 상자에서 ColouredSquareHolder을 추가하고 ColouredSquareHolder을 도킹 -> 채우기로 설정하십시오. 이 데모에서는 기본값 인 colouredSquareHolder1을 그대로 두십시오.

은 다음과 같이 당신의 Form1 클래스를 변경 :

public partial class Form1: Form 
{ 
    readonly ColouredSquareCollection _squares; 
    readonly Random _rng = new Random(); 

    public Form1() 
    { 
     InitializeComponent(); 

     _squares = new ColouredSquareCollection(100, 100); 

     for (int x = 0; x < _squares.Width; ++x) 
      for (int y = 0; y < _squares.Height; ++y) 
       _squares[x, y] = randomColour(); 

     colouredSquareHolder1.Squares = _squares; 
    } 

    Color randomColour() 
    { 
     return Color.FromArgb(_rng.Next(256), _rng.Next(256), _rng.Next(256)); 
    } 
} 

은 프로그램을 실행하고 사각형 그리기에 얼마나 빨리 참조하십시오.

이 기능을 통해 여러분이 구축 할 수있는 기반이 마련되기를 바랍니다.

참고 : 사각형 컬렉션의 색을 변경하는 경우 양식의 컨트롤에서 .Invalidate()을 호출하여 새 색으로 다시 그려야합니다.

관련 문제