Delphi TChart Bar Width - delphi

I'm trying to figure it out how to set a fixed size to the bars' width in TChart.
I've tried to search a lot for a similar "problem", but I may be using the wrong terms, because I found no related topics in the internet.
My chart has Horizontal Scrolling enabled, so I would like to have bars with the same width regardless how many bars are in the chart.
Here's a sample where I added 10 sample values and, for my purpose, this bar width is acceptable:
But when I add 40 sample values, for example, the bars became so thin, even when showing only 10 values and letting all the others visible only after scroll the bars to the left:
Here's the code I'm using to add the sample values (just for you to see there's nothing special):
procedure TForm5.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to ChartFatGrupoPerc.SeriesCount-1 do
ChartFatGrupoPerc.Series[i].FillSampleValues(StrToInt(eItems.Text));
ChartFatGrupoPerc.BottomAxis.Maximum := StrToInt(eMax.Text);
ChartFatGrupoPerc.BottomAxis.Minimum := StrToInt(eMin.Text);
end;
So, the question is: Is there an way I can define the bars' width regardless the amount of values?
Thanks in advance,
Kelver Merlotti [KM]

Is there an way I can define the bars' width regardless the amount of values?
Yes, setting these properties would do the trick:
AutoBarSize := false;
CustomBarWidth := aSuitableNumber;

Related

Get Top and Left position of an FMX Control, based on screen bounds

I'm trying to place an outside program right into an FMX TPanel using SetWindowPOS from WinAPI.
In order to do that I need the exact Top and Left values of the TPanel to pass it to SetWindowPOS. However, this value is always according to its parent, so i.e. if the Tpanel's parent is a TLayout and no margins are set, then the value of Top will be 0.
I need the Top value according to the screen.
I tried searching for that quite a bit but I can't figure it out.
Any help with that would be greatly appreciated.
After just posting the question I got the simple solution
var
pnt: TPointF;
begin
pnt := myRctngl.LocalRect.TopLeft;
pnt := myRctngl.LocalToAbsolute(pnt);
pnt := ClientToScreen(pnt);
End;
pnt should now have the value of the Point according to the screen.
You can now use pnt.x and pnt.y to get the top/left values.

How to calculate the height of a TCategoryButtons at run-time?

In a Delphi 10.4.2 VCL Application in Windows 10, how can I calculate the height of a TCategoryButtons object at run-time, i.e. the sum of all its button heights and its Category items, as this height could vary depending on its font size?
Measuring the pixel heights at run-time, I have noticed that all buttons have the same height and that the buttons have a different height as the Category items.
Also, note that the buttons do not have a published Height property in the Object Inspector.
But shouldn't it be possible to calculate the sum of all its button heights and its Category items with some low-level methods?
This is a control entirely implemented in Pascal, in Vcl.CategoryButtons.pas.
Therefore, you can see exactly how it is implemented. For instance, in TCategoryButtons.Paint you see its complete drawing code. Similarly, you can investigate the hit testing done in MouseMove (or MouseDown or MouseUp).
Consequently, if nothing else, you can create your own modified version of TCategoryButtons using this code. Your version can save the total height when it has been determined (for instance, certainly after painting).
However, after a quick look, it seems like TButtonCategory.Bounds might be interesting. If you are lucky, this returns the on-screen rect of a category. The Bottom of the last category's rect should be the (effectively used) height of the entire control.
It seems to work for me:
Here I draw a red bar of the same height as the control.
procedure TForm5.FormPaint(Sender: TObject);
begin
var y := CategoryButtons1.Categories[
CategoryButtons1.Categories.Count - 1
].Bounds.Bottom;
Canvas.Brush.Color := clRed;
Canvas.FillRect(Rect(0, 0, ClientWidth, y))
end;

TVirtualStringTree ScaleBy Stretch

I'm Trying to get a VST to resize automatically when its Height and Width is changed.
I don't have this problem with other placed VCL components, some of them have a Property "Stretch" like TImage, which lets them adjust automatically. The VST remains stubborn and keeps nodeHeights and Column widths.
I have seen Header->hoAutoResize, hoColumnResize. In this matter, AutoSizeIndex <> -1 is not so useful, since I need every column to scale down. I think that's why these don't do anything. Changing the AutoSizeIndex to my last Column (3, because i have 4 Columns) and having hoAutoResize = True; still doesn't affect my column widths. hoColumnResize is the setting that lets the User resize columns, so no luck with that either
I have seen TreeOptions->AutoOptions->toAutoChangeScale and toAutoSpanColumns. I found out that toAutoSpanColumns is counter-productive in my case, so that's off. My Font-Size is adjusting.
I have found Tree.Scaleby, but I can't make it work in my favor and it's undocumented in the official .pdf docs I have.
All 4 columns have minWidth of 10, so no issue there
All 4 have coEnabled, coVisible, coResizable := True and coFixed, coSmartResize := False fwiw
I guess I'm just hitting the wrong combinations of settings or something.
Any hints would be great, thanks.
From your post I understand that you want to automatically adjust widths of all columns proportionally when the TVirtualStringTree width changes. If you want that to also happen with the row heights, you can just apply the following correspondingly.
There is no setting for the a propertional column width, but it is simple to achieve in the OnResize event of the TVirtualStringTree:
procedure TForm1.VSTResize(Sender: TObject);
begin
VST.Header.Columns[0].Width := MulDiv(VST.Width, 50, 100);
VST.Header.Columns[1].Width := MulDiv(VST.Width, 30, 100);
VST.Header.Columns[2].Width := MulDiv(VST.Width, 20, 100);
end;
In the above, the columns are kept as 50%, 30% and 20% of the components width.
You need to set Header->AutoSizeIndex to the index of yours last column, besides the Header->hoAutoResize to true.
Something like this if you wish to do it programmatically:
vt.Header.Options := vt.Header.Options + [hoAutoResize];
vt.Header.AutoSizeIndex := vt.Header.Columns.GetLastVisibleColumn;

Report Builder Spacing DBMemo Delphi

I am using a DBMemo (TPPDBMemo) component in reportbuilder within delphi. The Stretch property is true but the control doesn't always stretch itself out correctly within the region.
For example if there is lower case text, that dips downward, eg, chars like p,g,q... The bottom part of the text will get cut off if it's on the last line.
I tried adding an event to the onPrint to slightly grow the DBMemo when it prints,
procedure Tfrm.ppDBMemPrint(Sender: TObject);
begin
ppDBMem.Height := ppDBMem.Height + 10;
end;
But this didn't work.
Any thoughts on how this can be achieved. If I could simply add a border to the DBMemo that would be ideal, although I do not see that property anywhere.
Thank you!

How to find the real size ("logical area") of a TScrollBox

I need to find the entire size (also called "logical area") of a TScrollBox - as opposite to visible area that you get via Width and Height property (or ClientWidth ClientHeight).
I want to create some controls inside that TScrollBox. One of them (called TViewer) needs to be as high as the TScrollBox itself. The thing is that during creation, the TScrollBox is scrolled down to show last created control. So, using Top=1 will not work because my control will have top=1 which is not the top of the logical area.
Delphi 7
Drop a component, like a TLabel, on the TScrollBox.
Set the component's Left and Top properties to 0.
Set the component's Visible property to False.
Now you always have the origin. The "logical height" is now:
myScrollBox.Height + (myOriginControl.Top * -1);
Maybe ScrollBox.HorzScrollBar.Range and ScrollBox.VertScrollBar.Range + the corresponding .Positions are what you need.
Look at Scrollbars:
ScrollBox1.VertScrollBar.Range
ScrollBox1.HorzScrollBar.Range
It can be less than height and width if the scrollbox logical area is not bigger than phisical area (scrollbars not visible in that case)
Or use this to get the max of both:
var
AHeight, AWidth: Integer;
begin
AHeight := Max(ScrollBox1.VertScrollBar.Range, ScrollBox1.Height);
AWidth := Max(ScrollBox1.HorzScrollBar.Range, ScrollBox1.Width);
ShowMessageFmt('%d,%d', [AHeight, AWidth]);
end;
Edit
From #Altar comments, I can add the logical height and/or width is not the problem. If you want to add any control which occupies all the height of the scrollbar, use the AHeight from the above calculation, but set the Top to the negative of VertScrollBar.Position, something like this:
procedure TForm2.Button3Click(Sender: TObject);
var
AHeight, AWidth: Integer;
Btn: TButton;
begin
AHeight := Max(ScrollBox1.VertScrollBar.Range, Height);
AWidth := Max(ScrollBox1.HorzScrollBar.Range, Width);
Btn := TButton.Create(Self);
Btn.Parent := ScrollBox1;
Btn.Left := 15;
Btn.Top := -ScrollBox1.VertScrollBar.Position;
Btn.Height := AHeight;
end;
Im not sure i understand exactly what you want to do, but to get the complete area defined as "scrollable" you would have to write ScrollBox.HorScrollBar.Range + ScrollBox.Clientwidth (and the same thing for the vertical section). The scrollbox always deducts the visible "page" size from the total. So if you define a height of 1000 pixels, with 100 pixels showing - it will have a scrolling range of 900. You have to add the clientheight to get the rest.
Also, to get the correct "top" position you will have to read Canvas.Cliprect.Top, since a scrolling window does not change the top position of sub-controls. Windows handles this for you and only tells you what to re-draw once the scrollbars are initialized.
Since you want to create a control that is just as high as the complete scrollable area, i presume you are creating an editor of sorts?
If so you would probably get better results taking a look at SynEdit and extract the base-class that adds scrollbars to a normal TCustomControl (it's quite easy). That way you can control both the painting and the layout of your controls.
Here is one I wrote for Lazarus and FreePascal a while back. If you add messages to the uses clause and prefix the message handlers with WM rather than TLM it will compile under Delphi.
(code to long, had to use external link): http://delphimax.wordpress.com/2010/09/20/platform-independent-image-component-for-lazarus/
I have tried to do that, and believe me, I was not able to.
If you have the instances of the controls that are inside TScrollBox, you can use them to calculate (not precisely) the area.
Here is a complicated (but complete) solution:
I create my first child control during TScrollBox.Create (when TScrollBox does not have yet a scrollbar)
Set Child.Top:= 1
Create the rest of the child controls (this may force the TScrollBox to show the scrollbar)
Scroll the TScrollBox up
Use one of the above solutions to calculate the height of the TScrollBox

Resources