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);