2016-11-08 16 views
1

我試圖找到最好的路徑去創建一個像素「網格」,將允許基本的繪畫功能,如通過單擊和移動鼠標着色像素,選擇用於複製,粘貼或移動的區域,或者使用其他圖形功能來爲像素呈現文本或形狀。我已經看了一些例子,比如this example,它覆蓋了面板控制,並且與我試圖實現的效果類似,但是繪畫很慢,看起來它不能很好地用於繪製老鼠。是否有控制權,或者我可以重寫的控制權,這將允許我尋找的功能?C#爲繪畫像素和渲染文本創建網格

以下是對上面的例子看起來像一個示例: Sample pixel grid

而且我適應從上面的例子代碼:

public class Pixel 
{ 
    public Rectangle Bounds { get; set; } 
    public bool IsOn { get; set; } 
    public bool IsSelected { get; set; } 
} 


public class PixelGridControl : Panel 
{ 
    public int Columns = 99; 
    public int Rows = 63; 
    private readonly Pixel[,] pixels; 

    public PixelGridControl() 
    { 
     this.DoubleBuffered = true; 
     this.ResizeRedraw = true; 

     // initialize pixel grid: 
     pixels = new Pixel[Columns, Rows]; 
     for (int y = 0; y < Rows; ++y) 
     { 
      for (int x = 0; x < Columns; ++x) 
      { 
       pixels[x, y] = new Pixel(); 
      } 
     } 
    } 

    // adjust each column and row to fit entire client area: 
    protected override void OnResize(EventArgs e) 
    { 
     int top = 0; 
     for (int y = 0; y < Rows; ++y) 
     { 
      int left = 0; 
      int height = (this.ClientSize.Height - top)/(Rows - y); 
      for (int x = 0; x < Columns; ++x) 
      { 
       int width = (this.ClientSize.Width - left)/(Columns - x); 
       pixels[x, y].Bounds = new Rectangle(left, top, width, height); 
       left += width; 
      } 
      top += height; 
     } 
     base.OnResize(e); 
    } 

    protected override void OnPaint(PaintEventArgs e) 
    { 
     e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; 
     for (int y = 0; y < Rows; ++y) 
     { 
      for (int x = 0; x < Columns; ++x) 
      { 
       if (pixels[x, y].IsOn) 
       { 
        e.Graphics.FillRectangle(Brushes.Gold, pixels[x, y].Bounds); 
       } 
       else 
       { 
        ControlPaint.DrawButton(e.Graphics, pixels[x, y].Bounds, 
              ButtonState.Normal); 
       } 
      } 
     } 
     base.OnPaint(e); 
    } 

    // determine which button the user pressed: 
    protected override void OnMouseDown(MouseEventArgs e) 
    { 
     for (int y = 0; y < Rows; ++y) 
     { 
      for (int x = 0; x < Columns; ++x) 
      { 
       if (pixels[x, y].Bounds.Contains(e.Location)) 
       { 
        pixels[x, y].IsOn = true; 
        this.Invalidate(); 
        MessageBox.Show(
         string.Format("You pressed on button ({0}, {1})", 
         x.ToString(), y.ToString()) 
        ); 
       } 
      } 
     } 
     base.OnMouseDown(e); 
    } 
} 
+0

爲什麼說GDI +速度慢,任何測量?你知道[Double Buffered Graphics](https://msdn.microsoft.com/en-us/library/b367a457(v = vs.110).aspx)嗎? –

+0

我並不是想說GDI +很慢,只是我在鏈接的示例中提到的實現。我編輯了這篇文章,並添加了我正在測試的代碼,該代碼也使用了您指的DoubleBuffered圖形。在點擊鼠標按鈕和矩形區域的實際外觀變化顏色之間,大約需要2秒。我試圖找出是否有不同的控制方式或不同的方式來實現這一點,這將提供流暢的體驗而不會有任何延遲。 – Rob

+0

你可以提交演示測試項目到** github **供其他人測試嗎? –

回答

1

下面是一個最小使用位圖作爲像素存儲的示例,並在面板中顯示放大的像素進行編輯。

您可以通過設置它來編輯像素的Picturebox pBox_Target.Image,也許像這樣使用它:

public Form1() 
{ 
    InitializeComponent(); 
    .. 
    .. 
    pixelEditor1.APBox = pBox_Target; 
    pixelEditor1.TgtBitmap = (Bitmap)pixelEditor1.APBox.Image; 
    .. 

} 

編輯暴露像素大小,以最小的性能中繪製的顏色..

總而言之,它略超過100行 - 當然它的意圖是擴大!

這是在工作中: enter image description here

class PixelEditor : Panel 
{ 
    public Color DrawColor { get; set; } 
    public Color GridColor { get; set; } 
    int pixelSize = 8; 
    public int PixelSize 
    { 
     get { return pixelSize; } 
     set 
     { 
      pixelSize = value; 
      Invalidate(); 
     } 
    } 


    public Bitmap TgtBitmap { get; set; } 
    public Point TgtMousePos { get; set; } 

    Point lastPoint = Point.Empty; 

    PictureBox aPBox = null; 
    public PictureBox APBox { 
     get { return aPBox; } 
     set 
     { 
      if (value == null) return; 
      aPBox = value; 
      aPBox.MouseClick -=APBox_MouseClick; 
      aPBox.MouseClick +=APBox_MouseClick; 
     } 
    } 

    private void APBox_MouseClick(object sender, MouseEventArgs e) 
    { 
     TgtMousePos = e.Location; 
     Invalidate(); 
    } 


    public PixelEditor() 
    { 
     DoubleBuffered = true; 
     BackColor = Color.White; 
     GridColor = Color.DimGray; 
     DrawColor = Color.Red; 
     PixelSize = 10; 
     TgtMousePos = Point.Empty; 

     if (APBox != null && APBox.Image != null) 
      TgtBitmap = (Bitmap)APBox.Image; 

     MouseClick +=PixelEditor_MouseClick; 
     MouseMove +=PixelEditor_MouseMove; 
     Paint +=PixelEditor_Paint; 
    } 

    private void PixelEditor_Paint(object sender, PaintEventArgs e) 
    { 
     if (DesignMode) return; 

     Graphics g = e.Graphics; 

     int cols = ClientSize.Width/PixelSize; 
     int rows = ClientSize.Height/PixelSize; 

     if (TgtMousePos.X < 0 || TgtMousePos.Y < 0) return; 

     for (int x = 0; x < cols; x++) 
      for (int y = 0; y < rows; y++) 
      { 
       int sx = TgtMousePos.X + x; 
       int sy = TgtMousePos.Y + y; 

       if (sx > TgtBitmap.Width || sy > TgtBitmap.Height) continue; 

       Color col = TgtBitmap.GetPixel(sx, sy); 

       using (SolidBrush b = new SolidBrush(col)) 
       using (Pen p = new Pen(GridColor)) 
       { 
        Rectangle rect = new Rectangle(x * PixelSize, y * PixelSize, 
                 PixelSize, PixelSize); 
        g.FillRectangle(b, rect); 
        g.DrawRectangle(p, rect); 
       } 
      } 
    } 

    private void PixelEditor_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (e.Button != MouseButtons.Left) return; 

     int x = TgtMousePos.X + e.X/PixelSize; 
     int y = TgtMousePos.Y + e.Y/PixelSize; 

     if (new Point(x, y) == lastPoint) return; 

     Bitmap bmp = (Bitmap)APBox.Image; 
     bmp.SetPixel(x,y, DrawColor); 
     APBox.Image = bmp; 
     Invalidate(); 
     lastPoint = new Point(x, y); 
    } 

    private void PixelEditor_MouseClick(object sender, MouseEventArgs e) 
    { 
     int x = TgtMousePos.X + e.X/PixelSize; 
     int y = TgtMousePos.Y + e.Y/PixelSize; 
     Bitmap bmp = (Bitmap)APBox.Image; 
     bmp.SetPixel(x,y, DrawColor); 
     APBox.Image = bmp; 
     Invalidate(); 
    } 


} 

注意,該解決方案既採用了特殊的像素級的也使得選擇套像素的任何規定。要實施大多數選擇工具,您可以使用GraphicsPath;你可以使用IsVisible填充路徑或循環遍歷其邊界使用IsVisible枚舉路徑中的像素。