Check is TScrollBox scrollbars are actually visible - delphi

I have a simple sizable form with TScrollBox (Align := alClient) and some controls put on TScrollBox. If user change the form size, TScrollBox show and hide the HorzScrollBar and VertScrollBar (depend on actual client form size).
How to check at run-time - does HorzScrollBar or VertScrollBar are visible right now?
TControlScrollBar.Visible is not an answer, because it hase a regulating function only.

Use TControlScrollBar.IsScrollBarVisible to test this.
Call IsScrollBarVisible to determine whether the scroll bar is visible. IsScrollBarVisible returns true if the Visible property is true and the associated scrolling windowed control contains child controls that lie within Margin pixels from the edge.

Related

What is the difference between TScrollBar and TControlScrollBar to scroll TForm client area

I want to draw small bitmaps hold in a list on a TForm with Canvas but beyond the limit of the size of the TForm and use Vertical and Horizontal Scrollers to navigate and allow the user to display the entire area.
I noticed that there are HorzScrollBar and VertScrollBar TControlScrollBar in the TForm, but impossible to get them visible or usable, even if they are checked as Visible.
I suppose that they are concerned only with components of the TForm, if we resize the TForm, they should appear.
Do I have to use external TScrollBar (Vertical and Horizontal ones) to achieve the scrolling (by program) of the client area of the TForm or is there a way of using the HorzScrollBar and VertScrollBar TControlScrollBar?
To automatically show the scrollbars when needed (controls outside of the visible area) set AutoScroll := true;.
But that requires that you use controls to draw your images. If you want to show the scrollbars even if you only draw (paint) directly on the form canvas, you can do so by setting the Range property to the actual extent of your drawn area.
E.g.
procedure TForm24.FormCreate(Sender: TObject);
begin
self.HorzScrollBar.Range := 1000;
end;
So, to answer your question, you can use the built-in scrollbars.

Centered, Full Screen Application

I am currently developing a fullscreen application that I want to be centered on the screen. I have set the following settings on the form:
WindowState:= wsMaximized
FormStyle:= fsStayOnTop
However due to the form height and width being much lower than the screens actual resolution, the form is aligned into the top-left corner. I have also attempted using the Position setting on the form, however none of these settings seem to have the desired outcome. They either have no effect or shift the entire maximized for towards the Bottom-Right corner, resulting in being able to see the forms behind (I hope I have described this well enough).
Thankyou
The way I understand your question is that the form, as such, maximises correctly, but the components are in top-left corner of the maximized form, according to their Left and Top properties as set in the form designer.
For example, a form as designed in the designer:
Form as it appears when maximized (and this is the problem):
If my understanding of the problem is correct, the solution is to place all components on a TPanel and then center that TPanel on the form.
There are two ways to center the TPanel
1) Clear (set to false) all anchors of the panel as in the link provided by TLama in his comment.
2) Center the panel in the forms OnResize event
procedure TForm4.FormResize(Sender: TObject);
begin
Panel1.Left := (ClientWidth - Panel1.Width) div 2;
Panel1.Top := (ClientHeight - Panel1.Height) div 2;
end;
Either way the result looks like:

How to resize a form past/outside of its parent's bounds?

This question applies to two scenarios.
(1)
The first is having a MDI Form and MDI Child, At runtime if I try to resize the Form either horizontally or vertically I cannot go past the edge of the main MDI Form, somewhere there must be a SetBounds or something similar that prevents this type of behavior as the mouse just snaps to the edge.
What I would like is to be able to resize past/outside the MDI Form bounds rect - which would then show the scrollbars on the main MDI Form (just like when you move a Child Form around).
(2)
The second is I find the scrolling within a MDI layout application a bit annoying and not very pleasing to use, so instead of using MDI I thought I could simulate it by setting a Form inside a TScrollBox, doing this I hoped would give more better fluid scrolling. But as with the first scenario placing a Form inside a ScrollBox still does not allow resizing outside the client - and doing this method does not even show the scrollbars when you move the Form around the ScrollBox.
You can try this very quickly by making a new MDI Application. Try resizing using the bottom right corner and dragging as far to to the right/bottom as you can, the Mouse stops at the main MDI client preventing outside resizing.
So how can I allow at runtime, a Form whether it be a MDI Child or parent to a TScrollBox to be resized outside the parent bounds?
Is there a simple property I need to set that I may have overlooked or does it require more work to do such as overriding the Form's messages maybe?
MDI children are not bound by their parent's size, but they are not visible outside their parent's boundaries and therefor cannot be resized outside of those bounds.
However, you can move them outside of the boundaries, so if you move your child form to the left, leaving only a part of the form visible, you can then resize that visible part upto the boundary of the parent. So there's no really a limit in size, but it's just a functional limitation that you cannot further size the form when it's size handles/borders would become hidden.
I think, rather than placing the MDI child on a scrollbox or resizing the MDI child, you could better put the contents of the child on a scrollbox and leave the child form itself as is.
Or, of course, you could revise the design so that you don't need the scrolling at all, but it's impossible to give a proper advise without knowing your form.

Why is my TScrollBox not showing scrollbars?

This seems like a very simple problem, but I cannot get a scrollbox to display scrollbars, and it is driving me crazy.
Here is the situation. I need to display a variable number of frames in a portion of a form. The area in which these frames are being displayed can be resized either through a TSplitter or by resizing the form.
I am dynamically generating the frames based on records in a database when the form is created. This frames are parented to a FlowPanel, which is responsible for frame placement. The FlowPanel is in a ScrollBox.
Due to the FlowPanel, when the user uses the TSplitter or resizes the form, the frames may re-align themselves. If any of the frames re-position out of the view of the form, I expect the ScrollBox to display scrollbars so that the user could scroll down to those inaccessible frames. This does not happen. Those frames that are in the area of the flowpanel outside the dimensions of the scrollbox are inaccessible.
I've built some tests with simple objects in a scrollbox, and the scrollbox correctly places scrollbars if any of its contained objects appear outside of the scrollbox's dimensions.
It does not matter if the flowpanel is aligned to clClient (the scrollbox) or anchored to the sides of the scrollbox, or none of these.
I realize that I can use a TPanel instead, and perform the placement and re-positioning of the frames in code from the panel's OnResize event handler, but this is what the FlowPanel is for.
What's going on here? I've fiddled around with many different scrollbox properties, and still can't get it to work. What's the issue, and is there a solution?
Ok. I am selecting Ewe's answer as correct, but the trick to making this work was in one of his comments, and I am still not completely satified with the results.
Here is the scoop. I did have my ScrollBox and FlowPanel configured the way that Ewe suggested, but played around with a number of other settings because that configuration did not work. I am pretty sure this was due to the complexity of the form's user interface, which has many panels in panels, many splitters, and the form itself is parented into a TabSheet of a PageControl (I omitted this fact since testing the form as a stand alone form produced the same results).
What made it work, albeit in a clunky fashion, is Ewe's suggestion to toggle the FlowPanel's AutoWrap off and on again. I added the following code to the OnResize event handler of the ScrollBox:
procedure TCurrentJobsForm.ScrollBox1Resize(Sender: TObject);
begin
Flowpanel1.Autowrap := False;
FlowPanel1.AutoWrap := True;
end;
There is a noticeable flicker when resizing, but I can live with that, since it produces the desired result. Once a user resizes the form, it will always be re-created using those dimensions, so resizing is something the user will do infrequently.
The ScrollBox will only show scrollbars when the containg controls exceed the visible rectangle. As the only control inside your scrollbox is the flowpanel, it doesn't help to client align the flowpanel inside the scrollbox. This will always make the flowpanel equal the size of the scrollbox and thus no scrolling is necessary.
If you want f.i. vertical scrolling, make the flowpanel top aligned and auto sized. This should make the flowpanel height bigger when more frames are placed inside.
Just in case: check that the Visible property of the vertical scrollbar is set to true.
I do not have Autosize true.
I have the flow panel on a Scrollbox.
The flow planel align is set to leftRightTopBottom.
On the formresize event I do this:
procedure TForm2.FormResize(Sender: TObject);
var
i,h:integer;
begin
h:=0;
for i:=0 to FlowPanel1.ControlCount - 1 do
h:=Max(FlowPanel1.Controls[i].BoundsRect.Bottom,h);
ScrollBox1.VertScrollBar.Range:=h;
end;
Works great.
I had similar problem and I solved it with an adaptation of #Mark's code. Considering you have a FlowPanel1 and a ScrollBox1 on your Form1, you can try:
Set the ScrollBox1's Align property to alClient;
Put the FlowPanel1 on the ScrollBox1;
Set the FlowPanel1's FlowStyle property to fsLeftRightTopBottom.
Now, on the OnResize event of the Form1, just do:
procedure TForm1.FormShow(Sender: TObject);
var
I: Integer;
VButton: TButton;
begin
for I := 1 to 10 do
begin
VButton := TButton.Create(FlowPanel1);
VButton.Parent := FlowPanel1;
VButton.Name := 'Button' + I.ToString;
VButton.Height := 200;
VButton.Width := 200;
end;
end;
See the result in the picture below:
HTH.
All efforts to get TScrollBox working failed to please but I was happy to find that dropping a TFlowPanel with AutoSize and AutoWrap set to true and its alignment set to alTop into a TPageScroller with Orientation = soVertical worked rather well. Scrolling ensued.
You may wish to embiggen the pagescroller's ButtonSize to allow it to stand out. 18 seems about right.

How to show scrollbars in TScrollBox after it has been made visible again?

I've ran into one small problem. I am dynamically generating some controls and place them on a TScrollbox component. But I noticed that if the scrollbox is visible, user can clearly see each of the controls being created and placed. So it looks like lots of work is being done and it is slow.
I hid the scrollbox and generated all the controls on it, which took much less time and no flickering and alike. But here's the problem. When I show the scrollbox again, its' scrollbar doesn't appear until I actually resize the form. (The alignment of scrollbox is alClient)
Any ideas on how to fix this?
Tried repainting, but it didn't work. Refresh didn't work either.
Thank you
EDIT:
TScrollBox(Form1.FindComponent('termai')).Visible:= false;
for I := 0 to mazgas.GrafasPagalVarda(sActiveGrafas).Termai.Count - 1 do
begin
fNaujasTermas(i,oHook);
end;
TScrollBox(Form1.FindComponent('termai')).Visible := true;
The code above shows how I hide and show the scrollbox.
fNaujasTermas generates a panel with several trackbars, images and edits.
I'm not sure about what step-by-step explanation there might be. Just make a procedure where it would generate some panel with many controls on it and set the ScrollBox as a parent. Hide scrollbox before generating anything and unhide it after all is done.
Oh btw, the panel is aligned alTop. So every time new panel is created and placed into scrollbox, it will appear at the top while all other panels will move down.
This is how I created the scrollbox itself
pTermai := TScrollBox.Create(Self);
pTermai.Parent := pLeft;
pTermai.Align := alClient;
pTermai.Name := 'termai';
pTermai.BorderStyle := bsNone;
pTermai.VertScrollBar.Increment := 40;
EDIT2: I think I know how to reproduce this.
It appears that when adding a new panel to the scrollbox, it does not count it into the total height of all the controls which already are in that scrollbox.
So to give example. Lets say 1 Panel has height of 200px.
ScrollBox height is 300px.
So after creating 2 panels which add up to 400px of height, scrollbox does not show the scrollbars, even though half of the second panel is not visible. If i add one more panel = 600px total, scrollbox will show the scrollbar which looks like it would only scroll per 2 panels, not 3. When trying to scroll such window, values get recalculated and everything is shown nicely.
So the main problem is, how to make a scrollbox show scrollbar "in time" so no panels are half cut?
You can request the scrollbox to recalculate its scrollbar properties by calling the Realign() method it inherits from TWinControl. To minimize flicker you should do this while it's still invisible, like so:
ScrollBox.Visible := False;
try
// create your new panel ...
finally
ScrollBox.Realign;
ScrollBox.Visible := True;
end;
As I said in the comments, I am unable to reproduce the problem. It would help if you gave step-by-step instructions on how to reproduce the problem.
But if you say that the problem goes away if you resize the form, why not simply resize the form? Maybe you could try to resize it 0 pixels using SetWindowPos. You might also try ScrollBox1.Perform(WM_VSCROLL, SB_PAGEUP, 0);.

Resources