2016-01-06 3 views
4

Я пытаюсь создать небольшое приложение для рисования в Visual Studio 2015. Мой проект относится к категории приложений Windows Form. У меня следующая проблема:Как сохранить нарисованные фигуры после обновления формы?

private void Form1_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (a == 1) 
     { 
      if (r == 1 || el == 1) 
      { 
       int x = Math.Min(inX, e.X); 
       int y = Math.Min(inY, e.Y); 
       int width = Math.Max(inX, e.X) - Math.Min(inX, e.X); 
       int height = Math.Max(inY, e.Y) - Math.Min(inY, e.Y); 
       rect = new Rectangle(x, y, width, height); 
       Refresh(); 
      } 
      else if (l == 1) 
      { 
       ep = e.Location; 
       Refresh(); 
      } 
      else 
      { 
       ep = e.Location; 
       g = this.CreateGraphics(); 
       g.DrawLine(p, sp, ep); 
       sp = ep; 
      } 
     } 
    } 

Эта часть моих кодов создает Прямоугольную (второго если), отрезок (третьего если) и только строку. Он работает почти так же, как MS Paint; прямоугольник или сегмент линии не завершены до тех пор, пока пользователь не отпускает левый клик мыши (Mouse up). Но когда наконец создается прямоугольник, когда я пытаюсь создать еще один, форма обновляется (Refresh();), и я теряю все предыдущие нарисованные прямоугольники или линии. Я попытался заменить Refresh(); с Invalidate (rect); и Обновить();, но я не получаю результат, которого хочу.

Вместо этого, я получаю это:

enter image description here

+0

Immediate (как GDI в вашем случае) против удержанного режима объяснения - https://msdn.microsoft.com/en-us/library/windows/desktop/ff684178(v=vs.85).aspx –

ответ

6

Вы должны сделать все рисунок в отдельном растровом изображении buffer, что вы сохраняете вокруг. Нарисуйте свои фигуры на это растровое изображение, затем, когда экран действительно нужно обновить, нарисуйте буфер на экране.

Кроме того, в любое время, когда вы звоните CreateGraphics, вам необходимо запомнить Dispose, иначе он будет утечка ресурсов, таких как сумасшедший.

Невероятно простой пример

using System; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Windows.Forms; 

namespace DrawExample 
{ 
    public partial class Form1 : Form 
    { 

     private Bitmap _canvas; //This is the offscreen drawing buffer 
     private Point _anchor; //The start point for click-drag operations 
     private Rectangle? _ghost; 
     private Brush _ghostBrush; 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      _ghostBrush = new SolidBrush(Color.FromArgb(200, 200, 200, 255)); //This creates a slightly blue, transparent brush for the ghost preview 
      ResizeCanvas(); 
     } 

     private void Form1_Resize(object sender, EventArgs e) 
     { 
      ResizeCanvas(); 
     } 

     /// <summary> 
     /// Resizes the offscreen bitmap to match the current size of the window, it preserves what is currently in the bitmap. 
     /// </summary> 
     private void ResizeCanvas() 
     { 
      Bitmap tmp = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppRgb); 
      using (Graphics g = Graphics.FromImage(tmp)) 
      { 
       g.Clear(Color.White); 
       if (_canvas != null) 
       { 
        g.DrawImage(_canvas, 0, 0); 
        _canvas.Dispose(); 
       } 
      } 
      _canvas = tmp; 
     } 

     private void Form1_MouseDown(object sender, MouseEventArgs e) 
     { 
      if (e.Button == MouseButtons.Left) 
      { 
       _anchor = new Point(e.X, e.Y); 
      } 
     } 
     private void Form1_MouseMove(object sender, MouseEventArgs e) 
     { 
      if (e.Button == MouseButtons.Left) 
      { 
       _ghost = new Rectangle(_anchor.X, _anchor.Y, e.X - _anchor.X, e.Y - _anchor.Y); 
       this.Invalidate(); 
      } 
     } 

     private void Form1_MouseUp(object sender, MouseEventArgs e) 
     { 
      if (e.Button == MouseButtons.Left) 
      { 
       //Create a Graphics for the offscreen bitmap 
       using (Graphics g = Graphics.FromImage(_canvas)) 
       { 
        Rectangle rect = new Rectangle(_anchor.X, _anchor.Y, e.X - _anchor.X, e.Y - _anchor.Y); 
        g.FillRectangle(Brushes.White, rect); 
        g.DrawRectangle(Pens.Black, rect); 
       } 

       _ghost = null; 

       //This queues up a redraw call for the form 
       this.Invalidate(); 
      } 
     } 

     private void Form1_Paint(object sender, PaintEventArgs e) 
     { 

      if (_ghost.HasValue) 
      { 
       using (Bitmap tmp = new Bitmap(_canvas)) 
       { 
        using (Graphics g = Graphics.FromImage(tmp)) 
        { 
         g.FillRectangle(_ghostBrush, _ghost.Value); 
         g.DrawRectangle(Pens.Black, _ghost.Value); 

         e.Graphics.DrawImage(tmp, 0, 0); 
        } 
       } 
      } 
      else 
      { 
       e.Graphics.DrawImage(_canvas, 0, 0); 
      } 
     } 


     //This stops the flickering 
     protected override void OnPaintBackground(PaintEventArgs e) 
     { 
      //Do nothing 
     } 
    } 
} 
+0

Спасибо за такой быстрый ответ. Я ищу учебник для битового массива, но я не могу найти что-то полезное и тщательное. У вас есть руководство? – Xaris

+0

Я добавил несколько заметок в свой ответ за вас. –

+0

Вот пример MSDN, показывающий более полный код. Он не использует подход с постоянным буфером, который, как Дэвид и я предположили, хотя. Но это дает хороший пример создания и рисования для растрового изображения вне экрана. https://msdn.microsoft.com/en-us/library/ms172506(v=vs.90).aspx –

3

Вы рисуете непосредственно на поверхности рисования формы. Эта поверхность не является постоянной. Он длится до следующего цикла краски.

Вместо этого вы должны:

  1. Розыгрыш с закадровым растрового изображения.
  2. Нарисуйте это растровое изображение, например, на управление ящиком. Или нарисуйте его непосредственно на поверхности рисунка формы в своем событии Paint.
+0

Или любой другой вид сохраняющейся модели изображения - дерево объектов WPF, настраиваемое дерево/список объектов (например, массив прямоугольников). –

+0

@Alexei действительно так –

+0

@DavidHeffernan Прежде всего, спасибо за такой немедленный ответ. Мне кажется, что это ваше второе предложение. Но если я создам картинку в моей форме, могу ли я рисовать растровое изображение внутри нее. Я все еще учусь, поэтому спасибо за терпение. – Xaris

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