B4J Tutorial Canvas inside a ScrollPane (Beginner-Tutorial)

As my research in the forum for this combination needed 2 hours, I offer here a tutorial for future newbies not to waste such a long time for a actually easy-to-solve problem.

A window with a Scroll-Pane and inside a graphics that can be scrolled horizontally:
1603459912512.png



The use of the Scroll-Pane in B4J is a little bit trickys, because you cannot add children in the designer. So you have to create a second layout and then load this at runtime:
First main layout holds your views and only the ScrollPane without content:
1603458126476.png

Define here the outer dimensions of the graphic. Later you will get Scrollbars to move the inner graphic. We save the Layout as "Layout1"

Second layout contains only a canvas directly (and full) on the main form:

1603458246423.png

Define the anchors to fit the form completely. We save the layout as "Inner"

Now the code:


B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
    Private Scroll As ScrollPane
    Private Canvas As Canvas
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
    Scroll.LoadLayout("Inner",1000,200)
    DrawGraph
End Sub
This is very normal: MainForm load the first layout. Then you can load the inner layout to Scroll. Here you now should define the inner size (here: 1000x200pix) of the canvas. As I could read in the forum it should not adjusted a second time. So set the values and do not change them anymore in your code.

Now you can paint on the canvas as you like. Here it is a random graphics:
B4X:
Sub DrawGraph
    Dim Random, High, Low As Int
    Canvas.DrawRect(0,0,1000,200,fx.colors.black,True, 0 )
    For i=0 To 800 Step 2
        Random =Rnd(-50,50)
        If Random<0 Then
            High=100+Random
            Low=-Random
        Else
            High=100
            Low=Random
        End If
        Canvas.DrawRect(i,High,2,Low,fx.Colors.Yellow ,True,0)
    Next
End Sub
In the description of DrawRect we can read the parameters: X, Y, Width and Height are easy to understand, But the fifth parameter is Paint As javafx.scene.paint.Paint...
1603458996897.png


But you simply can define a JFX-Color here:
B4X:
Canvas.DrawRect(0,0,1000,200,fx.colors.black,True, 0 )

That's all. Now you can call the Sub as often as you want. Press the button to draw a complete different graph. The first Canvas.DrawRect works like an CLS (here in black). Then you can combine as many drawing commands as you like. You do not have to care about resfreshing, etc...

Here is the complete project as ZIP:
 

Attachments

  • CanvasTest.zip
    3 KB · Views: 138
  • 1603459845534.png
    1603459845534.png
    19.8 KB · Views: 78
Last edited:

klaus

Expert
Licensed User
It is possible to add Nodes in a ScrollPane with the trick below:
Load an empty layout, this converts the ScrollPane.InnerPane to a Pane.
Define a Pane object, InnerPane and set it to ScrollPane.InnerPane.
Then you can AddNodes.
This can be useful if you want to add Nodes at run time.

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
    Private Scroll As ScrollPane
    Private Canvas As Canvas
    Private InnerPane As Pane
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
    Scroll.LoadLayout("Dummy",1000,200)
    InnerPane = Scroll.InnerNode
    Canvas.Initialize("Canvas")
    InnerPane.AddNode(Canvas, 0, 0, InnerPane.PrefWidth, InnerPane.PrefHeight)
    DrawGraph
End Sub
 

kimstudio

Member
As I could read in the forum it should not adjusted a second time. So set the values and do not change them anymore in your code.

Is it possible to dynamically remove/add canvas to the scrollview if we can't adjust the size on runtime? considering if we want to plot audio waves with different length.
 

kimstudio

Member
Thanks Midimaster and klaus, this is useful for me so I tried the following code and it works.
The aim is to able to load different 1d data files and plot it in same scrollable canvas. I am not sure about multiple create/add same canvas problem so I add some protections like InnerPane.RemoveAllNodes, is this necessary/the correct way?

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI 
    Private ScrollPane1 As ScrollPane
    Private cv As Canvas
    Private InnerPane As Pane
    
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
End Sub

Sub Button1_Click
    ScrollPane1.LoadLayout("dummy",1000,1000)
    InnerPane = ScrollPane1.InnerNode
    InnerPane.RemoveAllNodes
    If Not(cv.IsInitialized) Then cv.Initialize("Canvas")
    InnerPane.AddNode(cv, 0, 0, InnerPane.PrefWidth, InnerPane.PrefHeight)
    DrawGraph
End Sub

Sub Button2_Click
    ScrollPane1.LoadLayout("dummy",2000,2000)
    InnerPane = ScrollPane1.InnerNode
    InnerPane.RemoveAllNodes
    If Not(cv.IsInitialized) Then cv.Initialize("Canvas")
    InnerPane.AddNode(cv, 0, 0, InnerPane.PrefWidth, InnerPane.PrefHeight)
    DrawGraph
End Sub

Sub DrawGraph
    Dim y,r,s As Int
    If Not(cv.IsInitialized) Then Return
    cv.DrawRect(0,0,cv.Width,cv.Height,fx.colors.black,True, 0 )
    y = cv.Height/2
    s = 5
    For i= s To cv.Width-1 Step s
        r =Rnd(-400,400)
        cv.DrawLine(i-s,y,i,cv.Height/2+r,fx.Colors.Yellow,2.2)
        y = cv.Height/2+r
    Next
    cv.DrawLine(0,cv.Height/2,cv.Width-1,cv.Height/2,fx.Colors.Red,2.2)
End Sub

Clipboard01.png
 
Top