#c# #forms #button #paint #doevents
#c# #формы #кнопка #Краски #doevents
Вопрос:
При использовании Button-Paint-Event кнопка не обновляется на каждой итерации цикла for. Но форма или панель обновляются плавно с каждой итерацией.
Итак, при выполнении этого кода кнопка запускается с цветом по умолчанию, затем, после завершения цикла for, отображает последний цвет в массиве цветов. Он не обновляется с каждой итерацией.
Мой вопрос: Кто-нибудь знает, почему кнопка не обновляется с каждой итерацией, но другие элементы управления используют тот же код?
void Main()
{
Color[] colors = new Color[10]
{
Color.White, Color.Red, Color.Blue, Color.Green, Color.Black,
Color.Purple, Color.Brown, Color.Yellow, Color.Gray, Color.Lime
};
Button button = new Button();
button.FlatStyle = FlatStyle.Flat;
button.Paint = (sender, e) =>
{
for (int i = 0; i < 10; i )
{
e.Graphics.FillRectangle(
new SolidBrush(colors[i]),
new RectangleF(0, 0, button.Width, button.Height));
Thread.Sleep(100);
Application.DoEvents();
}
};
Form form = new Form();
form.Controls.Add(button);
form.Show();
}
Комментарии:
1. Событие рисования является особенным. — Не пытайтесь выполнить анимацию в событии Paint. У вас нет никакого контроля над ним, и вы должны позволить системе работать с ним, включая любую настройку. Вы можете переместить этот цикл наружу и вызывать Invalidate после каждого режима ожидания или использовать таймер, как предложено, что является обычным средством для анимации..
2. Почему у меня нет контроля над этим? Я могу реализовать разные методы для реагирования на разные ситуации. У меня пока не было проблем, кроме проблемы с кнопкой.
3. Потому что системе тоже нужно его вызвать; и это потребует вольностей при его оптимизации .. Кстати: 10 * 100 мс = 1секунда
4. «10 * 100 мс = 1 секунда». …итак? Пример заключается в том, чтобы сформулировать вопрос и проблему. Это не окончательная реализация, просто упрощенная версия. И базовое событие рисования все равно будет вызвано, это просто «дополнительно».
Ответ №1:
Мой вопрос: Кто-нибудь знает, почему кнопка не обновляется с каждой итерацией, но другие элементы управления используют тот же код?
Понятия не имею.
Однако ваш подход изначально ошибочен. Вы никогда не должны Sleep () в основном потоке пользовательского интерфейса, поскольку это может привести к тому, что пользовательский интерфейс не будет отвечать. Кроме того, вызов DoEvents() может вызвать больше событий Paint() (код повторного ввода).
Используйте элемент управления Timer и измените BackColor кнопки оттуда.
Вот простой пример использования перечислителя для многократного перебора цветов:
static void Main()
{
Color[] colors = new Color[10]
{
Color.White, Color.Red, Color.Blue, Color.Green, Color.Black,
Color.Purple, Color.Brown, Color.Yellow, Color.Gray, Color.Lime
};
IEnumerator colorEnum = colors.GetEnumerator();
Button button = new Button();
button.FlatStyle = FlatStyle.Flat;
System.Windows.Forms.Timer tmr = new System.Windows.Forms.Timer();
tmr.Interval = 250;
tmr.Tick = (s, e) =>
{
if (!colorEnum.MoveNext())
{
colorEnum.Reset();
colorEnum.MoveNext();
}
button.BackColor = (Color)colorEnum.Current;
};
Form form = new Form();
form.Shown = (s, e) =>
{
tmr.Start();
};
form.Controls.Add(button);
Application.Run(form);
}
Комментарии:
1. Ну, как я уже сказал, я сократил его до минимума. В моем реальном коде был бы bool для проверки, выполняется ли уже событие paint. И время ожидания составило бы 1 миллисекунду, что должно привести к идеально отзывчивому пользовательскому интерфейсу. Я бы держал в уме ваш метод, возможно, это просто более надежный подход.
2. Небольшой переход в режим ожидания просто приведет к сверхбыстрому миганию кнопки; недостаточно времени, чтобы увидеть текущий цвет. Очевидно, что вы могли бы написать цикл для задержки на указанное количество времени, чтобы «исправить» это, но единственная причина, по которой он был бы «отзывчивым», связана с вызовом DoEvents (), который является немедленным предупреждением о том, что это неправильный подход. =)
3. … и вы никогда не упоминали, что это был сжатый / минимальный код.
4. Это верно. Я вырезал свой исходный текст, чтобы не раздувать сообщение. Извините за это. Я думаю, что мигание не произойдет. Что он будет делать, так это, например, переход от темно-серого к светло-серому. или из стального синего в голубой. такие цвета. Почему вызов DoEvents неправильный?
5. DoEvents() — это один из самых быстрых способов отправить StackOverflow в биполярное безумие комментариев. Смотрите , DoEvents — это зло? для одного обсуждения. Всегда ли это wrong?…no . Но в целом, обычно существуют более эффективные способы выполнения задачи.