Как изменить элементы управления одновременно, не перекрашивая каждое?

Например, мне нужно отключить две кнопки во время выполнения. После того, как я отключил первую кнопку, она стала серой, вторая - тоже стала серой. Но как сделать перекраску одновременной - не знаю!

Мне нужно что-то вроде этого:

  1. заморозить форму (отключить перерисовку)
  2. отключить первую кнопку
  3. отключить вторую кнопку
  4. Включить перерисовку формы

Как это реализовать?


person Alexander    schedule 11.03.2010    source источник


Ответы (5)


Посмотрите на сообщение Win32 API WM_SETREDRAW. Например:

SendMessage(Handle, WM_SETREDRAW, False, 0);
Button1.Enabled := False;
Button2.Enabled := False;
SendMessage(Handle, WM_SETREDRAW, True, 0);
InvalidateRect(Handle, nil, True);
person Remy Lebeau    schedule 11.03.2010
comment
Я использую WM_SETREDRAW в нескольких проектах, работает нормально. Кроме того, компоненты VCL, у которых есть методы Begin / EndUpdate (), внутренне используют WM_SETREDRAW. - person Remy Lebeau; 11.03.2010
comment
В данном случае это не сработало ... 1) ЛОЖЬ и ИСТИНА не являются допустимыми параметрами для SendMessage () [Требуется целое число] 2) После изменения ЛОЖЬ и ИСТИНА params на 0 и 1 соответственно, чтобы он компилировался и работал должным образом, форма не перерисовывалась в конце - кнопки остаются видимыми включенными до тех пор, пока / пока не будут скрыты и, таким образом, вынуждены перерисовать 3), даже если это сработало, try / finally будет de rigeur 4) также, даже если бы это сработало, это все равно было бы бессмысленно из-за зависимости от обработки сообщений для рисования - person Deltics; 11.03.2010
comment
WM_SETREDRAW может быть жизнеспособным для изменения поведения рисования отдельного элемента управления (например, списка, при добавлении / удалении элементов и т. Д.), Но я не верю, что это будет надежным при попытке повлиять на поведение элементов управления, которые являются родителями (или сами являются родителями) других элементов управления ... вы слишком зависимы от поведения обрезки и взаимодействия между всеми задействованными элементами управления. т.е. в этом случае вам нужно будет WM_SETREDRAW и впоследствии сделать недействительными кнопки (и любые / все другие задействованные элементы управления), а не родительскую форму. - person Deltics; 11.03.2010
comment
Большое спасибо! С действительно небольшими изменениями он работает идеально: SendMessage (Handle, WM_SETREDRAW, 0, 0); Dutton1.Enabled: = False; Dutton2.Enabled: = False; SendMessage (Дескриптор, WM_SETREDRAW, -1, 0); Перекрасить; - person Alexander; 12.03.2010
comment
Будьте осторожны с SETREDRAW: fgaillard.com/2011/02/the-unortunate -effect-of-wm_setredraw - person Z80; 17.12.2012

Сообщения не могут быть обработаны до тех пор, пока ваше приложение повторно не войдет в цикл обработки сообщений, поэтому любая попытка изменить / обновить состояние управления, которое зависит от обработки сообщений, не будет работать в рамках одной последовательности кода, которая не «перекачивает» сообщения.

К счастью, элементы управления VCL обычно предоставляют средства для принудительной перерисовки, не дожидаясь обработки сообщений, с помощью метода Update:

Button1.Enabled := False;
Button2.Enabled := False;
Button1.Update;
Button2.Update;

Это работает независимо от необходимости отключать перерисовку формы. Форма не будет перерисовываться до тех пор, пока ваше приложение не войдет в цикл сообщений, поэтому отключение рисования формы и повторное включение в рамках одной процедуры, которая сама по себе не вызывает обработку сообщений, является пустой тратой времени.

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

person Deltics    schedule 11.03.2010
comment
Синхронные сообщения обрабатываются немедленно. Асинхронные требуют прокачки очереди сообщений. - person David Heffernan; 26.03.2014
comment
Только если HWND, на который отправляется сообщение (SendMessage), был создан тем же потоком, который отправляет сообщение. В противном случае сообщение остается синхронным, но окно приема будет обрабатывать сообщение только при перекачке очереди сообщений. Точно так же, хотя вы можете отправить синхронное сообщение PAINT, обработка этого сообщения может сама полагаться на асинхронные сообщения, полученные от обработчика PAINT. продолжение ... - person Deltics; 26.03.2014
comment
... следствием ненадежности синхронных сообщений, обрабатываемых по-настоящему синхронно (или немедленно), является то, что если вы хотите вызвать подпрограмму, которая обычно вызывается в ответ на сообщение, и делать это синхронно, тогда самый надежный способ сделать это. так что просто вызвать эту процедуру синхронно и не полагаться на обмен сообщениями. И наоборот, при других обстоятельствах обмен сообщениями должен быть предпочтительным и более надежным механизмом. :) - person Deltics; 26.03.2014
comment
Нет, это не совсем так. Синхронный не означает немедленной обработки. Это означает, что обрабатывается до возврата из вызывающей функции. SendMessage не возвращается, пока целевое окно не обработает сообщение. И вы не можете отправить WM_PAINT. - person David Heffernan; 26.03.2014
comment
Во всяком случае, меня привел сюда еще один недавний вопрос. Ваш ответ более понятен принятому ответу, который для меня не имеет смысла. Тем не менее, вопрос является фиктивным, потому что он описывает проблему без объяснения того, как ее воссоздать. Установка Enabled на True для двух кнопок одним и тем же методом не вызывает видимых проблем. Я предполагаю, что настоящая проблема в коде, которым никто не поделился. - person David Heffernan; 26.03.2014

Кому Elias551:

LockWindowUpdate, вероятно, не лучший способ справиться с этим, поскольку он предназначен для операций перетаскивания и может вносить небольшие ошибки при неправильном использовании.

См. http://blogs.msdn.com/b/oldnewthing/archive/2007/02/22/1742084.aspx

Вместо этого используйте SendMessage(hwnd, WM_SETREDRAW, FALSE, 0)

person Jon Grewer    schedule 18.01.2011

Приведенное выше решение с WM_SETREDRAW не обновляет дочерние окна.

Вместо этого я рекомендую RedrawWindow:

RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_ALLCHILDREN);
person Pavel Labutin    schedule 24.09.2015

Это может помочь: API LockWindowUpdate (Handle: HWND) блокирует рисование для дескриптора и дочерних элементов.

ex:

procedure TForm1.ColorButtons();
begin
  LockWindowUpdate(Self.Handle);
  // Make some stuff
  LockWindowUpdate(0);
end;

После сброса заблокированной ручки компонент перекрашивается.

person elias551    schedule 20.07.2010