• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 433
  • Last Modified:

Prevent flash when closing MDI windows from OnShow event

I have a generic procedure that allows me to close forms during the OnShow event if, for example, it proves impossible to open databases or some other problem means that I do not wish the form to complete its display.

This works perfectly well, but gives a flash of the window caption bar which looks awful.  I cannot hide the window if it is an MDI form...  My code:

procedure ForceFormClose(Form: TForm);
begin
  with Form do
    begin
      // Disable any Resize processing for form
      OnResize := NIL;
      //  Zero form size
      Height := 0;
      Width := 0;
      // minimize form
      WindowState := wsMinimized;
      // Despatch Close message
      PostMessage(Handle, WM_CLOSE, 0, 0);
    end;
end;

How can I get rid of the flash?

Chris Bray.
0
chrisbray
Asked:
chrisbray
  • 4
  • 2
1 Solution
 
Russell LibbySoftware Engineer, Advisory Commented:

You can hide it, but you need to do it at a lower level than the class wrapper (as Delphi traps for it on MDI children). Give the following a try to see if it makes a difference:

Regards,
Russell

procedure ForceFormClose(Form: TForm);
begin

  with Form do
  begin
     // Disable any Resize processing for form
     OnResize:=nil;
     // Zero form size
     Height := 0;
     Width := 0;
     // Hide form
     ShowWindow(Handle, SW_HIDE);
     // Despatch Close message
     PostMessage(Handle, WM_CLOSE, 0, 0);
  end;

end;
0
 
chrisbrayAuthor Commented:
No difference, except that the flash is at the top of the screen (default position) instead of at the bottom when minimizing...

Chris Bray.
0
 
Russell LibbySoftware Engineer, Advisory Commented:
Could you post enough code to demonstrate the problem (mdi form and child), as I am unable to duplicate the flash

Russell
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Russell LibbySoftware Engineer, Advisory Commented:
Chris,

Nevermind, I can dupe it if I create 100 child windows in a loop. Looking at a resolution now....

Russell
0
 
Russell LibbySoftware Engineer, Advisory Commented:
Chris,

Delphi seems pretty insistent that if you enter the OnShow event (regardless of form style), then it WILL show the window. Mainly due to this code:

// Borland's code for TCustomForm.CMShowingChanged(var Message: TMessage);

...
        if FormStyle = fsMDIChild then
        begin
          { Fake a size message to get MDI to behave }
          if FWindowState = wsMaximized then
          begin
            SendMessage(Application.MainForm.ClientHandle, WM_MDIRESTORE, Handle, 0);
            ShowWindow(Handle, SW_SHOWMAXIMIZED);
          end
          else
          begin
            ShowWindow(Handle, ShowCommands[FWindowState]);
            CallWindowProc(@DefMDIChildProc, Handle, WM_SIZE, SIZE_RESTORED,
              Width or (Height shl 16));
            BringToFront;
          end;
          SendMessage(Application.MainForm.ClientHandle,
            WM_MDIREFRESHMENU, 0, 0);
        end
        else
          ShowWindow(Handle, ShowCommands[FWindowState]);
...

Makes it pretty hard to disable the showing of the window, as everything you need to access is private to the form instance. There is a way around this though, and it is by re-parenting the form (window) to a parent form that is hidden. Below is the code for a unit that does just that.

Regards,
Russell

--

unit ForceClose;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit           :  FORCECLOSE
//   Date           :  05.02.2005
//   Author         :  rllibby
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows,
  Messages,
  SysUtils,
  Classes,
  Forms;

////////////////////////////////////////////////////////////////////////////////
//   Form function
////////////////////////////////////////////////////////////////////////////////
procedure ForceFormClose(Form: TForm);

implementation

////////////////////////////////////////////////////////////////////////////////
//   Protected variables
////////////////////////////////////////////////////////////////////////////////
var  hwndReparent:  HWND = 0;
     bRegistered:   Boolean =False;
     lpwcTemp:      TWndClass;
     lpwcReparent:  TWndClass = (style: 0;
                                 lpfnWndProc: @DefWindowProc;
                                 cbClsExtra: 0;
                                 cbWndExtra: 0;
                                 hInstance: 0;
                                 hIcon: 0;
                                 hCursor: 0;
                                 hbrBackground: 0;
                                 lpszMenuName: nil;
                                 lpszClassName: 'TReparentClass');

procedure ForceFormClose(Form: TForm);
begin

  // Clear event handlers
  Form.OnShow:=nil;
  Form.OnResize:=nil;

  // Set show state
  ShowWindow(Form.Handle, SW_HIDE);

  // Reparent the window
  SetParent(Form.Handle, hwndReparent);

  // Post a close message to the form
  PostMessage(Form.Handle, WM_CLOSE, 0, 0);

end;

initialization

  // Get instance
  lpwcReparent.hInstance:=HInstance;

  // Get class info
  bRegistered:=GetClassInfo(HInstance, lpwcReparent.lpszClassName, lpwcTemp);

  // Check registered state and window procedure
  if not(bRegistered) or (lpwcTemp.lpfnWndProc <> @DefWindowProc) then
  begin
     // Unregister
     if bRegistered then Windows.UnregisterClass(lpwcReparent.lpszClassName, HInstance);
     // Register
     Windows.RegisterClass(lpwcReparent);
  end;

  // Create hidden window to use as parent
  hwndReparent:=CreateWindowEx(WS_EX_TOOLWINDOW, lpwcReparent.lpszClassName, '', WS_POPUP, 0, 0, 0, 0, 0, 0, HInstance, nil);

finalization

  // Destroy window
  if (hwndReparent <> 0) then DestroyWindow(hwndReparent);

end.




0
 
chrisbrayAuthor Commented:
Hi Rusell,

An excellent answer, and solved the problem immediately.  Thank you very much for your help.

Chris Bray.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

  • 4
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now