Why SendToBack is not working with Delphi XE4 - delphi

I'm using Delphi XE4 and trying to create 2nd form and set it as a background while the first form is transparent (AlphaBlend = true; AlphaBlendValue = 220)
uses Unit2;
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2.Show;
Form2.SendToBack;
end;
The codes above are working with Delphi 7, but not with Delphi XE4 (Form2 still over on the Form1). Can anyone tell me why the codes are not working with XE4? And how to make it working?
Thanks in advance.

Check the setting of Form2's PopupMode property. It is likely set in a way that cause's Form1's window to become the parent of Form2's window, which would prevent Form2 from moving behind Form1. The PopupMode (and PopupParent) property did not exist in D7, it was introduced in a later version to address z-order bugs that the VCL suffered from in earlier versions.
Read the following blob article for more details:
PopupMode and PopupParent

Related

Delphi 11 Alexandria PaintBox flicker in RDP

I've just upgraded to Delphi 11 Alexandria from Delphi 10.4.2. I use RDP a lot so I noticed flicker when a TPaintBox is invalidated. The weird thing is that it doesn't flicker if the form with the TPaintBox is the first one created. Also it doesn't flicker if run on local machine. Only in RDP. If I compile same project in Delphi 10.4.2 it doesn't flicker in RDP.
Can anyone figure this one out? Is it "simply" a bug in Delphi 11?
Edit: Demoproject http://procurisupdate.se/downloads/Temp/PaintBoxFlicker.zip
Simple project with two forms. One has an TImage so it is quite large.
If run as is, when you click the picture and move the mouse it flickers. If you change so that Form23 is created first (or even if it is created before Application.run) it doesn't flicker. Note it onlyt flickers in RDP.
Edit2: After some looking I find the following in TApplication.Run:
procedure TApplication.Run;
begin
FRunning := True;
try
{$IF NOT DEFINED(CLR)}
AddExitProc(DoneApplication);
{$ENDIF}
RemoteSessionCheck; // This has been added since Delphi 10.4.2
if FMainForm <> nil then
...
If I comment out RemoteSessionCheck; and recompile (you have to add Your Source\vcl dir to Library path) it works with no flicker.
Per a private communication with Embarcadero:
fyi: This issue seems related to:
TRemoteSessionChangedEvent = procedure (Sender: TObject; var InRemoteSession) of object;
which should have been:
TRemoteSessionChangedEvent = procedure (Sender: TObject; var InRemoteSession: Boolean) of object;
Our Support team tracked down the issue; explained why it does not affect auto-created forms, and how this will mess up C++ (where the untyped parameter will be exposed as Variant).
A bug ticket was filed, but it is private to their internal system only.
You can check the TApplication.SingleBufferingInRemoteSessions property and set it to False.

How to set FireMonkey form icon runtime in Delphi 10.2

I'm creating an application for Windows and OS X using Firemonkey Framework with Delphi 10.2 Tokyo and can't set application or form icon dynamically.
In VCL project I've used following code:
Form1.Icon.LoadFromFile()
or
Application.Icon.LoadFromFile()
But there are no such properties or methods in FMX. Is there any way to set project icon otherwise than in Project -> Options menu?
Add to your uses list {$IFDEF WIN32}WinApi.Windows,FMX.Platform.Win,{$ENDIF}
procedure setFormIcon(Form: TForm; FileName: String);
var Icon : NativeUInt;
begin
{$IFDEF WIN32}
ICON := LoadImage(0,PWideChar(Filename),IMAGE_ICON,0,0,LR_LOADFROMFILE OR LR_DEFAULTSIZE OR LR_SHARED);
SetClassLong(FmxHandleToHWND(Form.Handle), GCL_HICON, icon);
{$ENDIF}
end;
procedure TForm1.btn1Click(Sender: TObject);
begin
setFormIcon(Form1,'my icon path.ico');
end;
In the 10.2 Rio sources, I see that the function TPlatformWin.CreateWindow, which is used to create a window in the Windows, have only this line to provide a window's icon:
WindowClass.hIcon := LoadIconW(MainInstance, PChar('MAINICON'));
And function TPlatformWin.CreateAppHandle have an absolutely same code! So, we have not a direct way to set app or form icon through FireMonkey components.
At Windows You still can use WinAPI message WM_SETICON (SendMessage(Handle, WM_SETICON, ICON_BIG, MyIconHandle);), but I have not tried that and do not know any troubles in this way.
Also in Windows we may use TTaskbarBase and TPreviewClipRegion classes to the more precise and functional way of TaskBar interactions.
P.S. I do not know, what we have for same requirements at OS X.

Delphi MainFormOnTaskBar Modal windows bug

HI
I'm using Delphi 2007 and have set the MainFormOnTaskBar property to true.
The issue that I'm having is this.
If you open a child window from the main form and then you show a message dialog from the child window you just opened. When you close the message dialog and then close the child window, the main form will be sent to the back of any other application you have on the screen.
This happens under windows Vista and Windows 7. Does anyone know why this is happens and how can I fix it?
I guess that would be QC66892-Closing forms deactivates the application, which appears to have been fixed with Delphi 2009 according to the report. At the bottom of the QC report you'll find a comment by Andreas Hausladen including a link to his fix of the bug. But you'd really want to utilize his VCL Fix Pack which includes many other fixes as well.
I've fixed this in two ways.
Firstly by adding stdcall to the end of DoFindWindow in Forms.pas as described by Andreas Hausladen. This handles when a child form is hidden (CloseAction = caHide) instead of released when closing the form.
Secondly - copied the code from TCustomForm.CMShowingChanged that calls FindTopMostWindow and then activates the window that was returned into TCustomForm.CMRelease.
(Edit: code block needs to be indented by 4 spaces)
procedure TCustomForm.CMRelease;
var
NewActiveWindow: LongInt;
begin
if Application.MainFormOnTaskbar then
begin
NewActiveWindow := 0;
if (GetActiveWindow = Handle) and not IsIconic(Handle) then
begin
NewActiveWindow := FindTopMostWindow(Handle);
end;
if NewActiveWindow <> 0 then
begin
SetActiveWindow(NewActiveWindow);
end;
end;
Free;
end;
This seems to have done it, I'll continue testing to make sure.
The PopupMode and PopupParent properties were added specifically to TForm to address this issue. Before showing the child form, set it's PopupParent to the main form, and it's PopupMode to pmAuto.
PopupParent specifically affects the Z-order of windows when other windows are shown.
The Delphi 2007 help has some documentation on these two properties, but you have to go through TForm to get to them. Use 'TForm,Pop' as your search topic (w/o the quotes, obviously ) to get there. The docs are a little confusing about PopupParent, because it discusses the effect that PopupMode has on the automatic assignment of PopupParent. A little experimentation after reading the docs should pay off, though.

Form is hidden behind other forms when ShowModal is called

My application is based on modal forms. Main form opens one form with ShowModal, this form opens another with ShowModal, so we have stacked modal forms. There is sometimes a problem that when we call ShowModal in new form, it hides behind previous forms, instead of showing on top. After pressing alt+tab, form comes back to the top, but this is not good solution. Did You meet this problem and how did you handle it?
EDIT:
I use Delphi 7.
You didn't mention which version of Delphi...
Newer Delphi versions have added two new properties to TCustomForm: PopupMode and PopupParent. Setting PopupParent of your modal dialog to the form that's creating that dialog makes sure that the child form stays on top of it's parent. It usually fixes the problem you're describing.
I think this pair of properties were added in Delphi 2006, but it may have been 2005. They're definitely there in Delphi 2007 and up.
EDIT: After seeing you're using Delphi 7, the only suggestion I have is that, in the code that displays your modal form, you disable the form creating it, and re-enable on return. That should prevent the creating window from receiving input, which may help keep the Z-order correct.
Something like this may work (untested, as I'm no longer using D7):
procedure TForm1.ShowForm2;
begin
Self.Enabled := False;
try
with TForm2.Create(nil) do
begin
try
if ShowModal = mrOk then
// Returned OK. Do something;
finally
Free;
end;
end;
finally
Self.Enabled := True;
end;
end;
If Form2 creates a modal window (as you've mentioned), just repeat the process - disable Form2, create Form3 and show it modally, and re-enable Form2 when it returns. Make sure to use try..finally as I've shown, so that if something goes wrong in the modal form the creating form is always re-enabled.
Sorry for adding a separate answer, but I have done a bit more research, and some of it indicates that my previous answer (DisableProcessWindowsGhosting) doesn't help. Since I can't always reproduce this issue, I cannot say for sure.
I found a solution that appears to appropriate. I referenced the code in Delphi 2007 for the CreateParams method and it matches pretty close (without having all of the other code that handles PopupMode).
I created the unit below which subclasses TForm.
unit uModalForms;
interface
uses Forms, Controls, Windows;
type
TModalForm = class(TForm)
protected
procedure CreateParams(var params: TCreateParams); override;
end;
implementation
procedure TModalForm.CreateParams(var params: TCreateParams);
begin
inherited;
params.WndParent := Screen.ActiveForm.Handle;
if (params.WndParent <> 0) and (IsIconic(params.WndParent)
or not IsWindowVisible(params.WndParent)
or not IsWindowEnabled(params.WndParent)) then
params.WndParent := 0;
if params.WndParent = 0 then
params.WndParent := Application.Handle;
end;
What I do then is include this unit in with a form unit, and then change the form's class (in the .pas code file) from class(TForm) to class(TModalForm)
It works for me, appears to be close to CodeGear's solution.
From this link it appears that the problem is with the "Ghosting window" that was introduced in 2000/XP. You can disable the ghosting feature by calling the following code at startup.
procedure DisableProcessWindowsGhosting;
var
DisableProcessWindowsGhostingProc: procedure;
begin
DisableProcessWindowsGhostingProc := GetProcAddress(
GetModuleHandle('user32.dll'),
'DisableProcessWindowsGhosting');
if Assigned(DisableProcessWindowsGhostingProc) then
DisableProcessWindowsGhostingProc;
end;
The only issue that I can see is that it will cause problems with the feature that allows for the user to minimize, move, or close the main window of an application that is not responding. But in this way you do not have to cover each call with the Self.Enabled := False code.
Just set the Visible property of the form, that you want to open modal, to False. Then you can open it with .ShowModal(); and it will work.
I have found that using the "Always On Top" flag on more than one form causes problems with the Z order. And you may also find the need for the BringWindowToTop function.
When launching a message box using the built-in WinAPI (MessageBox), I have found that passing the calling window's handle is necessary in order to make sure that the the prompt appears on top all the time.
try it
OnShowForm:
PostMessage(Self.Handle, WM_USER_SET_FOCUS_AT_START, 0, 0);

Why Treeview.Clear fails on parent form borderstyle change?

I have 2 forms. Form1 with one panel and 2 buttons (pnl1, btnShowTree and btnAddItems). There is also Form2 which contains Treeview (tv1).
Please see short code below to understand this little demonstration:
procedure TForm1.btnShowTreeClick(Sender: TObject);
begin
with Form2 do
begin
tv1.Items.clear;
Tv1.Items.AddChild(nil, '1.' );
Tv1.Items.AddChild(nil, '2.' );
Tv1.Items.AddChild(nil, '3.' );
Form2.Parent:=pnl1;
Form2.BorderStyle:=bsNone;
Form2.show;
end;
end;
procedure TForm1.btnAddItemsClick(Sender: TObject);
begin
with Form2 do
begin
BorderStyle:=bsSizeable; // here it works wrong
tv1.Items.clear;
Tv1.Items.AddChild(nil, 'A.' );
Tv1.Items.AddChild(nil, 'B.' );
Tv1.Items.AddChild(nil, 'C.' );
// BorderStyle:=bsSizeable; here it works fine. WHY ?????
Form2.Show;
end;
end;
procedure TForm2.btnCloseForm2Click(Sender: TObject);
begin
Parent:=nil;
Hide;
// when I exchange instructions order like:
// Hide;
// Parent:=nil;
// I get the same problem with improperly nested BorderStyle:=bsSizeable; I have
// only blur idea why it is so...
end;
I expected, that when I click on btnAddItems I will see 3 items (A. B. C.). But it will show 6 items, because the previous ones are not deleted !!! can anybody thow a light on it, 'cause I stucked here for hours to make program work well, but I still have not the thiniest idea what I do wrong...
Changing the BorderStyle at runtime means that the window has to be destroyed and recreated. This means that the VCL has to store the content of whatever controls are on the form (like your TTreeView), destroy the form, create the form with the new BorderStyle, recreate all the controls on the form, and then restore all the content.
You're probably using an older version of Delphi (see note below) that doesn't properly remove the stored content from memory. #M Schenkel is using a later version that does.
The solution, of course, is to stop changing the BorderStyle at runtime, which will stop causing the form to be destroyed and recreated. :-) I've been programming with Delphi starting with version 1 and continuing through the current Delphi 2010, and in all that time I have never once had a need to change BorderStyle at runtime.
NOTE: When posting a Delphi question, you should always indicate what version of Delphi you're using. Differences in Delphi version means differences in the VCL, and a problem can be caused by different things in those different versions. Knowing what version of Delphi you're using makes solving your problem or answering your question easier.

Resources