How can i use TRect in delphi to paint with a angle? - delphi

I want to paint something similar to the image? How can I rotate the TRect, to paint with a specific angle?

You need to specify the coordinates of the quadrilateral manually:
procedure TForm1.FormPaint(Sender: TObject);
var
W10,
H10,
Delta: Integer;
begin
W10 := ClientWidth div 10;
H10 := ClientHeight div 10;
Delta := W10;
Canvas.Brush.Color := clWhite;
Canvas.FillRect(ClientRect);
Canvas.Pen.Color := clBlack;
Canvas.Pen.Width := 8;
Canvas.Polygon(
[
Point(W10, H10),
Point(W10, ClientHeight - H10),
Point(ClientWidth - W10, ClientHeight - H10),
Point(ClientWidth - W10, H10)
]
);
Canvas.Brush.Color := $E8A200;
Canvas.Polygon(
[
Point(W10, H10),
Point(W10, ClientHeight - H10),
Point(ClientWidth div 2 - Delta, ClientHeight - H10),
Point(ClientWidth div 2 + Delta, H10)
]
);
end;
procedure TForm1.FormResize(Sender: TObject);
begin
Invalidate;
end;
produces the following output:

To rotate your drawing, you can use a Direct2D canvas and set the transformation as a rotation (You can translate, rotate, scale, skew, and combine several of them).
Example:
In your form, add the following:
private
FD2DCanvas : TDirect2DCanvas;
function CreateD2DCanvas: Boolean;
protected
procedure CreateWnd; override;
Then implement CreateD2DCanvas() and CreateWnd():
function TForm1.CreateD2DCanvas: Boolean;
begin
try
FD2DCanvas.Free;
FD2DCanvas := TDirect2DCanvas.Create(Handle);
Result := TRUE;
except
Result := FALSE;
end;
end;
procedure TForm1.CreateWnd;
begin
inherited;
CreateD2DCanvas;
end;
You must also provide a OnResize event handler like this:
procedure TForm1.FormResize(Sender: TObject);
begin
// When the windows is resized, we needs to recreate RenderTarget
CreateD2DCanvas;
Invalidate;
end;
And finally provide a OnPaint event handler like this:
procedure TForm1.FormPaint(Sender: TObject);
var
Rect1 : D2D1_RECT_F;
begin
FD2DCanvas.BeginDraw;
try
FD2DCanvas.Brush.Color := clRed;
FD2DCanvas.RenderTarget.SetTransform(TD2DMatrix3x2F.Identity);
Rect1 := Rect(50, 70, 80, 100);
FD2DCanvas.FillRectangle(Rect1);
FD2DCanvas.RenderTarget.SetTransform(TD2DMatrix3x2F.Rotation(30.0, Rect1.Left, Rect1.Top));
FD2DCanvas.Brush.Color := clYellow;
FD2DCanvas.FillRectangle(Rect1);
finally
FD2DCanvas.EndDraw;
end;
end;
Don't forget to add Winapi.D2D1 and Vcl.Direct2D in the uses clause.
The simple example above draw two rectangles (Actually squares), the first not rotated, the second rotated 30 degrees. Of course you can make as many transformations as you like. To combine transformations, you have to multiply them. Warning: this is not commutative: a translation followed by a rotation is not the same as the same rotation followed by the same rotation!
Edit: I wrote a blog post about this topic: https://francois-piette.blogspot.com/2020/08/direct2d-canvas-for-delphi-forms.html

Related

How draw a shadow effect in a complete Bitmap image?

I want know if is possible draw a shadow effect in a complete Bitmap image already existent and after have a effect similar to this example below, where all area behind modal Form is my new Bitmap image already with the shadow effect? =>
This is pretty easy. First we need a routine that fades a given bitmap:
procedure FadeBitmap(ABitmap: TBitmap);
type
PRGBTripleArray = ^TRGBTripleArray;
TRGBTripleArray = array[word] of TRGBTriple;
var
SL: PRGBTripleArray;
y: Integer;
x: Integer;
begin
ABitmap.PixelFormat := pf24bit;
for y := 0 to ABitmap.Height - 1 do
begin
SL := ABitmap.ScanLine[y];
for x := 0 to ABitmap.Width - 1 do
with SL[x] do
begin
rgbtRed := rgbtRed div 2;
rgbtGreen := rgbtGreen div 2;
rgbtBlue := rgbtBlue div 2;
end;
end;
end;
Then, when we want to display our modal message, we create a bitmap 'screenshot' of our current form, fade it, and place it on top of all controls of the form:
procedure TForm1.ButtonClick(Sender: TObject);
var
bm: TBitmap;
pn: TPanel;
img: TImage;
begin
bm := GetFormImage;
try
FadeBitmap(bm);
pn := TPanel.Create(nil);
try
img := TImage.Create(nil);
try
img.Parent := pn;
pn.BoundsRect := ClientRect;
pn.BevelOuter := bvNone;
img.Align := alClient;
img.Picture.Bitmap.Assign(bm);
pn.Parent := Self;
ShowMessage('Hello, Faded Background!');
finally
img.Free;
end;
finally
pn.Free;
end;
finally
bm.Free;
end;
end;
Hint: If you have more than one modal dialog to display in your application, you probably want to refactor this. To this end, have a look at TApplicationEvent's OnModalBegin and OnModalEnd events.

Creating a transparent custom bitmap brush

Problem Definition
I am trying to create a custom bitmap brush with transparency but it doesn't seem to be working as expected. If you look at this example. Add the code and hook up the paint, create and destroy events.
type
TForm3 = class(TForm)
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
private
FBitmap: TBitmap;
end;
// Implementation
function CreateBlockBitmap(const APenColor: TColor): TBitmap;
begin
Result := TBitmap.Create;
Result.Transparent := True;
Result.Canvas.Brush.Color := clWhite;
Result.Canvas.Brush.Style := bsClear;
Result.PixelFormat := pf32bit;
Result.SetSize(20, 20);
Result.Canvas.Brush.Color := APenColor;
Result.Canvas.Brush.Style := bsSolid;
Result.Canvas.FillRect(Rect(0,0,10,10));
end;
procedure TForm3.FormDestroy(Sender: TObject);
begin
FBitmap.Free;
end;
procedure TForm3.FormCreate(Sender: TObject);
begin
FBitmap := CreateBlockBitmap(clRed);
end;
procedure TForm3.FormPaint(Sender: TObject);
var
colNum: Integer;
rowNum: Integer;
begin
// Paint the rectangle using the brush
Canvas.Pen.Color := clGreen;
Canvas.Brush.Bitmap := FBitmap; // This is using bitmap
Canvas.Rectangle(50, 50, 250, 250);
// Draw the block using Canvas.Draw
for rowNum := 0 to 9 do
for colNum := 0 to 9 do
Canvas.Draw(350 + rowNum * 20, 50 + colNum * 20, FBitmap);
end;
This code produces two painted blocks. The left one is painted using a bitmap brush and the right hand side one is painted using a number of Canvas.Draw calls.
I need the brush to be painted with transparency similar to what would happen if you used a hatch brush. This SO answer seems to indicate that it's possible:
How can I draw a patternBrush with transparent backround (GDI)?
What I have tried
1) I tried using a solid background color instead of using bsClear. This just makes the background white.
Result.Canvas.Brush.Color := clWhite;
Result.Canvas.Brush.Style := bsSolid;
If I use clFuchsia then the color is Fuchsia. I also tried painting the background clFuchsia and then setting the TransparentColor to clFuchsia. The Canvas.Draw option paints with transparency and the brush doesn't.
2) I tried setting the alpha channel directly with the following code:
procedure SetAlphaBitmap(const Dest: TBitmap;Color : TColor;Alpha:Byte);
type
TRGB32 = record
B, G, R, A: byte;
end;
PRGBArray32 = ^TRGBArray32;
TRGBArray32 = array[0..0] of TRGB32;
var
x, y: integer;
Line, Delta: integer;
ColorRGB : TColor;
begin
if Dest.PixelFormat<>pf32bit then exit;
ColorRGB := ColorToRGB(Color);
Line := integer(Dest.ScanLine[0]);
Delta := integer(Dest.ScanLine[1]) - Line;
for y := 0 to Dest.Height - 1 do
begin
for x := 0 to Dest.Width - 1 do
if TColor(RGB(PRGBArray32(Line)[x].R, PRGBArray32(Line)[x].G, PRGBArray32(Line)[x].B)) = ColorRGB then
PRGBArray32(Line)[x].A := Alpha;
Inc(Line, Delta);
end;
end;
And then calling this routine immediately after the rectangle has been painted using the background color.
Result.Canvas.Brush.Style := bsSolid;
Result.Canvas.FillRect(Rect(0,0,10,10));
SetAlphaBitmap(Result, clBlack, 0); // Set the alpha channel
end;
I know that the alpha channel is working because if I pass in an alpha value of 255 then it shows up in black in the Canvas.Draw too.
SetAlphaBitmap(Result, clBlack, 255);
3) I tried testing by creating a pattern brush and assigning that instead of the bitmap. That produces exactly the same results. FBrush is an HBRUSH.
FBrush := CreatePatternBrush(FBitmap.Handle);
And the setting the brush like this:
Canvas.Brush.Handle := FBrush;
4) I tried calling SetBkMode as indicated in the SO answer above. That made no difference at all.
Canvas.Pen.Color := clGreen;
Canvas.Brush.Bitmap := FBitmap;
SetBkMode(Canvas.Handle, TRANSPARENT); // This doesn't make a difference
Canvas.Rectangle(50, 50, 250, 250);
Edit
5) I just tested with a Monochrome bitmap and it has the same problem. The image is painted with a white background and black foreground for the brush and transparent for the Canvas.Draw.
function CreateMonochromeBitmap: TBitmap;
begin
Result := TBitmap.Create;
Result.Transparent := True;
Result.Canvas.Brush.Color := clWhite;
Result.Canvas.Brush.Style := bsSolid;
Result.PixelFormat := pf1bit;
Result.SetSize(20, 20);
Result.Canvas.Brush.Color := clBlack;
Result.Canvas.Brush.Style := bsSolid;
Result.Canvas.FillRect(Rect(0,0,10,10));
end;
And in the constructor:
FBitmap := CreateMonochromeBitmap;
FBrush := CreatePatternBrush(FBitmap.Handle);
In the paint we set the handle rather than the bitmap property.
Canvas.Brush.Handle := FBrush;
Try to clear the canvas this null color before your drawing loop.
Canvas.Clear(TAlphaColorRec.Null);
Greetings.
Pau.
You need to use white color for transparent areas and SetROP2 before filling the rectangle, like this:
Canvas.Brush.Bitmap := FBitmap; // This is using bitmap
SetROP2(Canvas.Handle, R2_MASKPEN);
Canvas.Rectangle(50, 50, 250, 250);
And don't forget to restore the previous ROP mode.
Good luck!
Solved! Here is my solution:
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormPaint(Sender: TObject);
public
FBitmap: TBitmap;
end;
//Implementation
function CreateBlockBitmap: TBitmap;
begin
Result := TBitmap.Create;
Result.PixelFormat := pf1bit; //!! 1-bit
Result.Width := 20;
Result.Height := 20;
Result.Canvas.Brush.Color := clBlack;
Result.Canvas.FillRect(Rect(0, 0, 10, 10));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FBitmap := CreateBlockBitmap;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FBitmap.Free;
end;
procedure TForm1.FormPaint(Sender: TObject);
const
PatternColor = clRed; //brush color to be used
var
R: TRect;
begin
//filling the background with different colors for test
Canvas.Brush.Color := clGreen;
Canvas.FillRect(Rect(0,0,100,600));
Canvas.Brush.Color := clAqua;
Canvas.FillRect(Rect(100,0,200,600));
Canvas.Brush.Color := clYellow;
Canvas.FillRect(Rect(200,0,300,600));
Canvas.Brush.Color := clWhite;
Canvas.FillRect(Rect(300,0,400,600));
//draw the rectangle
R := Rect(50, 50, 500, 500);
Canvas.Brush.Color := PatternColor;
BitBlt(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom, Canvas.Handle, 0, 0, PATINVERT);
Canvas.Brush.Bitmap := FBitmap;
SetROP2(Canvas.Handle, R2_MASKPEN);
Canvas.Rectangle(R); //draw any figure here
Canvas.Brush.Color := PatternColor;
SetROP2(Canvas.Handle, R2_COPYPEN);
BitBlt(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom, Canvas.Handle, 0, 0, PATINVERT);
end;

Screenshot of Webbrowser

I have a TwebBrowser on a form, of which I need to take a Screenshot. Some may think Isn't this a dublicate. But it's not, because the solutions in the orter answers doesn't work, thay all just gives med a black screen.
Så I try to get my pixels from DC(0)
First some source code:
Place a TWebBrowser and a TButton on a form, and add the following code to a OnCreate Event:
procedure TForm1.FormCreate(Sender: TObject);
var
Doc: Variant;
begin
Width := 1350;
Height := 860;
with WebBrowser1 do
begin
Left := 0;
Top := 0;
Width := 1330;
Height := 760;
Anchors := [akLeft, akTop, akRight, akBottom];
end;
with Button1 do
begin
Left := 1048;
Top := 776;
Width := 58;
Height := 25;
Anchors := [akRight, akBottom];
Caption := 'GetDC';
OnClick := Button1Click;
end;
WebBrowser1.Navigate('about:blank');
Doc := WebBrowser1.Document;
Doc.Clear;
Doc.Write('<embed src="https://r1---sn-cgxqc55oqovgq-55ae.googlevideo.com/videoplayback?sver=3&requiressl=yes&itag=22&ratebypass=yes&pl=19' +
'&upn=PRgjNIjXqZo&ipbits=0&mm=31&id=o-AFwGYl-Gni-Xv-OpmDFDHPmsirrQ-tP9XPjRwG8B7XFk&initcwndbps=2765000&signature=772D32F7C20412D37B3F23A36D262D58A34BBEF8.9A9463362C4438781A05F634DDD97A590D6EF387'
+ '&ip=77.68.203.5&mv=m&mt=1428297827&ms=au&dur=274.692&key=yt5&mime=video%2Fmp4&source=youtube&sparams=dur%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Cmime%2Cmm%2Cms%2Cmv%2Cpl%2Cratebypass%2Crequiressl'
+ '%2Csource%2Cupn%2Cexpire&expire=1428319485&fexp=900234%2C900720%2C907263%2C917000%2C932627%2C934954%2C9406733%2C9407060%2C9408101%2C946800%2C947243%2C948124%2C948703%2C951703%2C952612%2C957201%2C961404%2C961406%2C966201" width="1280" height="720">');
Doc.Close;
end;
This gives you a WebControl playing a video. There is a reason for doing it like this, but thats out of scope for this question.
Then The Screenshot stuff:
procedure TForm1.Button1Click(Sender: TObject);
var
bitmap: TBitmap;
BrowserRect: TRect;
DC: HDC;
w, h: Integer;
pt: TPoint;
begin
bitmap := TBitmap.Create;
BrowserRect := WebBrowser1.ClientRect;
DC := GetDC(0);
bitmap.Height := WebBrowser1.Height;
bitmap.Width := WebBrowser1.Width;
BitBlt(bitmap.Canvas.Handle, BrowserRect.Left, BrowserRect.Top, WebBrowser1.Width, WebBrowser1.Height, DC, 0, 0, SrcCopy);
bitmap.SaveToFile('aa.bmp');
FreeAndNil(bitmap);
end;
I've tried a lot of stuff. But I cant get the calculation og the Webbrowser's bounds correct. Så I just posted this code.
Windows : Windows 8.1 64 bit
Delphi : Delphi Xe6
Exe : 64 bit
So in short:
Is there an other way of captureing a Screenshot of a TWebBrowser
or
How to calculate the abosolute boundaries of TWebBrowser
* UPDATE *
Based on the code I got from Dalija Prasnikar I wrote a procedure for captureing a WinControl
procedure PrintControl(AControl: TWinControl; var AOut: TBitmap);
var
DC: HDC;
pt: TPoint;
begin
if not Assigned(AControl) then
Exit;
if not Assigned(AOut) then
Exit;
DC := GetDC(0);
pt := AControl.ClientToScreen(AControl.BoundsRect.TopLeft);
try
AOut.Height := AControl.Height;
AOut.Width := AControl.Width;
BitBlt(AOut.Canvas.Handle, 0, 0, AControl.Width, AControl.Height, DC, pt.X, pt.Y, SRCCOPY);
finally
ReleaseDC(0, DC);
end;
end;
You have to use WebBrowser.BoundsRect and then convert its TopLeft point to screen coordinates to get correct origin of your WebBrowser control.
You have used BitBlt parameters incorrectly. Declaration is
function BitBlt(DestDC: HDC; X, Y, Width, Height: Integer; SrcDC: HDC;
XSrc, YSrc: Integer; Rop: DWORD): BOOL; stdcall;
X and Y are coordinates in destination HDC, not the source.
You also need to release captured DC after you are done with it, or you will be leaking Windows resources.
var
Bitmap: TBitmap;
BrowserRect: TRect;
DC: HDC;
W, h: integer;
pt: TPoint;
begin
Bitmap := TBitmap.Create;
try
BrowserRect := WebBrowser1.BoundsRect;
pt := ClientToScreen(BrowserRect.TopLeft);
DC := GetDC(0);
try
Bitmap.Height := WebBrowser1.Height;
Bitmap.Width := WebBrowser1.Width;
BitBlt(Bitmap.Canvas.Handle, 0, 0, WebBrowser1.Width, WebBrowser1.Height, DC, pt.X, pt.Y, SRCCOPY);
Bitmap.SaveToFile('c:\work\aa.bmp');
finally
ReleaseDC(0, DC);
end;
finally
FreeAndNil(Bitmap);
end;
end;

Delphi image canvas... paint an area (triangle, rectangle, polygons)

I have a variable number of points on a canvas.
Sometime its four other times 3 points, or 6.
Is there a function that can paint the area inside?
Thank you for your help.
Use the TCanvas.Polygon function. Declare an array of TPoint, set its length to the count of your points, specify each point's coordinates (optionally modify canvas pen and/or brush) and pass this array to the TCanvas.Polygon function. Like in this boring example:
procedure TForm1.Button1Click(Sender: TObject);
var
Points: array of TPoint;
begin
SetLength(Points, 3);
Points[0] := Point(5, 5);
Points[1] := Point(55, 5);
Points[2] := Point(30, 30);
Canvas.Pen.Width := 2;
Canvas.Pen.Color := clRed;
Canvas.Brush.Color := clYellow;
Canvas.Polygon(Points);
end;
Here's how it looks like:
As a complement to TLama's excellent answer, this is a case where you can obtain pretty convenient syntax using the open array construct. Consider the helper function
procedure DrawPolygon(Canvas: TCanvas; const Points: array of integer);
var
arr: array of TPoint;
i: Integer;
begin
SetLength(arr, Length(Points) div 2);
for i := 0 to High(arr) do
arr[i] := Point(Points[2*i], Points[2*i+1]);
Canvas.Polygon(arr);
end;
defined and implemented once and for all. Now you can do simply
Canvas.Pen.Width := 2;
Canvas.Pen.Color := clRed;
Canvas.Brush.Color := clYellow;
DrawPolygon(Canvas, [5, 5, 55, 5, 30, 30]);
to draw the same figure as in TLama's example.
As a complement to both TLama's and Andreas answer, here's another alternative :
procedure TForm1.Button1Click(Sender: TObject);
begin
Canvas.Pen.Color := clRed;
Canvas.Brush.Color := clYellow;
Self.Canvas.Polygon( [Point(5,5), Point(55,5), Point(30,30)]);
end;
Utilizing open array construct and Point record.

What is the best way to make a Delphi Application completely full screen?

What is the best way to make a delphi application (delphi 2007 for win32 here) go completely full screen, removing the application border and covering windows task bar ?
I am looking for something similar to what IE does when you hit F11.
I wish this to be a run time option for the user not a design time decision by my good self.
As Mentioned in the accepted answer
BorderStyle := bsNone;
was part of the way to do it. Strangely I kept getting a E2010 Incompatible types: 'TFormBorderStyle' and 'TBackGroundSymbol' error when using that line (another type had bsNone defined).
To overcome this I had to use :
BorderStyle := Forms.bsNone;
Well, this has always worked for me. Seems a bit simpler...
procedure TForm52.Button1Click(Sender: TObject);
begin
BorderStyle := bsNone;
WindowState := wsMaximized;
end;
A Google search turned up the following, additional methods:
(though I think I'd try Roddy's method first)
Manually fill the screen (from: About Delphi)
procedure TSomeForm.FormShow(Sender: TObject) ;
var
r : TRect;
begin
Borderstyle := bsNone;
SystemParametersInfo
(SPI_GETWORKAREA, 0, #r,0) ;
SetBounds
(r.Left, r.Top, r.Right-r.Left, r.Bottom-r.Top) ;
end;
Variation on a theme by Roddy
FormStyle := fsStayOnTop;
BorderStyle := bsNone;
Left := 0;
Top := 0;
Width := Screen.Width;
Height := Screen.Height;
The WinAPI way (by Peter Below from TeamB)
private // in form declaration
Procedure WMGetMinMaxInfo(Var msg: TWMGetMinMaxInfo);
message WM_GETMINMAXINFO;
Procedure TForm1.WMGetMinMaxInfo(Var msg: TWMGetMinMaxInfo);
Begin
inherited;
With msg.MinMaxInfo^.ptMaxTrackSize Do Begin
X := GetDeviceCaps( Canvas.handle, HORZRES ) + (Width - ClientWidth);
Y := GetDeviceCaps( Canvas.handle, VERTRES ) + (Height - ClientHeight
);
End;
End;
procedure TForm1.Button2Click(Sender: TObject);
Const
Rect: TRect = (Left:0; Top:0; Right:0; Bottom:0);
FullScreen: Boolean = False;
begin
FullScreen := not FullScreen;
If FullScreen Then Begin
Rect := BoundsRect;
SetBounds(
Left - ClientOrigin.X,
Top - ClientOrigin.Y,
GetDeviceCaps( Canvas.handle, HORZRES ) + (Width - ClientWidth),
GetDeviceCaps( Canvas.handle, VERTRES ) + (Height - ClientHeight ));
// Label2.caption := IntToStr(GetDeviceCaps( Canvas.handle, VERTRES ));
End
Else
BoundsRect := Rect;
end;
Maximize the form and hide the title bar. The maximize line is done from memory, but I'm pretty sure WindowState is the property you want.
There's also this article, but that seems too complicated to me.
procedure TForm1.FormCreate(Sender: TObject) ;
begin
//maximize the window
WindowState := wsMaximized;
//hide the title bar
SetWindowLong(Handle,GWL_STYLE,GetWindowLong(Handle,GWL_STYLE) and not WS_CAPTION);
ClientHeight := Height;
end;
Edit: Here's a complete example, with "full screen" and "restore" options. I've broken out the different parts into little procedures for maximum clarity, so this could be greatly compressed into just a few lines.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
btnGoFullScreen: TButton;
btnNotFullScreen: TButton;
btnShowTitleBar: TButton;
btnHideTitleBar: TButton;
btnQuit: TButton;
procedure btnGoFullScreenClick(Sender: TObject);
procedure btnShowTitleBarClick(Sender: TObject);
procedure btnHideTitleBarClick(Sender: TObject);
procedure btnNotFullScreenClick(Sender: TObject);
procedure btnQuitClick(Sender: TObject);
private
SavedLeft : integer;
SavedTop : integer;
SavedWidth : integer;
SavedHeight : integer;
SavedWindowState : TWindowState;
procedure FullScreen;
procedure NotFullScreen;
procedure SavePosition;
procedure HideTitleBar;
procedure ShowTitleBar;
procedure RestorePosition;
procedure MaximizeWindow;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btnQuitClick(Sender: TObject);
begin
Application.Terminate;
end;
procedure TForm1.btnGoFullScreenClick(Sender: TObject);
begin
FullScreen;
end;
procedure TForm1.btnNotFullScreenClick(Sender: TObject);
begin
NotFullScreen;
end;
procedure TForm1.btnShowTitleBarClick(Sender: TObject);
begin
ShowTitleBar;
end;
procedure TForm1.btnHideTitleBarClick(Sender: TObject);
begin
HideTitleBar;
end;
procedure TForm1.FullScreen;
begin
SavePosition;
HideTitleBar;
MaximizeWindow;
end;
procedure TForm1.HideTitleBar;
begin
SetWindowLong(Handle,GWL_STYLE,GetWindowLong(Handle,GWL_STYLE) and not WS_CAPTION);
ClientHeight := Height;
end;
procedure TForm1.MaximizeWindow;
begin
WindowState := wsMaximized;
end;
procedure TForm1.NotFullScreen;
begin
RestorePosition;
ShowTitleBar;
end;
procedure TForm1.RestorePosition;
begin
//this proc uses what we saved in "SavePosition"
WindowState := SavedWindowState;
Top := SavedTop;
Left := SavedLeft;
Width := SavedWidth;
Height := SavedHeight;
end;
procedure TForm1.SavePosition;
begin
SavedLeft := Left;
SavedHeight := Height;
SavedTop := Top;
SavedWidth := Width;
SavedWindowState := WindowState;
end;
procedure TForm1.ShowTitleBar;
begin
SetWindowLong(Handle,gwl_Style,GetWindowLong(Handle,gwl_Style) or ws_Caption or ws_border);
Height := Height + GetSystemMetrics(SM_CYCAPTION);
Refresh;
end;
end.
Put to the form onShow event such code:
WindowState:=wsMaximized;
And to the OnCanResize this:
if (newwidth<width) and (newheight<height) then
Resize:=false;
How to constrain a sub-form within the Mainform like it was an MDI app., but without the headaches! (Note: The replies on this page helped me get this working, so that's why I posted my solution here)
private
{ Private declarations }
StickyAt: Word;
procedure WMWINDOWPOSCHANGING(Var Msg: TWMWINDOWPOSCHANGING); Message M_WINDOWPOSCHANGING;
Procedure WMGetMinMaxInfo(Var msg: TWMGetMinMaxInfo); message WM_GETMINMAXINFO;
later...
procedure TForm2.WMWINDOWPOSCHANGING(var Msg: TWMWINDOWPOSCHANGING);
var
A, B: Integer;
iFrameSize: Integer;
iCaptionHeight: Integer;
iMenuHeight: Integer;
begin
iFrameSize := GetSystemMetrics(SM_CYFIXEDFRAME);
iCaptionHeight := GetSystemMetrics(SM_CYCAPTION);
iMenuHeight := GetSystemMetrics(SM_CYMENU);
// inside the Mainform client area
A := Application.MainForm.Left + iFrameSize;
B := Application.MainForm.Top + iFrameSize + iCaptionHeight + iMenuHeight;
with Msg.WindowPos^ do
begin
if x <= A + StickyAt then
x := A;
if x + cx >= A + Application.MainForm.ClientWidth - StickyAt then
x := (A + Application.MainForm.ClientWidth) - cx + 1;
if y <= B + StickyAt then
y := B;
if y + cy >= B + Application.MainForm.ClientHeight - StickyAt then
y := (B + Application.MainForm.ClientHeight) - cy + 1;
end;
end;
and yet more...
Procedure TForm2.WMGetMinMaxInfo(Var msg: TWMGetMinMaxInfo);
var
iFrameSize: Integer;
iCaptionHeight: Integer;
iMenuHeight: Integer;
Begin
inherited;
iFrameSize := GetSystemMetrics(SM_CYFIXEDFRAME);
iCaptionHeight := GetSystemMetrics(SM_CYCAPTION);
iMenuHeight := GetSystemMetrics(SM_CYMENU);
With msg.MinMaxInfo^.ptMaxPosition Do
begin
// position of top when maximised
X := Application.MainForm.Left + iFrameSize + 1;
Y := Application.MainForm.Top + iFrameSize + iCaptionHeight + iMenuHeight + 1;
end;
With msg.MinMaxInfo^.ptMaxSize Do
Begin
// width and height when maximized
X := Application.MainForm.ClientWidth;
Y := Application.MainForm.ClientHeight;
End;
With msg.MinMaxInfo^.ptMaxTrackSize Do
Begin
// maximum size when maximised
X := Application.MainForm.ClientWidth;
Y := Application.MainForm.ClientHeight;
End;
// to do: minimum size (maybe)
End;
In my case, the only working solution is:
procedure TFormHelper.FullScreenMode;
begin
BorderStyle := bsNone;
ShowWindowAsync(Handle, SW_MAXIMIZE);
end;
You need to make sure Form position is poDefaultPosOnly.
Form1.Position := poDefaultPosOnly;
Form1.FormStyle := fsStayOnTop;
Form1.BorderStyle := bsNone;
Form1.Left := 0;
Form1.Top := 0;
Form1.Width := Screen.Width;
Form1.Height := Screen.Height;
Tested and works on Win7 x64.
Try:
Align = alClient
FormStyle = fsStayOnTop
This always align to the primary monitor;
Hm. Looking at the responses I seem to remember dealing with this about 8 years ago when I coded a game. To make debugging easier, I used the device-context of a normal, Delphi form as the source for a fullscreen display.
The point being, that DirectX is capable of running any device context fullscreen - including the one allocated by your form.
So to give an app "true" fullscreen capabilities, track down a DirectX library for Delphi and it will probably contain what you need out of the box.

Resources