cadenza
asked on
Modal dialog not modal
In my app I create a dialog which I show with the ShowModal method.
After the dialog shows, a procedure is started (an other dialog method) where I run a loop which contains Application.ProcessMessage s. Now the dialog no longer is modal: my app reacts to all other events, something I don't want. How can I show this dialog modal and still call Application.ProcessMessage s? (I don't want to disable all controls of my main window to simulate a modal dialog). Or is this simply contradictory?
Wim
After the dialog shows, a procedure is started (an other dialog method) where I run a loop which contains Application.ProcessMessage
Wim
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Another thing would be to place your procedure in a seperate thread.
ASKER
Hi Rick and d003303,
HandleMessage nor a separate thread will do what I want. The app will still react on all messages, including messages sent to e.g. the buttonbar of my main form. What I want is that only the messages sent to my modal dialog (or its child controls) are handled. The messages relevant to me are: pressing the close button, scrolling a stringlist and some timer messages.
What I initially had hoped was that by showing the dialog modal, windows/delphi would ignore all messages sent to my app but not to the dialog.
More and more I get the feeling the only way to get this effect is to disable all controls of the main form (which is th only visible part of the app besides the dialog at the moment the dialog is shown)...
HandleMessage nor a separate thread will do what I want. The app will still react on all messages, including messages sent to e.g. the buttonbar of my main form. What I want is that only the messages sent to my modal dialog (or its child controls) are handled. The messages relevant to me are: pressing the close button, scrolling a stringlist and some timer messages.
What I initially had hoped was that by showing the dialog modal, windows/delphi would ignore all messages sent to my app but not to the dialog.
More and more I get the feeling the only way to get this effect is to disable all controls of the main form (which is th only visible part of the app besides the dialog at the moment the dialog is shown)...
What happens if you only use the ShowModal method and no ProcessMessages loop ? Like
MyDialog := TMyDialog.Create(Self);
MyDialog.Init;
if MyDialog.ShowModal = mrOK
then UserPressedOK
else UserPressedCancel;
MyDialog.Free;
Slash/d003303
MyDialog := TMyDialog.Create(Self);
MyDialog.Init;
if MyDialog.ShowModal = mrOK
then UserPressedOK
else UserPressedCancel;
MyDialog.Free;
Slash/d003303
I'm a little confused on the behavior that you are trying to get...like Slash/d003303 shows...if you just place it in Showmodal...this is the default behavior of Delphi...if that's not what you want then you can use this procedure to enable and disable all your children...Just feed the procedure your Forms...and it should disable all it's controls...and also do the reverse...
procedure EnableControls(Enabled: boolean; Control: TWinControl);
var
i: integer;
begin
for i:= 0 to Control.ControlCount -1 do
if ((Control.Controls[i]) is TControl) then
if ((Control.Controls[i]) is TWinControl) and (TWinControl(Control.Contr ols[i]).Co ntrolCount > 0) then
EnableControls(Enabled,TWi nControl(C ontrol.Con trols[i]))
else
TControl(Control.Controls[ i]).Enable d := Enabled;
end;
Rick
procedure EnableControls(Enabled: boolean; Control: TWinControl);
var
i: integer;
begin
for i:= 0 to Control.ControlCount -1 do
if ((Control.Controls[i]) is TControl) then
if ((Control.Controls[i]) is TWinControl) and (TWinControl(Control.Contr
EnableControls(Enabled,TWi
else
TControl(Control.Controls[
end;
Rick
...some cosmetics:
procedure TForm_Progress.VisualFeedb ack(Sender : TObject);
begin
with ProgressThread do
begin
ProgressBar1.Position := Trunc(100 / TotalCount * Position);
Label_Progress.Caption := Format('%d of %d processed', [TotalCount, Position]);
end;
end;
procedure TForm_Progress.FormShow(Se nder: TObject);
var SaveCursor : TCursor;
begin
SaveCursor := Screen.Cursor;
Screen.Cursor := crHourGlass;
StartThread;
Screen.Cursor := SaveCursor;
end;
Slash/d003303
procedure TForm_Progress.VisualFeedb
begin
with ProgressThread do
begin
ProgressBar1.Position := Trunc(100 / TotalCount * Position);
Label_Progress.Caption := Format('%d of %d processed', [TotalCount, Position]);
end;
end;
procedure TForm_Progress.FormShow(Se
var SaveCursor : TCursor;
begin
SaveCursor := Screen.Cursor;
Screen.Cursor := crHourGlass;
StartThread;
Screen.Cursor := SaveCursor;
end;
Slash/d003303
oops, sorry, wrong thread :-|
ASKER
Rick & Slash,
I use the dialog to measure and present data from external equipment. I need a timer for time-out etc., so I need to call ProcessMessages once in a while to be able to catch the timer event. (this is reason 1 I need to call ProcessMessages)
I can not put the loop in the OnShow event handler, since that would not show the dialog (and my measurements would not be shown). Therefor I send a user message to the dialog from the OnShow event handler. In the handler of the user message I put my measurement loop. This is handled after showing the dialog. If I would not call ProcessMessages in the loop, the click of the close button would not be handled. (reason 2).
If I don't call ProcessMessages, I have a modal dialog which can not be closed anymore and the timer event goes unnoticed. If I do call ProcessMessages, the dialog becomes modeless, effectively.
I think the only solution is Ricks disabling of all child controls, so I'll give him the points.
Both Rick and Slash many thanks for your contributions!
Wim
I use the dialog to measure and present data from external equipment. I need a timer for time-out etc., so I need to call ProcessMessages once in a while to be able to catch the timer event. (this is reason 1 I need to call ProcessMessages)
I can not put the loop in the OnShow event handler, since that would not show the dialog (and my measurements would not be shown). Therefor I send a user message to the dialog from the OnShow event handler. In the handler of the user message I put my measurement loop. This is handled after showing the dialog. If I would not call ProcessMessages in the loop, the click of the close button would not be handled. (reason 2).
If I don't call ProcessMessages, I have a modal dialog which can not be closed anymore and the timer event goes unnoticed. If I do call ProcessMessages, the dialog becomes modeless, effectively.
I think the only solution is Ricks disabling of all child controls, so I'll give him the points.
Both Rick and Slash many thanks for your contributions!
Wim
Note...instead of watching for all the messages...you could have your timer...kickoff it's own personal message(using PostMessage and Wm_User)...that you watch for in your HandleMessage loop in your dialog...
Rick
Rick
ASKER
Uhh, I think you may be right. Sounds quite complicated, though. And I'll have to do the same trick with some other components, like the close button? It seems to me that following your other suggestion with the recursive disableing of child controls is more straightforward to program.
I think I'll go for the easy solution now (disabling), keeping in mind what you wrote last, and try that later, when I have more time (instrument i/o always takes a lot of time to get right).
Thanks again,
Wim
I think I'll go for the easy solution now (disabling), keeping in mind what you wrote last, and try that later, when I have more time (instrument i/o always takes a lot of time to get right).
Thanks again,
Wim
mmh, what about the following thought:
unit _tempform;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, ExtCtrls;
type
TForm_Temperature = class(TForm)
Button1: TButton;
ProgressBar1: TProgressBar;
Label1: TLabel;
Label2: TLabel;
ProgressBar2: TProgressBar;
Label3: TLabel;
ProgressBar3: TProgressBar;
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form_Temperature: TForm_Temperature;
implementation
{$R *.DFM}
procedure TForm_Temperature.Timer1Ti mer(Sender : TObject);
begin
// get measuer values form whatever API
// just fake here
ProgressBar1.Position := ProgressBar1.Position + Trunc(Random(20) + 0.6) - 10;
ProgressBar2.Position := ProgressBar2.Position + Trunc(Random(20) + 0.6) - 10;
ProgressBar3.Position := ProgressBar3.Position + Trunc(Random(20) + 0.6) - 10;
end;
procedure TForm_Temperature.FormShow (Sender: TObject);
begin
Timer1.Enabled := true;
end;
end.
// form code
object Form_Temperature: TForm_Temperature
Left = 200
Top = 108
BorderStyle = bsDialog
Caption = 'Temperatures'
ClientHeight = 127
ClientWidth = 258
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 176
Top = 12
Width = 69
Height = 13
Caption = 'Temperature 1'
end
object Label2: TLabel
Left = 176
Top = 36
Width = 69
Height = 13
Caption = 'Temperature 2'
end
object Label3: TLabel
Left = 176
Top = 60
Width = 69
Height = 13
Caption = 'Temperature 3'
end
object Button1: TButton
Left = 172
Top = 92
Width = 75
Height = 25
Caption = '&Close'
Default = True
ModalResult = 2
TabOrder = 0
end
object ProgressBar1: TProgressBar
Left = 12
Top = 12
Width = 149
Height = 13
Min = 0
Max = 100
Position = 50
TabOrder = 1
end
object ProgressBar2: TProgressBar
Left = 12
Top = 36
Width = 149
Height = 13
Min = 0
Max = 100
Position = 50
TabOrder = 2
end
object ProgressBar3: TProgressBar
Left = 12
Top = 60
Width = 149
Height = 13
Min = 0
Max = 100
Position = 50
TabOrder = 3
end
object Timer1: TTimer
Enabled = False
Interval = 100
OnTimer = Timer1Timer
Left = 12
Top = 92
end
end
Slash/d003303
unit _tempform;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, ExtCtrls;
type
TForm_Temperature = class(TForm)
Button1: TButton;
ProgressBar1: TProgressBar;
Label1: TLabel;
Label2: TLabel;
ProgressBar2: TProgressBar;
Label3: TLabel;
ProgressBar3: TProgressBar;
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form_Temperature: TForm_Temperature;
implementation
{$R *.DFM}
procedure TForm_Temperature.Timer1Ti
begin
// get measuer values form whatever API
// just fake here
ProgressBar1.Position := ProgressBar1.Position + Trunc(Random(20) + 0.6) - 10;
ProgressBar2.Position := ProgressBar2.Position + Trunc(Random(20) + 0.6) - 10;
ProgressBar3.Position := ProgressBar3.Position + Trunc(Random(20) + 0.6) - 10;
end;
procedure TForm_Temperature.FormShow
begin
Timer1.Enabled := true;
end;
end.
// form code
object Form_Temperature: TForm_Temperature
Left = 200
Top = 108
BorderStyle = bsDialog
Caption = 'Temperatures'
ClientHeight = 127
ClientWidth = 258
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 176
Top = 12
Width = 69
Height = 13
Caption = 'Temperature 1'
end
object Label2: TLabel
Left = 176
Top = 36
Width = 69
Height = 13
Caption = 'Temperature 2'
end
object Label3: TLabel
Left = 176
Top = 60
Width = 69
Height = 13
Caption = 'Temperature 3'
end
object Button1: TButton
Left = 172
Top = 92
Width = 75
Height = 25
Caption = '&Close'
Default = True
ModalResult = 2
TabOrder = 0
end
object ProgressBar1: TProgressBar
Left = 12
Top = 12
Width = 149
Height = 13
Min = 0
Max = 100
Position = 50
TabOrder = 1
end
object ProgressBar2: TProgressBar
Left = 12
Top = 36
Width = 149
Height = 13
Min = 0
Max = 100
Position = 50
TabOrder = 2
end
object ProgressBar3: TProgressBar
Left = 12
Top = 60
Width = 149
Height = 13
Min = 0
Max = 100
Position = 50
TabOrder = 3
end
object Timer1: TTimer
Enabled = False
Interval = 100
OnTimer = Timer1Timer
Left = 12
Top = 92
end
end
Slash/d003303
Slash...
I think you posted to the wrong thread again....
Rick
I think you posted to the wrong thread again....
Rick
Bought this Q