Solved

z order problem

Posted on 2013-12-06
3
837 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 25

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 36

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

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

708 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

17 Experts available now in Live!

Get 1:1 Help Now