views:

500

answers:

3

For example I disable runtime two buttons. After I disabled first button it bacame gray, the second - it also became gray. But I do not know how to make the repainting simultaneous! I need something like that:

  1. freeze the Form (disable repainting)
  2. disable first button
  3. disable second button
  4. Enable Form repainting

If someone knows how to implement that, please help!

+3  A: 

Look at the Win32 API WM_SETREDRAW message. For example:

SendMessage(Handle, WM_SETREDRAW, False, 0);
Button1.Enabled := False;
Button2.Enabled := False;
SendMessage(Handle, WM_SETREDRAW, True, 0);
InvalidateRect(Handle, nil, True);
Remy Lebeau - TeamB
Clearly untested (doesn't work and doesn't even compile)
Deltics
I use WM_SETREDRAW in several projects, it works fine. Also, VCL components that do have Begin/EndUpdate() methods use WM_SETREDRAW internally.
Remy Lebeau - TeamB
It didn't work in this case... *1)* FALSE and TRUE are not valid params for SendMessage() [Integer required] *2)* After changing the FALSE and TRUE params to 0 and 1 respectively so that it does compile and work as intended the form doesn't repaint at the end - the buttons remain visibly "enabled" unless/until obscured and thereby forced to repaint *3)* even if it had worked, try/finally would be de rigeur *4)* also even if it had worked, it still would have been pointless due to the reliance on message processing for the painting to occur
Deltics
WM_SETREDRAW may be viable for changing the painting behaviour of an individual control (such as a listbox, whilst adding/removing items etc), but I do not believe that is going to be reliable when trying to affect the behaviour of controls that are parented by (or are themselves parents of) other controls ... you are too dependent on clipping behaviour and interactions of same between all the involved controls. i.e. in this case you would need to **WM_SETREDRAW** and subsequently Invalidate the **buttons** (and any/all other controls involved), not the parent form.
Deltics
Thanks a lot! With really tiny changes it works perfekt: SendMessage(Handle, WM_SETREDRAW, 0, 0); Dutton1.Enabled := False; Dutton2.Enabled := False; SendMessage(Handle, WM_SETREDRAW, -1, 0); Repaint;
Alexander
+5  A: 

Messages cannot be processed until your application re-enters a message loop, so any attempt to modify/update control state that relies on message processing will not work within a single sequence of code that does not "pump" messages.

Fortunately the VCL controls typically provide a means for force repainting without waiting for messages to be processed, via the Update method:

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

This works independently of having to disable form repainting. The form will not repaint until your application goes into a message loop anyway, so disabling form painting and re-enabling within a single procedure that does not itself cause message processing is a waste of time.

This may not be exactly simultaneous repainting of the two buttons, but truly simultaneous painting of two separate control is impossible without getting into multithreaded GUI painting code which I think is way beyond the scope of this problem. Calling Update on two buttons in this way will be as near simultaneous in effect as you need however.

Deltics
A: 

This could help: the API LockWindowUpdate(Handle: HWND) locks drawing to the handle and children.

ex:

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

Once the locked handle is reset, the component is repainted

elias551
Please see http://blogs.msdn.com/b/oldnewthing/archive/2007/02/19/1716211.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2007/02/20/1726880.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2007/02/21/1735472.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2007/02/22/1742084.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2007/02/23/1747713.aspx to see why it's not a good idea.
Sertac Akyuz