I'm using Delphi 4.
I have a main form with a button that dynamically creates a new form.
I'd like the new form to be visible, but to show up BEHIND the main form.
I've tried calling SendToBack() immediately after FormCreate(). But that makes the window flicker quickly before it's actually sent to back.
I've tried making the form invisible, then SendToBack(), then Visible := true.
But the new form is still at the front.
It looks like SendToBack() only works with visible forms? How can I cause the form to be shown behind the main form?
This worked for me:
SetWindowPos(newform.Handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_SHOWWINDOW
or SWP_NOMOVE or SWP_NOOWNERZORDER or SWP_NOSIZE or SWP_NOACTIVATE);
newform.Visible := true;
Thanks for help!
make the second window (e.g. form2) invisible, then call:
showWindow(form2.handle,SW_SHOWNOACTIVATE);
-don
Related
I have a delphi application with multiple forms. Initially I had tried a setup where each newly opened form was a frame and the "parent" of this form (whichever called to open the form) was hidden as the child was shown with the child being resized and relocated to give a seamless effect of having one window, when the child is closed the parent is relocated and again made visible. All forms have a bsSingle border style for the Windows title block.
This approach worked well for positioning however the issue I have is a noticeable flicker as the parent form is closed and the child opened, and as there is a small time period where no form is opened the icon/tray on the start bar would shift around and itself become hidden and visible.
Does anybody have any advice on solving this problem? I thought perhaps if I only had one form with the border within the application and opened each new form within this border it would work better - though I am unsure how exactly to do this.
Any help is much appreciated.
It is easy to make one form appear as a child inside another. Create a new form which will contain and create your other forms:
procedure TMainForm.FormCreate(Sender: TObject);
var
F : TForm;
begin
F := TOneOfYourChildForms.Create(Self);
F.Parent := Self;
F.Show();
end;
Create both your child forms similar to this, then just do Show on the one you want to display and Hide on the other. Set BorderStyle to bsNone on the child forms to remove the caption. Turn off Auto-Create on your forms in project settings if you create them yourself like this instead.
I've had success with this design, and I think it helped to have the contents of the "main form" within a TFrame as well. When you want to show the main form, you would just perform a frame swap.
In Delphi XE Update 1, I’m getting seemingly random behavior of modal forms if the parent (main) form’s FormStyle is set to fsStayOnTop.
1) With MainFormOnTaskbar := False (the old way), everything “just works”. With the new MainFormOnTaskbar := True, modal forms get hidden behind the main form when the main form is set to “stay on top”. In most cases saying
modalForm.PopupParent := self;
just before the call to modalForm.ShowModal seems to help. But not always.
2) All my modal forms are simple, no frills, positioned at MainFormCenter, not using form inheritance, etc. And yet the PopupParent fix only works for about half of them, while the other half still get hidden behind the main form. Strangest of all, in one case the ordering of unrelated lines of code breaks or makes it. See lines marked (1) and (2) in this code:
procedure TEchoMainForm.DBMaintenancePrompt( actions : TMaintenanceActions );
var
frm : TDBMaintenanceForm;
begin
frm := TDBMaintenanceForm.Create( self );
try
frm.Actions := actions; // (1)
frm.PopupParent := self; // (2)
frm.ShowModal;
finally
frm.Free;
end;
end;
When executed in this order, the modal form shows correctly on top of the main form. But when I reverse the lines, the modal form hides behind main. The line marked (1) sets a property of the modal form, which results in several checkboxes being checked on unchecked in a TRzCheckGroup, sitting on a TRzPageControl (from Raize components). This is the setter method that runs when line (1) above executes:
procedure TDBMaintenanceForm.SetActions(const Value: TMaintenanceActions);
var
ma : TMaintenanceAction;
begin
for ma := low( ma ) to high( ma ) do
cgMaintActions.ItemChecked[ ord( ma )] := ( ma in Value );
end;
end;
This is enough for the modal form to show behind the main form if the order of the lines (1) and (2) is reversed.
This might point to TRzCheckGroup (which gets manipulated when the setter code runs), but I have two other forms that show the same problem and do not use TRzCheckGroup (or TRzPageControl). And I could not reproduce the problem with a separate sample app using Raize components. Disabling the form, the pagecontrol or the TRzCheckGroup for the duration of the setter has no effect.
It does not appear to be a timing issue, because when the modal form shows hidden once, it always does. The change in behavior only comes from rearranging the lines of code.
3) One last observation: my modal forms are fairly simple, so they get displayed pretty much instantly, with no visible delay. But when the main form is fsStayOnTop, then very often I can see the modal form show on top of it, then see it get “pushed” behind. Then, on hitting Esc, the (invisible) modal form shows on top of the main form for a fraction of a second, then gets closed.
Either I‘m missing something that’ll seem obvious in hindsight, or this is a call for psychic debugging, I don’t know. Any ideas, please?
UPDATE. I’ve tried to track down the problem on another form where it occurs. It has a few buttons (Raize) and a TSyntaxMemo (an enhanced memo component from eControl.ru). This form has almost nothing in common with the other forms that experience the problem. After removing parts of the code and testing, I can now reproduce the problem by making a tiny change in a method that assigns a string to the memo component:
This is my original code, which causes the form containing the editor to hide behind the main form:
procedure TEditorForm.SetAsText(const Value: string);
begin
Editor.Text := Value;
end;
When I change the assignment to an empty string, the form displays correctly:
procedure TEditorForm.SetAsText(const Value: string);
begin
Editor.Text := ''; // CRAZY! Problem goes away
end;
When I assign a single character to the editor, the form starts hiding again:
procedure TEditorForm.SetAsText(const Value: string);
begin
Editor.Text := 'a'; // Problem is back
end;
Of course the other two problematic forms do not use this editor component or any of its units.
I've tried deleting the memo control and adding it again (think creation order etc.), but it had no effect. Same if I create the memo in code. The form hides as soon as a non-empty string is assigned to the memo's Text property.
I had the same issue some time ago. My solution was to add a Self.BringToFront; to the OnShow event of the modal form.
Windows does not support many top most forms for app. And modal form is topmost by default. But you have this style for your own form.
One decision in mind: remove top most of your main form (no visible effect), call modal form, set back topmost style when modal finished.
Is it possible to show a modeless "wsNormal" WindowsState form behind a MDIChild form? I want to create a NOTE form which is always behind other forms (but always in front of the MDI form), unless you bring it to the front. E.g when you click on it.
That's technically impossible for window that is not an child of the MDI container.
The MDI children are child windows of the MDI container which is a child of the main form. If a window is in front of the main form, then it is in front of the MDI children. If it is behind the main form, then it is behind the MDI children.
Normally no, MDI parent is the root parent of MDI childs, you're either below the MDI parent or above. But you can set the parent of your top-level form to be the MDICLIENT.
I wouldn't suggest this approach as it possibly would have complications (maybe(?) you can achieve the same effect by tweaking some other MDI client class). But if you want to try what it would look like create a new "MDI Application" project and change the code that runs from the Help->About menu item to:
procedure TMainForm.HelpAbout1Execute(Sender: TObject);
begin
// AboutBox.ShowModal;
windows.SetParent(AboutBox.Handle, ClientHandle);
AboutBox.Show;
SetWindowPos(AboutBox.Handle, HWND_BOTTOM, 0, 0, 0, 0,
SWP_NOSIZE or SWP_NOMOVE);
end;
I struggle to show a second form above the main form without losing focus.
I have tried ShowWindow(second.handle, SW_SHOWNOACTIVATE), but the mainform loses focus.
If I set Visible := false on the second window, the call to ShowWindow does not activate the second form, but the windows is empty when shown...
Does anyone have a good recipe for this?
UPDATE: What I'm trying to do, is showing a notify-window at a given event. It's crucial that the main form does not lose focus at any time.
There has to be something wrong with your code.
I tested this code, it works:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowWindow(Form2.Handle, SW_SHOWNOACTIVATE);
Form2.Visible := True;
end;
Be careful to use Visible, not Show ! Otherwise it'll override the SW_SHOWNOACTIVATE.
You can show the window (non modal) and reset the focus to the mainwindow.
procedure TMainForm.ButtonClick(Sender: TObject);
begin
OtherForm.Show;
SetFocus;
end;
Tested on 2006.
This does not show the other form on top. But it is very counter intuitive to have a window on top that does not have the focus.
I've used this in the past
SetWindowPos(WindowHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOMOVE);
I've not tested this with recent versions of Delphi though...
If possible, you should considered using some sort of tool tip window to display the notification information. A tool tip will not steal focus from you main window when it is displayed or when a user clicks on it. A regular form will have a border by default and if the user clicks on that border your main form will loose focus.
Here is some basic code to do this. The tip disappears when free is called; however you would be better off setting a timer than using sleep.
with THintWindow.Create(nil) do
try
ActivateHint(MyRect, 'My Notification');
Sleep(DisplayTime);
finally
Free;
end
Here you are:
// you have set your 2nd form as non resizable, without border nor title etc...
Form2.Enabled := False; // prevent the 2nd form to grab focus even when clicked
SetWindowPos(Form2.Handle, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW or SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOMOVE);
// be sure to hide it automatically when done as it is disabled...
I did this in the past, but I don't have the code because it was propietary in last job (sorry).
If I remember well, what I did was:
From client class A call a procedure (or function) that doesn't belongs to any class (a traditional Pascal method).
From that method, call some method in a class B that doesn't inherit from TForm
From the method in B, create an instance of popup form P, but with no parent or owner; and call a method in the instance.
From the method called in the instance, show itself.
The code (of step 3) could go something like this:
var p: TPopupForm;
begin
p := TPopupForm.Create(nil);
p.ShowWindow;
p.Release;
end;
I'm sorry if this doesn't work, I don't have Delphi too.
Daniels code works until ...
ShowWindow(Form2.Handle, SW_SHOWNOACTIVATE);
Form2.Visible := True;
Until your second form is created dynamically. Then your second form is located at position 0,0 with default width and height.
For a short moment when ShowWindow is executed you will see the second form on screen, disappearing when the next line is executed.
I am using the code for a transparent overlay form which is created dyamically. The following code is a combination of the given answers and places the second form without activation over the parent form.
SetWindowPos(Form2.Handle, HWND_TOP, Left, Top, Width, Height, SWP_NOACTIVATE);
Form2.Visible := True;
How can I create a Sidebar form in delphi.
I try the ScreenSnap and Align properties but I need that the form stay visible even if the user maximize other forms, without been on top. Just like the windows sidebar do.
Update: From the comments: if a window is maximized, it maximizes next to the window, not in front of or behind.
What you're looking for is called an AppBar. Begin your research with the ShAppBarMessage API function.
You can call a Windows API function to force your application to stay on top:
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);