пятница, 11 ноября 2011 г.

wxPython: Gif-анимация и прозрачность

Кратко об анимации в wxPython

Дяденька делает анимацию на wxPython
В wxPython средства для работы с анимацией имеются в виде пакета wx.animate. Пакет довольно нехитрый - всего несколько классов, из которых чаще всего в работе используются 2:

  1. wx.animate.Animation - инкапсулирует параметры анимации, а также поддерживает загрузку анимации из файла. Поддерживает Gif и Ani форматы анимаций.
  2. wx.animate.GifAnimationCtrl - Контрол для отрисовки проигрывания Gif-анимации в графическом интерфейсе приложения.
Последний - очень соблазнительное средство, так как позволяет фактически в несколько строчек добавить в окно готовую анимацию:

...
ag_fname
= r"progress.gif"
ag = wx.animate.GIFAnimationCtrl(self, -1, ag_fname, pos=(0, 0), size=(64,64))
ag.GetPlayer().UseBackgroundColour(True)     
ag.Play()

Довольно неплохо. И даже больше ... прозрачность.

Прозрачность

Третья строчка вышеприведенного кода намекает нам, что анимация будет использовать вместо цвета, который в ней установлен прозрачным - фоновый цвет окна. Поговаривают, что на GTK оно так и есть, но я, к сожалению, не имел удовольствия в этом убедится, так как пишу софт, давший вдохновение на написания этой статьи, исключительно для ОС Windows.

Что ж, на Windows оно немножко не совсем так. В случае, если окно, на котором находится контрол имеет установленный цвет фона без дополнительных излишеств - все отлично. Проблемы начинаются тогда, когда на форме вручную через графический контекст рисуется картинка или, чего хуже, форма вообще не прямоугольная, а произвольного формата (к сожалению, так получилось, что мой случай).

В таком случае GifAnimationCtrl только вредит, поскольку на нашей красивой форме вырисовывается анимация с прямоугольным серым (ну, или каким там у вас будет) фоном.

Выход есть

Что же, отбрасываем контрол, берем голую анимацию (благо wx.animate.Animation имеет все средства для получения информации о кадрах, их количестве и "прозрачном" цвете) и рисуем на необходимом окне пользуясь DC (естественно, BufferedDC, чтобы избежать неприятных миганий) и таймером. Все, что нам нужно:
  • wx.Timer
  • wx.animate.Animation (.GetFrameCount(), .GetFrame(), ...)
  • wx.BufferedDC
Единственное, что здесь важно, - метод GetFrame(frame_number) возвращает не wx.Bitmap, который рисуюют, а wx.Image. Поэтому, чтобы получить картинку для рисования, нужно сделать Animation.GetFrame(number).ConvertToBitmap().

При этом, если исходный файл анимации имеет прозрачный цвет, картинке даже не надо делать SetMask(), маска будет создана исходя из кадра и цвета прозрачности. Код приводить не буду, в различных ситуациях он может быть разным, но смысл, думаю, понятен.

4 комментария:

  1. "Пакет довольно нехитрый - всего парочка классов, из которых чаще всего в работе используются 2"

    Т.е. все классы пакета используются чаще всего? ;)

    ОтветитьУдалить
  2. Ну почему же, есть еще их предки, которые удобны для наследования, если вы, например какую-то хитрую анимацию свою сделать хотите, или какой-ниьбудь еще формат анимации реализовать свой.

    ОтветитьУдалить
  3. Я к тому, что "пара" и "2" равнозначны

    ОтветитьУдалить
  4. Ладно, привык думать, что парочка == несколько, так уж и быть, поправлю =)

    ОтветитьУдалить

В этом гаджете обнаружена ошибка