Solved

z order problem

Posted on 2013-12-06
3
940 Views
Last Modified: 2013-12-12
I have a windows application written with Delphi 2010 and occasionally forms that I have opened modal will get stuck behind my main application form.  What causes this?

Thanks for your help

Daniel
0
Comment
Question by:DanielManchester
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
3 Comments
 
LVL 19

Expert Comment

by:MerijnB
ID: 39702223
Do you have the formstyle of your main form set to stayontop? If yes, set the formstyle of your modal form to stayontop too.
0
 
LVL 27

Accepted Solution

by:
Sinisa Vuk earned 250 total points
ID: 39704468
This is know problem with parent-modal forms. I use this procedure to solve this issue.

Put this in definition section (before implementation)
procedure SwitchToThisWindow(h1: hWnd; x: bool); stdcall; external user32 Name 'SwitchToThisWindow';

Open in new window


.. and call procedure in OnShow event of modal form:
SwitchToThisWindow(Self.Handle, True);

Open in new window

0
 
LVL 38

Assisted Solution

by:Geert Gruwez
Geert Gruwez earned 250 total points
ID: 39705678
this is a bug
which unfortunately can't be reproduced, so it's difficult to solve

handling it in the onshow is not always enough ...
sometimes the window isn't visible until after that event :-)

there is 2 questions on this with solutions
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_26286057.html
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_23461413.html

i'd use a timer which puts the top form in front:
Maybe add some intelligence to detect changes to the form list ?
procedure TfrmMain.TimerLoginDialogTimer(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to Screen.FormCount-1 do
    if fsModal in Screen.Forms[I].FormState then
    begin
      if Screen.Forms[I].Visible and Application.Active then
      begin
        Screen.Forms[I].BringToFront;
        Exit;
      end;
    end;
end;

Open in new window


I setup a small test to test the bad behaviour
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm2 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Timer1: TTimer;
    Timer2: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

uses Unit3, TypInfo;

function GetOrdValue(Info: PTypeInfo; const SetParam): Integer;
begin
  Result := 0;

  case GetTypeData(Info)^.OrdType of
    otSByte, otUByte:
      Result := Byte(SetParam);
    otSWord, otUWord:
      Result := Word(SetParam);
    otSLong, otULong:
      Result := Integer(SetParam);
  end;
end;

function SetToString(Info: PTypeInfo; const SetParam; Brackets: Boolean): AnsiString;
var
  S: TIntegerSet;
  TypeInfo: PTypeInfo;
  I: Integer;
begin
  Result := '';

  Integer(S) := GetOrdValue(Info, SetParam);
  TypeInfo := GetTypeData(Info)^.CompType^;
  for I := 0 to SizeOf(Integer) * 8 - 1 do
    if I in S then
    begin
      if Result <> '' then
        Result := Result + ',';
      Result := Result + GetEnumName(TypeInfo, I);
    end;
  if Brackets then
    Result := '[' + Result + ']';
end;

procedure TForm2.Button1Click(Sender: TObject);
var frm: TForm;
begin
  frm := TForm3.Create(Application);
  frm.Show;
  frm.BringToFront;
  frm.Update;

  frm := TForm3.Create(Application);
  frm.Visible := False;
  frm.ShowModal;
end;

procedure TForm2.Timer1Timer(Sender: TObject);
var I: Integer;
  F: TForm;
  P: PTypeInfo;
  FS: TFormState;
  S: String;
begin
  Memo1.Clear;
  for I := 0 to Screen.FormCount - 1 do
  begin
    F := Screen.Forms[I];
    Fs := F.FormState;
    S := SetToString(PTypeInfo(TypeInfo(TFormState)), FS, False);
    memo1.Lines.Add('#: ' + IntToStr(I) + ', Form: ' + F.Name + ', FormState: ' + S +
      'Visible, ' + BoolToStr(F.Visible));
  end;
end;

procedure TForm2.Timer2Timer(Sender: TObject);
var I: Integer;
begin
// fix the form in front problem
  for I := 0 to Screen.FormCount-1 do
    if fsModal in Screen.Forms[I].FormState then
    begin
      if Screen.Forms[I].Visible and Application.Active then
      begin
        Screen.Forms[I].BringToFront;
        Exit;
      end;
    end;
end;

end.

Open in new window

object Form2: TForm2
  Left = 138
  Top = 118
  Caption = 'Form2'
  ClientHeight = 525
  ClientWidth = 963
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 32
    Top = 24
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Memo1: TMemo
    Left = 24
    Top = 72
    Width = 849
    Height = 401
    Lines.Strings = (
      'Memo1')
    TabOrder = 1
  end
  object Timer1: TTimer
    Interval = 1000
    OnTimer = Timer1Timer
    Left = 176
    Top = 32
  end
  object Timer2: TTimer
    Interval = 10000
    OnTimer = Timer2Timer
    Left = 276
    Top = 32
  end
end

Open in new window


unit Unit3;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm3 = class(TForm)
    Timer1: TTimer;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Timer1Timer(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
  public
    constructor Create(AOwner: TComponent); override;
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

constructor TForm3.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Width := 200;
  Height := 200;
end;

procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

procedure TForm3.FormShow(Sender: TObject);
begin
  if fsModal in FormState then
    Caption := 'Modal'
  else Caption := 'Modeless';

end;

procedure TForm3.Timer1Timer(Sender: TObject);
begin
  if not (fsModal in FormState) then
    BringToFront;
  timer1.Enabled := False;
end;

end.

Open in new window


object Form3: TForm3
  Left = 287
  Top = 165
  Caption = 'Form3'
  ClientHeight = 525
  ClientWidth = 963
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  Position = poOwnerFormCenter
  Visible = True
  OnClose = FormClose
  OnShow = FormShow
  PixelsPerInch = 96
  TextHeight = 13
  object Timer1: TTimer
    OnTimer = Timer1Timer
    Left = 104
    Top = 40
  end
end

Open in new window


The test:
After clicking the button it creates 2 forms.
first modeless, the next modal
a second later, the modeless form is put in front
(with timer on form3)

as the modal form only allows input and not the modeless form on top
nothing can be done with the app anymore.
> same problem as you have probably

after timer 2 has run (every 10 seconds) it should bring the modal form to the front
and the app should be responsive again
0

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…
This tutorial will teach you the special effect of super speed similar to the fictional character Wally West aka "The Flash" After Shake : http://www.videocopilot.net/presets/after_shake/ All lightning effects with instructions : http://www.mediaf…
Suggested Courses
Course of the Month11 days, 3 hours left to enroll

628 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question