Delphi - Disable [x] Close Button in VCL Styles - delphi

I'd like disable [X] close Button with VCL Style in DX Berlin.
Wy this code do not work wiht VCL Style?
EnableMenuItem(GetSystemMenu(Form3.Handle, LongBool(False)),SC_CLOSE, MF_BYCOMMAND or MF_GRAYED);

If you set the action in the FormClose event to caNone, when you try to close the form (clicking on the red cross) nothing is going to happen. In this way you can disable the button.
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//You cannot type only caNone, otherwise you'll get a compiler error
Action := TCloseAction.caNone;
end;
You can find caNone in System.UITypes; read the documentation for more information.

When using VCL Styles by default style affect the appearance of fonts being used, client area of your form and also your forms border (this also include minimize, maximize and close buttons).
So from what I see you have two options:
You could change StyleElements property of your form to [seFont, seClient] which means that style will only be applied to used fonts and client area of your form but the border area of your form would be unstyled and rendered by OS.
You modify the style at runtime in order to achieve desired effect. Unfortunately I don't have enough experience with Styles to present you with an example of how to achieve this.

Related

Delphi VCL styles problem with TListview EditCaption and HideSelection

I'm using Delphi 10.3 in a VCL app with a Dark VCL style (default Windows10 Dark for example).
I have two problems with VCL styling in TListview
When editing an item in TListview, the listview's edit is not styled: it has a white background with black text. It there any way to apply the VCL style to that edit although it not a VCL control?
Also, with HideSelection = False and the listview not having focus, the selected item's background color is the default light gray color instead of a much darker color that would better fit in the VCL style. Is there any way to modify that other than custom drawing?
I checked this with several dark VCL styles, they all have these problems with TListView (and TTreeview too).
I was able to fix the listview's edit background and text color by overriding message handler WM_CTLCOLOREDIT in a TListView descendant (TListViewEx in my case) like below. If you check the VCL source for TCustomListView.WMCtlColorEdit you'll see this fix does not cover the case glassPaint case correct - but I'm not using that. It seems to me this is actually a VCL bug and the below code should have been included in TCustomListView.WMCtlColorEdit.
Note: the same type of fix also works for TTreeview (using a TTreeview descendant obviously)
I have not found a workaround for the unfocused selection color yet.
procedure TListViewEx.WMCtlColorEdit(var Message: TMessage);
var
DC: HDC;
begin
if StyleServices.IsSystemStyle then
inherited
else
begin
DC := Message.WParam;
SetTextColor(DC, StyleServices.GetSystemColor(clWindowText));
SetBkColor(DC, StyleServices.GetSystemColor(clWindow));
Message.Result := 1;
end;
end;

FMX: How can I get a forms mousemove events outside of the form

I have a form which I'm painting on (OnPaint). I give the user grips to click on and change the shape. However, I would like to allow the user to move past the edge of the form. How can I get the mouse moments when the mouse goes past the edge. I know this can be done because it works on a TrackBar. And while that is a Component and not a Form, I assume I can change the forms style or register something to make it act in a similar manor.
I plan on making the form background transparent so ideally, the same solution would allow me to get mousemoves over the transparent areas.
FMX uses the AutoCapture property for that. Then the mouse will be captured while the mouse button is down.
constructor TMyGrip.Create(AOwner: TComponent);
begin
inherited;
AutoCapture := True;
CanFocus := True;
end;
This does not work for a form. But you could add a TLayout on the form that fills the entire client.
FMX internally uses FWinService.SetCapture(Self); and FWinService.ReleaseCapture(Self); for this, and this accepts a form. I haven't tested this, but it could happen that you'll confuse the FMX framework quite a bit if you call the internal functions like that.

How to cope with the bug with style lookup in controls nested in FMX Frames

I have met a bug in applying of StyleLookup in TTabControl nested in FMX Frame. The appearance of the control does not accept the style if the frame with the control is nested in a HorzScrollBox and at form creation the position of the frame is outside the visible area of the form. In other words if the control is visible when the form is shown the control is painted with necessary style appearance otherwise - not.
To reproduce the bug:
Create a new grid metropolis application.
Create a Frame and put a TTabControl on it. Set Align of the TabControl to alClient. Add, say, 4 TTabItems.
Open detail form, and set its width to a value > your Screen.Width (for me 2500 was enough).
Copy-paste any of the Columns (Layouts), say, 2 times and use the most right layout to nest a frame in it. You will see normal presentation of tabitems at designtime. Set style settings. You will get the following picture:
Done. Run the project. You will get the bug.
At runtime the appearance of TabItem is like this:
If you set the StyleLookup manually at runtime the appearance might either not change either be set to every other item (for example 1st, 3rd and not set to 2nd and 4th though you assign the same StyleLookup to all TabItems). The other interesting finding. If you have other forms containing TabControls with TabItems (nested without frames and closer to left border of the form) for example Form2, you get the following. If you show the faulty Form1 at runtime first you will see the bug, but if you close this form and show Form2 you see proper TabControl. Closing Form2 and showing Form1 (faulty) afterwards will give you a proper appearance of TabControl in a faulty form.
It has something in common with the bug reported by me earlier: Incorrect selection of items in an FMX TListbox (Grid Metropolis UI). It is still not fully solved.
There was also a question yesterday but it is about an exact problem with VCL Frames and the solution is not suitable for FMX.
Appended.
The way is to partially set the style is to set OnPainting event handler for TTabControl in the parent form unit (it does not work being set in frame unit) and write something like this:
procedure TPatientsScrollF.HMDiagnosisFr1TabControl2Painting(Sender: TObject;
Canvas: TCanvas; const ARect: TRectF);
var
i: byte;
begin
(Sender as TTabControl).StyleLookup := 'tabcontrolstyle';
for i := 0 to (Sender as TTabControl).TabCount-1 do
(Sender as TTabControl).Tabs[i].StyleLookup := 'tabitemstyle';
end;
But than you still get a problem - the Tabs are not drawn properly - see the lower edge of inactive Tabs.
Or even like this:
Appended 2
I have just met the bug appearing even at design-time after placing a frame in a form and assigning style to TabItems. The TabControl looks like in fig. 3.

Is it possible to drag a TPanel to outside the TForm?

I'm wondering if it's possible to make something like this:
but without creating a second TForm.
I'm using Delphi 7, but if a newer version make it possible just tell me.
I've always thought the DockEx demo was over-complicated for learning the basics of docking.
The following is the simplest example I know of:
Add a TPanel to a blank form and set its DragKind property to dkDock, DragMode to dmAutomatic and its Align property to alTop.
Drop a TButton on the TPanel
Add the code below to the form:
Run the project and manually drag the panel off the form.
Click Button1.
The above shows how Delphi can undock a Panel (or TEdit, etc) without you
needing to create a second form to host it while undocked, like Remy said in a comment. The Button1 click-handler shows a way (admittedly imperfect) of re-docking the panel. Next:
Undock the panel again, but this time, click the Close button on its auto-created host.
Then, read the OLH and figure out a) how to get the now-hidden panel visible again and b) to re-position & re-align it on the form as it was prior to undocking,
type
TMyClass = TControl;
procedure TForm1.Button1Click(Sender: TObject);
begin
TMyClass(Panel1).ManualDock(Self, Nil, alNone);
end;

Draw an image instead of window caption

I need to do something which seems to be easy, but I'm searching for days with no success.
I have a window of fixed size (say 500*250) and need to replace the whole caption bar with a fixed size JPEG (or better PNG) image (say 500*25).
There are lots of samples talking about Glass, Aero, DWM, blah blah blah. But I just need to draw a fixed image!
I've already tried this, but it doesn't work:
procedure TForm1.Button1Click(Sender: TObject);
var
bmp:TBitmap;
DC:HDC;
begin
DC:=GetWindowDC(form1.Handle);
bmp:=tbitmap.Create;
bmp.SetSize(500, 25);
bmp.Canvas.TextOut(5,5,'Helloooooooooooooooooo');
BitBlt(dc,0,0,500,25,bmp.Canvas.Handle,0,0,SRCCOPY);
bmp.Free;
ReleaseDC(form1.Handle,DC);
end;
It should work both on XP and Vista/7. Please help.
P.S: I have Delphi XE.
You can do so by using VCL Styles.
You can change the appearance of the Windows caption bar like that by using the Delphi integrated Bitmap style designer to change a custom style and then use that Style in your application.
If you don't want to enforce the style to the whole application you can set the StyleElements property of the form to only include seBorder, this means that only the border aka caption of your application will be rendered using your custom style.
If you're working in Delphi XE2 then you won't be able to use the StyleElements property but that is just a minor obstacle, it just means that you will have to resort to using StyleHooks to implement the same behaviour and there is enough documentation on how to do that here.
Sadly, if your Delphi version is older then XE2 then you won't be able to use VCL Styles.
Another but rather unpleasant way would be to create a borderless form by changing the BorderStyle property to bsNone and then implementing your image in a way that it would act as a title bar, processing all actions made on the image and sending appropriate Messages to the application.
You can either:
Intercept the WM_NCPAINT message and custom-draw the caption bar manually.
Remove the caption bar altogether, by using SetWindowRgn() or overriding the CreateParams() method to remove the WS_CAPTION style, and then use the form's OnPaint event, or even a TImage, to display the graphic at the top of the form's remaining client area.
The simplest solution would be to use CreateParams() and TImage.

Resources