2016-11-08 13 views
1

私は、マウスをクリックしたり移動したりしてピクセルの色を塗りつぶすなどの基本的なペイント機能を可能にするピクセル "グリッド"を作成する最善の方法を見つけようとしています。テキストや図形をピクセルにレンダリングするために、コピー、貼り付け、移動、または他のグラフィック機能を使用するための領域。私はthis exampleのようないくつかのサンプルを見てきましたが、これはパネルコントロールを無効にして、私が達成しようとしているものと似たようなものですが、ペイントが遅く、マウス。私が探している機能を可能にするコントロール、あるいは私が上書きできるコントロールはありますか?ペイントピクセルとレンダリングテキストのグリッドを作成する

ここで、上記の例は、どのように見えるかのサンプルです: 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

ここでは最小であるが、この例では、ビットマップをピクセルストレージとして使用し、拡大したピクセルを編集用のパネルに表示します。

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

} 

エディタは、ピクセルサイズとプロパティの最小値の間で描画する色を公開し..:

あなたは多分このように、Picturebox pBox_Target.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を使用してパスまたはループを境界線に塗りつぶして、パス内のピクセルを列挙します。

関連する問題