Почему событие FormPaint запускается несколько раз, когда мышь перемещается по TButton

Почему событие формы OnPaint запускается так много раз в этом приложении?

  1. Создайте новое приложение VCL Forms с двумя элементами управления TButton, одним элементом управления TMemo и одним элементом управления TBitBtn.

  2. Используйте этот код:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Memo1.Lines.Clear;
    end;
    
    procedure TForm1.FormPaint(Sender: TObject);
    begin
      Memo1.Lines.Add('FormPaint');
    end;
    
  3. Запустите приложение.

Когда мышь перемещается на TButton, событие OnPaint запускается 4 раза, и 4 раза, когда мышь перемещается из TButton.

Когда мышь перемещается на TBitBtn, событие OnPaint запускается 3 раза, и 3 раза, когда мышь перемещается от TBitBtn.

Когда стиль изменяется в «Проект/Параметры/Приложение/Внешний вид», например, на «Луна», вместо этого я получу такое поведение:

Когда мышь перемещается на TButton/TBitBtn, событие OnPaint запускается 1 раз, и 2 раза, когда мышь перемещается из TButton/TBitBtn.

Почему несоответствие?

Можно ли избежать события OnPaint при наведении мыши на TButton?

У меня есть обновление подписки XE8 1 (и Windows 10).


person Thomas    schedule 16.09.2015    source источник
comment
Почему это важно для вас? Если это проблема, то вам, вероятно, нужно исправить ошибку проектирования где-то еще в вашем коде.   -  person David Heffernan    schedule 16.09.2015
comment
Это простое приложение с прямым вопросом об основных функциях Delphi. Меня интересует поведение и различия. Вот почему это важно для меня.   -  person Thomas    schedule 16.09.2015
comment
OnPaint вызывается, потому что окно формы получило сообщение WM_PAINT. Он получил это, потому что часть окна недействительна. Почему для вас проблема покрасить окно? Это реальная проблема. FWIW, без наличия стилей VCL это не вопрос Delphi. Скорее это вопрос winapi.   -  person David Heffernan    schedule 16.09.2015
comment
Вопрос заключался в том, почему событие запускается несколько раз, в данном случае 4 раза, а не один раз. Если это не вопросы Delphi, получу ли я тот же результат, например. С#?   -  person Thomas    schedule 16.09.2015
comment
Я хочу сказать, что система отправляет сообщения Windows, которые приводят к запуску события OnPaint. Получили бы вы такой же результат на C#? Это зависит от того, какой UI-фреймворк вы использовали и как этот фреймворк реализует свои элементы управления. WPF не использует оконные элементы управления, а WinForms не использует элемент управления Win32 BUTTON.   -  person David Heffernan    schedule 16.09.2015


Ответы (1)


Эффект наведения кнопок отвечает за то, что вы наблюдаете. Когда вы наводите курсор на кнопку, она меняет внешний вид. Когда вы отводите курсор от кнопки, она меняет свой внешний вид. Каждое изменение внешнего вида приводит к срабатыванию события OnPaint формы. Именно так работает основная система рисования. Чтобы нарисовать дочерний элемент управления, родительскому элементу управления доставляется сообщение WM_PRINTCLIENT, что, в свою очередь, приводит к срабатыванию события OnPaint формы.

Вы можете увидеть, что это так, отключив темы выполнения. Когда вы делаете это, перемещение курсора по кнопкам не приводит к срабатыванию OnPaint.

Причина, по которой стили VCL и темы Windows приводят к различному количеству запускаемых событий OnPaint, заключается просто в том, что они по-разному обрабатывают отрисовку. Но стили VCL также имеют эффекты наведения, и они также приводят к запуску OnPaint событий.

Можно ли избежать события OnPaint при наведении курсора на кнопку?

В приложении в стиле VCL вы, вероятно, могли бы использовать стиль VCL, который не имел эффектов наведения. В тематическом приложении Windows вы можете отключить тему для кнопки.

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

person David Heffernan    schedule 16.09.2015