Solved

z order problem

Posted on 2013-12-06
3
850 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
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 26

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 37

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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …
Learn how to create flexible layouts using relative units in CSS.  New relative units added in CSS3 include vw(viewports width), vh(viewports height), vmin(minimum of viewports height and width), and vmax (maximum of viewports height and width).

861 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

Need Help in Real-Time?

Connect with top rated Experts

24 Experts available now in Live!

Get 1:1 Help Now