Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Разработка Windows Forms > анимация с помощью Graphics


Автор: 4ybaka 21.5.2007, 21:13
нужно выводить подряд неск битмапов,но само собой смещенных на какое то расстояние друг от друга.проблема в след-ем:
при рисовалке след битмапа предидущий не стирается,а значит получаем размазанную картинку.нужно это както исправить.
ЗУ:
1)функция рисования находится в отдельном файле,те не в классе формы.
2)тупая зарисовка фона не подходит - тогда не видно будет,что было за картинкой(она же не простой квадратsmile)
3)каждый раз вызывать Paint для формы не подходит - оч много объектов.

Автор: archeg 22.5.2007, 00:14
Рисовать все в Bitmap, а потом выводить на форму. Можно организовать несколько Bitmap`ов - в виде буфферa. Например перед отрисовкой картинки во второй Bitmap, копировать содержимое в первый а потом рисовать картинку. Таким образом мы получаем первый Bitmap, в котором нарисовано все, кроме картинки. И благодаря ему можно сделать "откат" на состояние без картинки и нарисовать уже новую, смещенную.... 

Если я правльно понял, что нужно smile 

Автор: tol05 22.5.2007, 09:06
archeg, в буфере хранить не надо. Ты же видишь, 
Цитата(4ybaka @  21.5.2007,  21:13 Найти цитируемый пост)
оч много объектов

К тому же, при каждом новом битмапе, как я понял, старые нужно не прорисовывать, а стирать.  smile 

4ybaka, ты при рисовании битмапов запоминай где-нибудь их Rectangle (по отношению к контролу, на котором рисуешь), а потом, в нужный момент вызывай Control.Invalidate (Rectangle).

Автор: archeg 22.5.2007, 10:04
Цитата(tol05 @  22.5.2007,  09:06 Найти цитируемый пост)
archeg, в буфере хранить не надо. Ты же видишь, 
Цитата(4ybaka @  21.5.2007,  21:13 ): "оч много объектов"

Дык я ж не предлагаю их рисовать каждый раз заново. Я предлагаю сделать еффект переднего и заднего плана. То есть на заднем плане у нас то что нужно чтобы было всегда - мы его не прорисовываем каждый раз, мы его прорисовали один раз. Вот на нем и рисуется куча объектов. А на переднем плане мы производим анимацию - перерисовываем все, каждый раз. Потом мы соединяем передний и задний план и отрисовываем на PictreBox - эта операция не зависит от количества объектов, она растровая.

Автор: Ch0bits 22.5.2007, 12:59
Это называется спрайтовая анимация. Есть полно готовых движков на codeproject.com

Автор: 4ybaka 26.5.2007, 23:18
tol05, Control.Invalidate (Rectangle) просто добавляет к области обновления данный квадрат,а само обновление происходит когда получится?а Update() это делает сразу?и нужно ли блокировать форму при многопоточном вызове Control.Invalidate (Rectangle)?и вообще,какие методы можно вызывать без блокировки(при многопоточном вызовах)?...... smile 

Автор: tol05 27.5.2007, 15:44
Контролы позволяют с собой работать только в основном потоке, в котором они созданы. Это уже много раз обсуждалось... и все равно продолжает обсуждаться smile. Примерно каждые две недели создается новая тема с одним и тем же вопросом smile. Ну просто топ-тема!

Так что в многопоточном формате у тебя просто не получиться вызвать хоть какой-нибудь член класса формы. Нужно через Invoke(). И поскольку вся работа с формой будет производиться в создающем ее потоке, ничего блокировать тебе не прийдется. Сколько бы потоков не просило бы форсу перерисоваться, эти запросы будут накапливаться в очереди запросов потока формы, а она будет их обрабатывать по мере своих возможностей, последовательно.

Методы:
Invalidate, Refresh, Update. Почитай о них в MSDN, чесное слово, там нормально написано. Я указал Invalidate просто потому что я им привык еще с плюсов пользоваться. И использую его почти всегда без Update. Некоторые уважают Refresh, все это - дело вкуса и конкретной задачи, ИМХО. 

Автор: mr.DUDA 27.5.2007, 15:54
Цитата(4ybaka @  26.5.2007,  23:18 Найти цитируемый пост)
tol05, Control.Invalidate (Rectangle) просто добавляет к области обновления данный квадрат,а само обновление происходит когда получится?

В обработчике события Paint или перекрытом методе OnPaint.

Цитата(4ybaka @  26.5.2007,  23:18 Найти цитируемый пост)
а Update() это делает сразу?

Не сразу, а ставит в очередь виндошных сообщений. Сразу перерисовывает Refresh, но перерисовывает всё.

Цитата(4ybaka @  26.5.2007,  23:18 Найти цитируемый пост)
и нужно ли блокировать форму при многопоточном вызове Control.Invalidate (Rectangle)? и вообще,какие методы можно вызывать без блокировки(при многопоточном вызовах)?......  

Для вызова перерисовки из другого потока надо вызывать метод Refresh или Update не напрямую а через Invoke:
Код
this.Invoke(new MethodInvoker(delegate()
{
     this.Update();
}));

Автор: 4ybaka 27.5.2007, 22:08
Цитата

Так что в многопоточном формате у тебя просто не получиться вызвать хоть какой-нибудь член класса формы. Нужно через Invoke(). 

Цитата

Для вызова перерисовки из другого потока надо вызывать метод Refresh или Update не напрямую а через Invoke:

я вот вызывал Invalidate из другого потока,а он нормально,ничего не ругался,даже вроде работает...
Код

form.Invalidate(new Rectangle(unit.Position, bitmap.Size));

это как объяснить?

Автор: tol05 28.5.2007, 09:09
Бдительность проверяешь?  smile 

Ну а объясняется просто:
Invalidate отправляет форме только сообщение с просьбой, когда будет возможно, перерисовать (если не трудно)   smile 
А  Refresh и Update - методы прямого действия, и 
Цитата(mr.DUDA @  27.5.2007,  15:54 Найти цитируемый пост)
Для вызова перерисовки из другого потока надо вызывать метод Refresh или Update не напрямую а через Invoke


Вот тебе тест. Попробуй раскоментировать любой из методов (одного достаточно) и получишь эксепшен.
Код

namespace InvalidateCall
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    private void paintButton_Click(object sender, EventArgs e)
    {
      Graphics gr = this.CreateGraphics();
      gr.DrawRectangle(new Pen(new SolidBrush(Color.Black)), new Rectangle(50, 50, 50, 50));
    }

    private void invalidateButton_Click(object sender, EventArgs e)
    {
      Thread thread = new Thread(TestInvalidate);
      thread.Start();
    }

    private void TestInvalidate()
    {
      this.Invalidate();
      //this.Update();
      //this.Refresh();
    }
  }
}



Автор: 4ybaka 28.5.2007, 20:16
Цитата

Бдительность проверяешь? 

а то! smile глаз да глаз за вами нужен...
вот еще один вопрос возник:при перерисовке области окна у нас перерисовываются только контролы,входящие в область перерисовки(если не ошибаюсь).а если на форме на фоне рисуется битмап,то он же не перерисовывается?(только если надо всю форму перерисовать,а это долго...)так вот как можно сделать так,чтобы перерисовывалась и та часть битмапа,кот входит в указанную область?

Автор: tol05 28.5.2007, 22:09
Цитата(4ybaka @  28.5.2007,  20:16 Найти цитируемый пост)
при перерисовке области окна у нас перерисовываются только контролы,входящие в область перерисовки

Что за сложности на ровном месте? 4ybaka, попрактикуйся ты с функциями, параметрами, чем терять время на сомнения и предположения.

Кому ты даешь задание перерисоваться? Форме или конкретному контролу? Форма - это тоже Control, так что для нее также действует Control.Invalidate(Rectangle), она перерисовывается сама и дает коменду перерисоваться контролам, это уже их головняк. smile

Rectangle - это область, которую ты объявляешь недействительной. Вот ты свернул форму в трей - вся область недействительна, перекрыл ее (сбоку наполовину) другим окном - значит та половина недействительна. И контролы на ней перерисуются не все, а только те, что в инвалид-область попали...
Но это поведение сама форма себе обеспечивает. А в твоей ситуации форму никто не трогает, никто не сворачивает, не перекрывает, она себе и спит спокойно. А ты Control.Invalidate(Rectangle) сообщаешь ей:"Эй, тебя перекрыли на 20%, давай перерисовывайся". 

И еще важный момент. Ты рисуешь в OnPaint. Контролы на форме сами должны прорисоваться, а ты еще два матюка ручками нарисовать хочешь. Матюки ты написать сумеешь (я почему-то в этом не сомневаюсь  smile ), а вот контролы прорисовать самому слабо? Вот для этого (и еще для чего-то) и вызывать всегда нужно базовый метод e.OnPaint()
Некоторые на это дело забивают, потом долго жалуются по непонятным траблам... 

Автор: 4ybaka 28.5.2007, 22:56
Цитата

Кому ты даешь задание перерисоваться? 

форме.
Цитата

а вот контролы прорисовать самому слабо? 

просто добавляешь свой контрол(юзер или какой там нашел) в список контролов формы как: this.Controls.Add(),и все,дальше они сами пусть себя рисуют,только вот ворос то в другом был smile :рисуется битмап на всю форму(за один раз),но в OnPaint() только вызывается функция для этого дела(функция лежит в другом файле).теперь если вызвать Invalidate(Rectangle) у формы,она разве обновит(перерисует) часть битмапа,входящую в эту область?я бы щас сам проверил,но чтото со студией страшное произошло:она перестала обращать внимание на контролы на форме(не добавляет,не дает выбрать..) smile ,так что если с этим кто-нибудь сталкивался - отзовитесь,буду благодарен smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)