2016-11-08 2 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, чтобы перечислять пиксели в пути.

Смежные вопросы