Выполнить анимацию свойств Windows Forms в C#
Изменение свойств элемента управления со временем называется анимацией свойств. Отслеживание того, где свойства элемента управления, например, его положение при его перемещении, может быть сложным, особенно если вам нужно одновременно анимировать несколько объектов. В этом примере используется следующий класс ControlSprite, чтобы отслеживать элемент управления, когда он перемещается по прямой.
// Информация о текущем движении. public class ControlSprite { public System.Windows.Forms.Control MovingControl; public int EndX, EndY; public float CurrentX, CurrentY; private float Dx, Dy; private DateTime LastMoveTime; private TimeSpan TotalElapsed, MoveUntil; private Timer MoveTimer; public delegate void DoneEventHandler(object sender); public event DoneEventHandler Done; // Подготовьтесь к перемещению элемента управления. public ControlSprite(System.Windows.Forms.Control control) { MovingControl = control; } // Начнем движение. public void Start(int end_x, int end_y, int pixels_per_second) { CurrentX = MovingControl.Location.X; CurrentY = MovingControl.Location.Y; EndX = end_x; EndY = end_y; // Рассчитаем общее расстояние. float dx = EndX - CurrentX; float dy = EndY - CurrentY; float dist = (float)Math.Sqrt(dx * dx + dy * dy); // Вычисление количества X и Y для перемещения в секунду. Dx = pixels_per_second * dx / dist; Dy = pixels_per_second * dy / dist; // Посмотрим, сколько времени займет общий ход. int milliseconds = (int)(1000.0f * dist / pixels_per_second); MoveUntil = new TimeSpan(0, 0, 0, 0, milliseconds); TotalElapsed = new TimeSpan(0); // Создаем таймер. MoveTimer = new Timer(); MoveTimer.Interval = 10; MoveTimer.Tick += MoveTimer_Tick; // Начнем движение. Start(); } // Продолжаем движение. public void Start() { LastMoveTime = DateTime.Now; MoveTimer.Enabled = true; } // Остановить перемещение. public void Stop() { MoveTimer.Enabled = false; } // Переместите элемент управления. private void MoveTimer_Tick(object sender, EventArgs e) { // Посмотрим, сколько времени прошло с момента последнего хода. DateTime now = DateTime.Now; TimeSpan elapsed_since_last = now - LastMoveTime; LastMoveTime = DateTime.Now; // Посмотрим, остановимся ли мы. TotalElapsed += elapsed_since_last; if (TotalElapsed >= MoveUntil) { // Стоп. MoveTimer.Enabled = false; CurrentX = EndX; CurrentY = EndY; if (Done != null) Done(this); } else { CurrentX += (float)(Dx * elapsed_since_last.TotalSeconds); CurrentY += (float)(Dy * elapsed_since_last.TotalSeconds); } MovingControl.Location = new Point((int)CurrentX, (int)CurrentY); } }
Класс начинается с некоторых относительно простых деклараций. Единственная действительно интересная часть здесь - объявление события Done, которое класс поднимает, когда его управление закончило движение.
Конструктор класса принимает в качестве параметра элемент управления, который он будет перемещать.
Первая перегруженная версия метода Start перемещает вещи. Он сохраняет текущее и конечное местоположение элемента управления и вычисляет общее расстояние, на которое должен двигаться элемент управления. Затем он использует это расстояние и параметр pixels_per_second, чтобы определить, сколько он должен увеличивать координату X и Y элемента управления в секунду для достижения желаемого движения в пикселях в секунду. Метод Start вычисляет общий период времени, в течение которого будет выполняться движение, создает Timer для управления движением, а затем вызывает вторую перегруженную версию Start .
Вторая версия Start сохраняет текущее время в переменной LastMoveTime и включает Timer.
Метод Stop просто отключает таймер sprite
.
Когда Timer вызывает событие Tick, спрайт определяет, сколько времени прошло с момента последнего обновления позиции элемента управления и добавило истекшее время к общему прошедшему до сих пор. Если элемент управления движется достаточно долго, чтобы достичь цели, код отключает Timer, переводит элемент управления в его конечное положение и вызывает событие Done. Если элемент управления не двигался достаточно долго, чтобы достичь цели, код увеличивает координаты X и Y элемента управления. Р>
В примерной программе используются два спрайта для анимации Button и Label одновременно.
Следующий код показывает, как программа готовит анимировать свои элементы управления.
private ControlSprite ButtonSprite, LabelSprite; // Создаем контрольные спрайты. private void Form1_Load(object sender, EventArgs e) { ButtonSprite = new ControlSprite(btnStart); ButtonSprite.Done += ButtonSprite_Done; LabelSprite = new ControlSprite(lblMessage); }
Этот код объявляет два объекта ControlSprite. Обработчик события Load инициализирует объекты и устанавливает обработчик событий Button Done (описанный в скором времени).
При нажатии кнопки выполняется следующий код.
// Запуск или остановка. private void btnStart_Click(object sender, EventArgs e) { const int PixelsPerSecond = 200; if (btnStart.Text == "Start") { // Кнопка Пуск. Измените заголовок на Стоп. btnStart.Text = "Stop"; // Посмотрим, где мы. if (btnStart.Location.X == 12) { // Переместите кнопку вниз и вправо. ButtonSprite.Start(197, 229, PixelsPerSecond); LabelSprite.Start(12, 232, PixelsPerSecond); } else if (btnStart.Location.X == 197) { // Переместите кнопку вверх и влево. ButtonSprite.Start(12, 12, PixelsPerSecond); LabelSprite.Start(186, 12, PixelsPerSecond); } else { // Продолжим предыдущий ход кнопки. ButtonSprite.Start(); LabelSprite.Start(); } } else { // Кнопка остановки. Измените заголовок на «Пуск». btnStart.Text = "Start"; // Остановить перемещение. ButtonSprite.Stop(); LabelSprite.Stop(); } }
Этот код сначала определяет, будет ли в настоящее время кнопка Button запускать или останавливать. Если кнопка Button говорит «Пуск», код говорит «Стоп». Тогда, если X-позиция Button равна 12, код запускает оба спрайта, перемещая элементы управления в позиции (197, 229) и (12, 232). Если X-позиция Button равна 197, код запускает оба спрайта, перемещая элементы управления в позиции (12, 12) и (186, 12).
Если X-позиция Button не является ни 12, ни 197, код просто вызывает методы sprites Start, чтобы они продолжали предыдущий ход. (Таким образом, вы можете остановить и перезапустить движение, когда захотите.)
Если кнопка начинается с надписей Stop, то код просто вызывает методы sprites Stop.
В следующем коде показан обработчик события Button Done.
// Кнопка перемещается. public void ButtonSprite_Done(object sender) { btnStart.Text = "Start"; }
Этот код просто сбрасывает текст Button для начала, чтобы вы могли перезапустить анимацию.