The interface of the TW3Scrollbox:
unit w3scrollbox;
interface
uses w3system, w3components, w3graphics, w3scrollbar;
//Default size of the scrollbars
const
CNT_SCROLLBAR_SIZE = 18;
type
TW3ScrollBoxContainer = Class(TW3CustomControl)
End;
TW3Scrollbox = Class(TW3CustomControl)
Private
FHScroll: TW3HorizontalScrollbar;
FVScroll: TW3VerticalScrollbar;
FContent: TW3ScrollBoxContainer;
Procedure HandleScroll(sender:TObject);
Procedure UpdateWhenReady;
protected
procedure ChildAdded(Const aChild:TW3Component);override;
procedure InitializeObject; override;
procedure FinalizeObject; override;
procedure Resize; override;
public
Property Content:TW3ScrollBoxContainer read FContent;
Procedure Update;
End;
Since all the child objects will be created runtime via the constructor in Smart, the JavaScript browser code might not be ready when ChildAdded() is called (which is invoked whenever a child control attach as a child). The “UpdateWhenReady” method will wait until both the DOM (document object model) and TApplication instance is truly ready, and then it will automatically update the scrollbars if there is any content that is larger than the client-area.
Take a look at the implementation:
implementation
//###########################################################################
// TW3Scrollbox
//###########################################################################
procedure TW3Scrollbox.InitializeObject;
Begin
inherited;
FContent:=TW3ScrollBoxContainer.Create(self);
FHScroll:=TW3HorizontalScrollbar.Create(self);
FHScroll.OnChanged:=HandleScroll;
FHScroll.visible:=False;
FVScroll:=TW3VerticalScrollbar.create(self);
FVScroll.OnChanged:=HandleScroll;
FVScroll.visible:=False;
//UpdateWhenReady;
end;
procedure TW3Scrollbox.FinalizeObject;
Begin
FHScroll.free;
FVScroll.free;
FContent.free;
inherited;
end;
procedure TW3Scrollbox.ChildAdded(Const aChild:TW3Component);
Begin
inherited ChildAdded(aChild);
UpdateWhenReady;
end;
Procedure TW3Scrollbox.UpdateWhenReady;
begin
if (w3_DOMReady=False)
or (ObjectReady=False) then
w3_callback(updateWhenReady,10) else
w3_callback(Update,1);
end;
procedure TW3Scrollbox.Resize;
var
wd,hd: Integer;
begin
inherited;
wd:=clientWidth;
hd:=clientHeight;
if FHScroll.visible then
dec(hd,CNT_SCROLLBAR_SIZE);
if FVScroll.Visible then
dec(wd,CNT_SCROLLBAR_SIZE);
if FHScroll.Visible then
FHScroll.setBounds(0,hd,wd,CNT_SCROLLBAR_SIZE);
if FVScroll.Visible then
FVScroll.setBounds(wd,0,CNT_SCROLLBAR_SIZE,hd);
FContent.SetBounds(1,1,wd-2,hd-2);
end;
Procedure TW3Scrollbox.HandleScroll(sender:TObject);
Begin
FContent.ScrollInfo.ScrollTo(FHScroll.Position,FVScroll.Position);
end;
Procedure TW3Scrollbox.Update;
begin
BeginUpdate;
try
if FContent.ScrollInfo.ScrollWidth>FContent.ClientWidth then
Begin
FHScroll.Total:=FContent.ScrollInfo.ScrollWidth;
FHScroll.PageSize:=FContent.ClientWidth;
If not FHScroll.Visible then
Begin
FHScroll.Visible:=True;
self.SetWasSized;
end;
end;
if FContent.ScrollInfo.ScrollHeight>FContent.clientHeight then
Begin
FVScroll.Total:=FContent.ScrollInfo.ScrollHeight;
FVScroll.PageSize:=FContent.clientHeight;
If not FVScroll.Visible then
Begin
FVScroll.Visible:=True;
SetWasSized;
end;
end;
FContent.SendToBack;
finally
EndUpdate;
end;
end;
end.
Using the scrollbox (without the designer) is straight forward. In this case I added a Beatles poster as a resource, inserted an image into the content of the scrollbox – and used the image as a background (as opposed to the image itself. Neat trick!).
FBox:=TW3Scrollbox.Create(self);
FBox.SetBounds(10,200,600,500);
FBox.StyleClass:='TW3CustomControl';
FTest:=TW3Image.Create(FBox.Content);
FTest.Background.FromURL('res/beatles.jpg');
FTest.setBounds(0,0,1644 * 2, 1086 * 2);
