FMX Change Coordinate System - delphi

I want to change Delphi FMX's coordinate system (for visual controls like TImage, TPaintBox, etc) to use Cartesian coordinate system (Bottom Left)
How can I do this?
This is very basic for GDI:
HDC hDC = this->Canvas->Handle;
SetMapMode(hDC, MM_LOENGLISH); //Change coordinate system
SetViewportOrgEx(hDC, 300, 200, NULL); //Change origin
Coordinate point change sample for Delphi FMX:
Image1.Position.Point := PointF(250, 250);

I've just noticed one can set a negative scale (at one or both axes) in FMX resulting in flipping things in the respective axes coordinates.
So to reverse the Y axis you need to do
SomeContainer.Scale.Point := TPointF.Create(0, -1);
after that you'd also need to offset though, but could do it by offseting a parent control by (-width/2, -height/2) I guess

Related

How set Panel position always above of hole region?

I have a code that creates a hole in Form using the mouse.
var
FormRegion, HoleRegion: HRGN;
begin
FormRegion := CreateRectRgn(0, 0, Form1.Width, Form1.Height);
HoleRegion := CreateRectRgn(X1, Y1, X2, Y2);
CombineRgn(FormRegion, FormRegion, HoleRegion, RGN_DIFF);
SetWindowRgn(Form1.Handle, FormRegion, True);
end;
Now i wish put one Panel (that already have a fixed height) always above of hole region (and with same width of hole) to simulate a title bar, something like this:
How can be made?
You did not read carefully my request for additional information, so I leave it to you to adjust however you like.
Anyway, I believe your actual question is concerning the alignment of the panel with the transparent region. You probably do not consider that the region calculations with the form window includes the borders, so you have an offset to the right and downwards.
Since the regions are calculated including the borders of the form, you will need a variable ClientOffset: TPoint to hold the values of width of the left border and the height of the top border (incl. title bar of the form).
var
ClientOffset: TPoint;
To calculate the ClientOffset you can use the predefined ClientOrigin and the forms Left and Top properties.
ClientOffset.X := Form36.ClientOrigin.X - Form36.Left; // Left border width
ClientOffset.Y := Form36.ClientOrigin.Y - Form36.Top; // Top border height (incl. title bar)
Then, either subtract ClientOffset from the panels Left and Top properties, or add ClientOffset to the HoleRegions coordinates. The latter being more correct if you use the mouse (and presumably the forms client coordinates) to define the "hole" region

Drawing rectangle with canvas

With this code I want to draw a rectangle:
procedure TForm1.Button1Click(Sender: TObject);
var rectangle:Trect;
begin
fx:=400;
fy:=400;
sc1:=base/fx;
sc2:=altezza/fy;
sc:=max(sc1, sc2);
lx:=fx*sc;
ly:=fy*sc;
xc:=base/2;
yc:=altezza/2;
x1:=xc-(lx/2); x2:=xc+(lx/2); y1:=yc-(ly/2); y2:=yc+(ly/2);
panel1.Repaint;
panel1.Canvas.Brush.color:= clblack;
panel1.Canvas.line((panel1.width div 2),0,(panel1.Width div 2), panel1.Height);
panel1.Canvas.line(0,(panel1.height div 2), panel1.Width,(panel1.Height div 2));
panel1.canvas.brush.style:=bsclear;
Rectangle:=rect(x1, y1, x2, y2);
end;
But there is a problem because I have to use only integer values.
Is it possible to use real values for drawing a rectangle with TCanvas?
The simple answer is no. Graphic devices as represented by TCanvas use a coordinate system with integral coordinates. If your coordinates are real values then you need to use some form of mapping between your coordinate system and the integral device coordinates.
However, in this instance it looks like it's not that complex. You don't need real valued coordinates per se. You only have real values because you used real division. Perhaps all you need to do is use integer division, div, rather than real division. Or perhaps you would prefer Round.
A bigger problem is that your code is in the wrong place. You cannot paint in a button handler. Windows will not remember what you painted. The next time the window is invalidated it will ask the panel to refresh itself, and your rectangle will be gone. Painting code needs to be inside an overriden Paint method or equivalent. Perhaps you need a paint box control.

Converting Delphi TPoint to C# Point

I am trying to convert some Delphi code as we are re-writing a Delphi 6.0 (VCL) application in .Net. I am not sure and could not figure out the comparison between 2 Delphi Tpoints(x,y) with that of C# Point(x,y).
I am trying to draw a line between 2 points but since I have no idea how Delphi draws it, I am not able to set the C# coordinates for it.
The Delphi code is simple:
Canvas.MoveTo(x, y - 128);
Canvas.LineTo(x, y);
I know about the C# coordinates though about 72 Points per inch and need to calculate the pixel density. But I am not sure about the Delphi PPI.
Any would be appreciated. Thanks.
Edit: If someone is wondering what TPoint I am talking when there is none in my code snippet, Canvas.MoveTo sets the PenPos property of the canvas which is of type TPoint.
I'm not sure what the exact question is that's being asked here. You have no Delphi TPoint in your code snippet; you simply have client rect logical coordinates.
The origin is at X = 0, Y = 0, which is the top left corner of the client area. Increasing X moves the position to the right, and increasing Y moves the position down. Logical units are pixels, so starting at the origin of 0, 0, a Canvas.MoveTo(10, 10) would set the new drawing position in from the left edge 10 pixels and down from the top 10 pixels, and a Canvas.LineTo(20, 20) from there would draw a line from the point at 10, 10 to 20, 20.
TCanvas.MoveTo and TCanvas.LineTo are simply wrappers around the underlying Windows GDI functions MoveToEx (with an always NULL third parameter) and LineTo.
As far as the C# equivalent, if you're referring to System.Drawing.Point, the units used are exactly the same (although I'm not sure where the origin is based by default). Given an origin of 0, 0, System.Drawing.Point(10, 10) should be the same position described above - 10 pixels from the left edge and 10 pixels down from the top edge.
A quick check confirms that the origin in a WinForms application is in fact the top left corner of the client area, using:
// Delphi code
procedure TForm3.FormPaint(Sender: TObject);
begin
Canvas.Pen.Color := clRed;
Canvas.MoveTo(0, 0);
Canvas.LineTo(100, 100);
end;
// C# code
private void Form1_Paint(object sender, PaintEventArgs e)
{
Pen newPen = new System.Drawing.Pen(Color.Red);
e.Graphics.DrawLine(newPen, new Point(0, 0), new Point(100, 100));
}
This produces the following output:

TeeChart VCL chart scale issue

I have an issue using Delphi 2007 & TChart 7.0.10.0 or 7.0.11.0 or the latest evaluation 9.0.5.0 on the TChart scaling.
The problem arises as soon I enlarge the window after a certain width and KEEP the Form height!
This is the drawing using a smaller form size.
now if I enlarge to 1200 weight I get this ugly scaling:
If I export in the designer without the aspect ratio set and with 1200 weight you will se this:
How to get ride of this?
Hp
I see you've set top and bottom margins to Chart1 in your project (8 and 20 percent respectively). I guess this has the intention of giving more space (in height) for Chart2 when you resize the form making it bigger.
Chart1's Top and Height properties should be set according to fill this blank space in the Form's OnResize event.
Try this:
procedure TGSSkillgroupStatisticForm.FormResize(Sender: TObject);
begin
Chart1.Draw;
Chart2.Top:=Chart1.ChartRect.Bottom + 25;
Chart2.Height:=Chart1.Height-Chart1.ChartRect.Bottom-40;
end;
Steema Support Central
Keep in mind that I only scale in the x-axis. Your 3-D bar / construct will after a certain width, overlap the scaling numbers! Your given answer do not fix this issue at all. To see the real problem in a better way, I added on the form creation:
Chart2.BottomAxis.Maximum := 20;
Series2.AddBar(12, 'Hallo', clred);
Here the result:

How to convert DLU into pixels?

Microsoft uses dialog length units (DLU) in their guidelines for UI. How can I convert them into pixels?
As I know, DLU depending on system font size. Can you advise some simple method of such conversion in Delphi for Win32?
First we start with what a dialog unit is.
For that i'll quote one of my own un-answered questions:
What's a dialog unit?
A dialog is a unit of measure based on the user's preferred font size.
A dialog unit is defined such that the average character is 4 dialog
units wide by 8 dialog units high:
This means that dialog units:
change with selected font
changed with selected DPI setting
are not square
i'll also quote another of my own un-answered questions:
You can check the Windows UX Guidelines to see where these
measurements come from. The short version is:
dlu = dialog unit
dlu is based on the font size (items change with user's font size)
a horizontal dlu is different from a vertical dlu (dlu's are not square)
This comes from the definition of a dialog unit: the average
character is 8dlus high by 4dlus wide.
Georgia 14pt:
If you use a smaller font (i.e. 8pt Tahoma verses 14pt Georgia), the
dlus get smaller:
Segoe UI 9pt:
Note: You'll notice that resolution (i.e. dpi) has no impact on the discussion.
So what you need is the average size of a character. Microsoft has an official technique for calculating the average character size.
average height:
GetTextMetrics(dc, {var}textMetrics);
averageHeight := textMetrics.tmHeight;
average width:
Measure the string ABCDEFGHIJLKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz using GetTextExtentPoint32, and divide by 52:
GetTextExtentPoint32(dc,
PChar('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 52, Size));
averageWidth := size.cx / 52.0;
So now you need the the size of a horizontal and a vertical dialog units. Remember that a horizontal dialog unit is 1/4 the average character width, and a vertical dlu is 1/8 the average character height:
procedure GetDlus(dc: HDC; out HorizontalDluSize, VerticalDluSize: Real);
var
tm: TTextMetric;
size: TSize;
begin
GetTextMetric(dc, tm);
VerticalDluSize := tm.tmHeight / 8.0;
GetTextExtentPoint32(dc,
PChar('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 52,
size);
HorizontalDluSize := size.cx / 52.0;
end;
Note: Any code is released into the public domain. No attribution required.
You should use the MapDialogRect() function.
Pass in a RECT in dialog units, and the equivalent RECT in pixel units is returned. Note that you need a handle to a dialog in order to give MapDialogRect() sufficient context. The function needs to know the font in order to perform the conversion.
In case you are tempted to use GetDialogBaseUnits(), remember what Raymond Chen said, GetDialogBaseUnits is a crock.
As you can guess from the title of this entry, GetDialogBaseUnits is a
crock. Since there is no HWND parameter to GetDialogBaseUnits, it
doesn't know which dialog box's DLUs you want to retrieve. So it
guesses.
And it always guesses wrong.
GetDialogBaseUnits returns the dialog base units for dialog boxes that
use the default system font. But nobody uses the default system font
any more. It screams "old and dorky". But it remains the default for
compatibility reasons. (And therefore so too does GetDialogBaseUnits.)
If you have to calculate pixel dimensions from DLUs, and you don't have a handle to a dialog, then you must use the method outlined here: How To Calculate Dialog Base Units with Non-System-Based Font
However, you made it clear in the comments that, for your problem, you do not actually need to convert from DLUs to pixels. You can use Delphi's built in form scaling to ensure that your forms are sized appropriately for the prevailing font scaling.
Here's C code for converting DLU ↔ pixels:
HWND hDlg = ...; // The handle to the dialog
LPDLGTEMPLATE *dlgTemplate = ...; // The template for the same dialog
SIZE dlgSize; // Only needed for converting DLU -> pixels
if (dlgTemplate->style == 0xFFFF0001)
{
dlgSize.cx = ((DLGTEMPLATEEX *)dlgTemplate)->cx;
dlgSize.cy = ((DLGTEMPLATEEX *)dlgTemplate)->cy;
}
else
{
dlgSize.cx = dlgTemplate->cx;
dlgSize.cy = dlgTemplate->cy;
}
RECT rc = { 0, 0, 4, 8 };
MapDialogRect(hDlg, &rc);
// To convert dlgSize to pixels, use:
SIZE wndSize = { dlgSize.cx * rc.right / 4, dlgSize.cy * rc.bottom / 8 };
// To convert wndSize to DLUs, use:
SIZE dlgSize2 = { size.cx * 4 / rc.right, size.cy * 8 / rc.bottom };
assert(dlgSize1 == dlgSize2);
For base value (and naturally, system font) call GetDialogBaseUnits. See also remarks paragraph there for the alternate method of translating dialog units <-> pixels with GetTextMetrics and/or GetTextExtentPoint32 without dialog HWND.

Resources