2016-06-26 4 views
1

После этого вопроса (Show trail of moving pixel in C# WinForm project) для моего личного проекта муравьиной колонии в C#, я пытаюсь применить решение второго предложенного решения: тот, который объединяет рисование тропы в растровое изображение и новые муравьи на поверхности.Динамический рисунок муравьев в winforms во время исполнения муравьиной колонии

[...]Application.Run(new ShowAnts());[...] 

public partial class ShowAnts : Form 
{ 
    Bitmap bmp; 
    int j = 0; 
    public ShowAnts() 
    { 
     InitializeAntProgram(); 
     InitializeComponent(); 
     bmp = new Bitmap(pictureBox1.ClientSize.Width, pictureBox1.ClientSize.Height); 
     pictureBox1.Image = bmp; 
    } 

    public void RenderAnts(object sender, PaintEventArgs e) 
    { 
     using (Graphics G = Graphics.FromImage(pictureBox1.Image)) 
     { 
      while (j < 1000) 
      { 
       Map.EvaporatesPheromones(); 
       foreach (Vector2D food in foodSrcs) 
       { 
        Map.SetMapPoint(food, 500); 
       } 
       foreach (Ant a in ants) 
       { 
        Brush c; 
        c = Brushes.DarkBlue; 
        if (a.role == AntRole.Scout) 
        { 
         a.Move(j); 
         c = Brushes.Red; 
        } 
        e.Graphics.FillRectangle(Brushes.DarkBlue, a.position.x, a.position.y, 1, 1); 
        G.FillRectangle(Brushes.Gray, a.position.x, a.position.y, 1, 1); 
       } 
       j++; 
      } 
     } 
    } 
} 

В приведенном выше коде показана попытка рисовать движение муравья в winform. Он отлично работает, но показывает только конечный результат. Я хотел бы показать поэтапную эволюцию, сохраняя информацию о графическом трейле, не пересматривая мою картографическую информацию.

Пожалуйста, обратите внимание, что рабочая консоль проект, на котором я разработке этого „графический интерфейс“ уже существует так:

  • некоторые переменные установлены в другом месте (т.е .: продукты питания) в проекте;
  • «a.Move (j);» относится к самой логике муравьев (анализ, решение, новое движение ячейки, относящееся к массиву карт);
  • Счетчик `j` используется для подсчета шагов и для установки произвольной остановки, но не имеет реального использования;
  • Я уже хранить в массиве карты и некоторые другие переменные, все сведения, касающиеся феромона, движения, позиции и т.д.
+0

Вы можете отделить каждый шаг внутри j-цикла как свой собственный метод и использовать Graphics только в этом методе. Затем добавьте таймер, при каждом тике вызывается метод. – Martheen

ответ

0

Глядя на ваш код, а также комментарии на предыдущий вопрос, мне кажется, что вам не хватает часть что могло бы оживить движение. Вместо этого вы зацикливаетесь внутри того, что кажется событием Paint.

Вот это быстрое решение. Он добавляет Timer, инициирующее RenderAnts событие, которое, кажется, подключили к pictureBox1.Paint обработчиком ..:

Несколько переменных уровня класса:

int counter = 0; 
int limit = 1000; 
Timer antTimer = new Timer(); 

Начало код:

antTimer.Interval = 50; // <-- pick your speed !! 
antTimer.Tick += (ss, ee) => 
{ pictureBox1.Invalidate(); counter++; if (counter > limit) antTimer.Stop(); }; 
antTimer.Start(); 

Скорость составляет 50 мс, что означает 20 Ticks в секунду.

Событие Tick связано с крошечным Lambda epression и имеет только одно утверждение плюс логику цикла. В InvalidatingpictureBox1 управляет своим событием Paint и тем самым инициируется событие RenderAnts.

Также обратите внимание, что я назвал это «быстрым решением». Обычно вы бы различать между рендерингом и движением код анимации; но в этом случае эта тонкая разница не имеет большого значения.

Теперь мы изменим метод RenderAnts, вынимая цикл:

public void RenderAnts(object sender, PaintEventArgs e) 
{ 
    using (Graphics G = Graphics.FromImage(pictureBox1.Image)) 
    { 
     Map.EvaporatesPheromones(); 
     foreach (Vector2D food in foodSrcs) 
     { 
      Map.SetMapPoint(food, 500); 
     } 
     foreach (Ant a in ants) 
     { 
      Brush c = Brushes.DarkBlue; 
      if (a.role == AntRole.Scout) 
      { 
       a.Move(j); 
       c = Brushes.Red; 
      } 
      e.Graphics.FillRectangle(c, a.position.x, a.position.y, 1, 1); 
      G.FillRectangle(Brushes.Gray, a.position.x, a.position.y, 1, 1); 
     } 
    } 
} 

Вы также можете добавить Start/Stop Button. Также необходимо изменить TrackBar.

Теперь вы сможете наблюдать за ходом ваших муравьев с частотой 20 Гц, оставляя серые следы.

+0

Я смог правильно установить код и он работает. Спасибо! Но у меня есть некоторые недостатки в понимании одной концепции: «При аннулировании управления pictureBox1 запускается событие Paint [...]». Означает ли это, что каждый раз, когда я вызываю 'Invalidate', запускается новое событие« Paint »? Если это так, достаточно вызвать 'Invalidate' каждый раз, когда мне нужно обновить изображение? (Последний вопрос не обязательно касается основного вопроса, он более теоретический) – sipronunciaaigor

+0

Да, так работает 'Invalidate'. (Вам нужно понять полную картину здесь: помимо вашего кода есть другие события (вне вашего контроля), которые вызовут событие «Paint». Наиболее часто: последовательность с минимальным/максимальным размером формы также заставит ее перерисовать себя и все его элементы управления, поэтому, как правило, картина и движение разделены. Не проблема для вашего случая, но когда вы хотите двигаться шаг за шагом, возможно, нажатие кнопки это не будет работать правильно, поскольку внешнее событие запускает «Paint» будет мешать движению. Не проблема с текущей анимацией) – TaW

+0

Еще раз спасибо за всю помощь, которую вы мне дали! Ясно, как свет. – sipronunciaaigor