How can I scroll the content of a TFlowPanel? - delphi

Delphi implementation of the TFlowPanel control seems to lack an important feature of the C# version, the AutoScroll one.
The C# control with AutoWrap= False and AutoScroll=True behave like a horizontal scrollable list of controls.
How can i mimic the behavior of the C# version of the control ?
Thanks,
Alin
P.S.
I know i can use TScrollBox to get this behavior but TFlowPanel (in the not crippled version) allow for much more flexibility.

Create your TFlowPanel inside a TScrollBox, with the following properties:
Align : alLeft
AutoSize : TRUE
AutoWrap : FALSE
That should get you the behaviour you are after I think.

If you want to scroll vertically set
FlowPanel1.Align := alTop;
FlowPanel1.AutoSize := True;
FlowPanel1.AUtoWrap := False;

For people who are looking for a working vertical scrolling method:
procedure TfrmSample.FixVerticalScroll(const AFloatPanel: TFloatPanel);
begin
fFloatPanel.Align := alTop;
fFloatPanel.AutoSize := True;
fFloatPanel.AutoWrap := True;
fFloatPanel.OnResize := OnFlowPanelResize;
end;
procedure TfrmSample.OnFlowPanelResize(Sender: TObject);
begin
// Fix: otherwise panel is not operating on the full width
fFloatPanel.Align := alClient;
fFloatPanel.Align := alTop;
end;

Related

How to stop Screen.Cursor affects all controls on the form?

I will try to simplify my problem. If for example you drop 2 TSpeedButton and do:
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
Screen.Cursor := crHourGlass;
SpeedButton2.Cursor := crHandPoint; // note I'm setting other cursor than crDefault
end;
The SpeedButton2.Cursor remains showing Screen.Cursor which was set to crHourGlass.
I have looked into the TScreen.SetCursor code, and realize it sets the cursor for the entire form.
My question: is it somehow possible to use the Screen.Cursor for the entire form, BUT without impacting some control(s) which I want to set other cursor.
The same happens with a TButton. I don't mind placing the SpeedButton on a windowed control if I can somehow control it's cursor while Screen.Cursor is set to crHourGlass.
Thanks.
This is intentional behavior as explained in the documentation for TScreen.Cursor:
... When Cursor is crDefault, the individual objects determine the
cursor image. Assigning any other value sets the mouse cursor image
for all windows belonging to the application. The global mouse cursor
image remains in effect until the screen's Cursor property is changed
back to crDefault. ..
Windowed controls handle their cursors in TWinControl.WMSetCursor procedure, handler of WM_SETCURSOR message, where they explicitly set the screen cursor if it is anything other than crDefault and disregard their own cursor.
So to change the behavior you can handle the mentioned message. For a TButton interposer, an example could be:
procedure TButton.WMSetCursor(var Message: TWMSetCursor);
begin
if (Cursor <> crDefault) and (Message.HitTest = HTCLIENT) then begin
Message.Result := 1;
Windows.SetCursor(Screen.Cursors[Cursor]);
end else
inherited;
end;
Graphic controls' cursors are handled by their parent TWinControl. So to change the behavior of a speed button, you would still need to handle the same message on its parent. This would likely be impractical since the parent class might not be known beforehand.
Still, a very non-generalized implementation, for example for a graphic control placed directly on the form, might look like the below:
procedure TForm1.WMSetCursor(var Message: TWMSetCursor);
var
SmPt: TSmallPoint;
Control: TControl;
begin
DWORD(SmPt) := GetMessagePos;
Control := ControlAtPos(ScreenToClient(SmallPointToPoint(SmPt)), True);
if Assigned(Control) and Boolean(Control.Tag) then begin
Message.Result := 1;
Windows.SetCursor(Screen.Cursors[Control.Cursor])
end else
inherited;
end;
Above example would require the graphic control to have a non zero tag value. E.g.:
procedure TForm1.Button1Click(Sender: TObject);
begin
Screen.Cursor := crHourGlass;
SpeedButton1.Cursor := crHandPoint;
SpeedButton1.Tag := 1;
end;

How to maximize a form in a Tpanel using delphi

i'm trying to dynamically show a form in a TPanel
using this function
procedure Show_form_in_panel(form: TForm; Panel: Tpanel);
begin
form.Parent := Panel;
form.Show;
form.WindowState := wsMaximized;
end;
the form is showing very normal but he's not maximized in my panel and also i want to make this form automaticly react like components that have the Alight property = (alClient)
I want to make this form automatically react like components that have the Align property set to alClient.
That's the solution. Remove
form.WindowState := wsMaximized;
and replace with
form.Align := alClient;

Delphi XE6 TForm.AutoSize

I've code in Delphi XE2 who work perfectly. But in Delphi XE6 it doesn't work.
I create a Tform with the property AutoSize to true. I use a TPanel align alTop with a button for create some another panels.
procedure TForm2.Button1Click(Sender: TObject);
var
t :TPanel;
begin
t := TPanel.Create(self);
t.Parent := self;
t.Align := alTop;
end;
The form doesn't auto size. If I want to see all my panels I have to move the form (or try to resize, ....).
Have you any idea's ?
This is indeed a change in behaviour. I can reproduce what you report. Namely that your code results in the form size changing in XE2, but not in XE6.
To work around this you can manually call AdjustSize:
procedure TForm1.Button1Click(Sender: TObject);
var
Panel: TPanel;
begin
Panel := TPanel.Create(self);
Panel.Parent := Self;
Panel.Top := ClientHeight;
Panel.Align := alTop;
AdjustSize;
end;
Not align, use anchors:
t.Anchors:=[TAnchorKind.akTop];
This is from my XE5 (have no XE6)

Disabled TEdit Font Colour

I have an application having one TEdit which is disabled when the application runs. After some calculations it will be enabled. My requirement is to set the Font.Color of this disabled TEdit as Blue instead of Grey (Disabled Font Color).
This is not supported by the standard TEdit. You could set the edit to ReadOnly instead of Disabled - this way the font color is preserved but user can't change the value of the edit. Ie to "disable" the edit
Edit1.ReadOnly := True;
Edit1.Font.Color := clBlue;
and to enable it again
Edit1.ReadOnly := False;
Edit1.Font.Color := clWindowText;
See Peter Below's two suggestions for accomplishing your objective on Torry's Delphi Pages at this link. Judging from your comment about what you Googled, his first suggestion will be simpler for you to implement. Drop a TPanel on a form and drag a TEdit onto the TPanel (i.e., TPanel is TEdit's parent. Then drop a Button on the form to simulate when your calculations are done.
procedure TForm1.btnToggleEnabledClick(Sender: TObject);
begin
if Panel1.Enabled then
begin
{Calcs are not done, so disable the TEdit}
Panel1.Enabled := false;
Edit1.Font.Color := clBlue;
Edit1.Text := 'Calcs not done';
end
else
begin
{Calcs are done, so enable the TEdit}
Panel1.Enabled := true;
Edit1.Font.Color := clWindowText;
Edit1.Text := 'Calcs all done';
end;
end;

Dynamically resize a form to fit the size of a Frame in Delphi

I have an application that has 5 different sized frames. I'd like to dynamically re-size the main form to fit the frame when I move from one frame to another.
I can use the MinHeight/MinWidth properties of the frame to force the main form to fit the frame, but then when moving to a smaller frame, the main form does not adjust it's size.
Any ideas?
--Edit
...
TFormMain = Class(TForm)
...
public
FrameImportPackage: TFrameImportPackage;
...
procedure TFormMain.MenuPackagesImportClick(Sender: TObject);
begin
if not (Assigned(FrameImportPackage)) then
begin
FrameImportPackage := TFrameImportPackage.Create(Self);
FrameImportPackage.LabelFrameCaption.Caption := 'Import or Edit a Package';
end
else
begin
FrameImportPackage.BringToFront;
end;
FrameImportPackage.Parent := Self;
end;
--Edit
Regards, Pieter
If I understand your question correctly, you've got frames that don't change size, you want the form to update size to fit your frames. Let Delphi handle that for you, using the AutoSize property.
Set AutoSize = True for your form.
I've tested AutoSize with the following code, using Delphi 2010:
Create a new VCL application. On the blank form drop a single Panel, let it keep it's name (Panel1). Make sure the panel is not too small, because we'll write code to decrease it's size at runtime.
Set the form's AutoSize property to True.
Drop two buttons on the panel, Button1 and Button2.
Double click the buttons, and copy-paste the following event handlers:
Code:
procedure TForm31.Button1Click(Sender: TObject);
var NewR: TRect;
begin
NewR := Panel1.BoundsRect;
Dec(NewR.Right, 32);
Dec(NewR.Bottom, 32);
Button1.Parent := Self;
Button2.Parent := Self;
Panel1.Free;
Panel1 := TPanel.Create(Self);
Panel1.BoundsRect := NewR;
Panel1.Parent := Self;
Button1.Parent := Panel1;
Button2.Parent := Panel1;
end;
procedure TForm31.Button2Click(Sender: TObject);
begin
Panel1.Height := Panel1.Height - 32;
Panel1.Width := Panel1.Width - 32;
end;
This essentially gives you two ways of decreasing the size of the panel, to handle two possible scenarios: Button1 frees the old panel and creates a new, smaller panel. Button2 directly resize the existing panel. Both work as expected!
At least on Delphi 2006 there is a really anonying BUG with Form AutoSize.
You put a TStringGrid onto the form (Left and Top equal zero, align equal None, Top, CLient does not matter), when you change its ClientWidth and ClientHeightt the form not allways adjusts its size to the control.
Normally when it fails is when control size is reduced, form size does not get reduced.
There is no good fix, the only way to do it is manually set clientwidth and clientheight of the form when the object is resized.
It is said: Form AutoSize does not allways work well! It is a BUG on the VCL.

Resources