B4J Question Set canvas borders when resize it, without clear current content

max123

Well-Known Member
Licensed User
Longtime User
I all,

I admit I've done much more difficult things, but I'm stuck here.

I need to make sure that when resizing the form (so even the Canvas that fit it), the 2 pixel wide red border is always shown, as in the first image attached, but without deleting the current content.

I've tried various ways but without success.

Does anyone understand how to do it?

Here is my simple code
Note, here the mainPnl is a panel on the designer, it fits the window and canvas is initialized to it.

Many thanks for help.

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
 
    Dim cvs As B4XCanvas
    Private mainPnl As Pane
    Private fnt As Font
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
 
    fnt = fx.CreateFont("Monospace",12,True,False)
    cvs.Initialize(mainPnl)
    Clear
    cvs.DrawText("I have to stay here when the canvas changes size", 50, 200, fx.CreateFont("Monospace",18,True,False), xui.Color_Cyan, "LEFT")
End Sub

Sub MainForm_Resize (Width As Double, Height As Double)
    cvs.Resize(Width,Height)
    ShowScreenDimensions
    ShowBorders
End Sub

Sub Clear
    Dim rect As B4XRect
    rect.Initialize(0, 0, cvs.TargetRect.Width, cvs.TargetRect.Height)
    cvs.DrawRect(rect, xui.Color_Black, True, 1)
End Sub

Sub ShowScreenDimensions
    Dim rect As B4XRect
    rect.Initialize(1, 1, 130dip, 80dip)
    cvs.DrawRect(rect, xui.Color_Black, True, 1)
 
    cvs.DrawText("DPI:    " & (96*Density), 20dip, 25dip, fnt, xui.Color_White, "LEFT")
    cvs.DrawText("Scale:  " & Density, 20dip, 38dip, fnt, xui.Color_White, "LEFT")
    cvs.DrawText("Width:  " & mainPnl.Width,20dip, 51dip, fnt, xui.Color_Yellow, "LEFT")
    cvs.DrawText("Height: " & mainPnl.Height,20dip, 64dip, fnt, xui.Color_Yellow, "LEFT")
    cvs.Invalidate
End Sub

Sub ShowBorders
'    Clear
    Dim rect As B4XRect
    rect.Initialize(1, 1, 1+cvs.TargetRect.Width-2, 1+cvs.TargetRect.Height-2)
'    cvs.DrawRect(rect, xui.Color_Black,False,2)
    cvs.DrawRect(rect, xui.Color_Red,False,2)
    cvs.Invalidate
End Sub
 

Attachments

  • Screenshot 2025-04-17 145345.png
    Screenshot 2025-04-17 145345.png
    28.1 KB · Views: 130
  • Screenshot 2025-04-17 145442.png
    Screenshot 2025-04-17 145442.png
    29.8 KB · Views: 123
Last edited:

klaus

Expert
Licensed User
Longtime User
In my last project do not resize cvsDrawing.
Draw a few lines and decrease and increase the form, the drawn lines remain.

B4X:
Sub MainForm_Resize (Width As Double, Height As Double)   
    cvsBackground.Resize(Width,Height)
    cvsInfo.Resize(Width,Height)
'    cvsDrawing.Resize(Width,Height)
    cvsCursor.Resize(Width,Height)
    
    ShowBorders
    ShowScreenDimensions
End Sub
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
I will try it, Many Thanks @klaus

EDIT: I tried it and seem to work as expected, do not resize the drawing canvas may do the trick ? Many Thanks, today I learned something else about B4X.

To @stevel05, Many Thanks, I will try now your last project to see the difference and compare them with @klaus code.
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
I've tried both codes and both seem to work the same way, but not the way I expected.
Both use 4 canvas and 4 panels.
On both I have to increase the red border line width that now seem to be 1 pixel smaller that my original project.
to change them I just had to modify this line as follow in the ShowBorders sub:
B4X:
rect.Initialize(2, 2, 2+cvs2.TargetRect.Width-4, 1+cvs2.TargetRect.Height-4)

@klaus, on your code I only can draw lines on the original canvas size even if I resize it bigger, because the cvsDrawing.Resize(Width,Height) commented.

I added my simplified version of @stevel05 code.

@klaus code
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
 
    Private cvsBackground As B4XCanvas  ' Background
    Private cvsInfo As B4XCanvas  ' Infos
    Private cvsDrawing As B4XCanvas  ' Drawing
    Private cvsCursor As B4XCanvas
 
    Private pnlBackground, pnlInfo, pnlDrawing, pnlCursor As B4XView
    Private fnt As Font
 
    Private x1, y1, x2, y2 As Int
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
 
    fnt = fx.CreateFont("Monospace",12,True,False)
 
    cvsBackground.Initialize(pnlBackground)
    cvsInfo.Initialize(pnlInfo)
    cvsDrawing.Initialize(pnlDrawing)
    cvsCursor.Initialize(pnlCursor)
 
    cvsDrawing.DrawText("I have to stay here when the canvas change size", 40, 200, fx.CreateFont("Monospace",18,True,False), xui.Color_Cyan, "LEFT")
End Sub

Sub MainForm_Resize (Width As Double, Height As Double)
    cvsBackground.Resize(Width,Height)
    cvsInfo.Resize(Width,Height)
'    cvsDrawing.Resize(Width,Height)
    cvsCursor.Resize(Width,Height)
 
    ShowBorders
    ShowScreenDimensions
End Sub

Private Sub pnlCursor_Touch (Action As Int, X As Float, Y As Float)
    Select Action
        Case pnlCursor.TOUCH_ACTION_DOWN
            x1 = X
            y1 = Y
        Case pnlCursor.TOUCH_ACTION_MOVE
            cvsCursor.ClearRect(cvsCursor.TargetRect)
            x2 = X
            y2 = Y
            cvsCursor.DrawLine(x1, y1, x2, y2, xui.Color_Red, 1dip)
        Case pnlCursor.TOUCH_ACTION_UP
            cvsCursor.ClearRect(cvsCursor.TargetRect)
            cvsDrawing.DrawLine(x1, y1, x2, y2, xui.Color_Blue, 1dip)
    End Select
End Sub

Sub ShowScreenDimensions
    cvsInfo.ClearRect(cvsInfo.TargetRect) 'sets the background transparent
    cvsInfo.DrawText("DPI:    " & (96*Density), 20dip, 25dip, fnt, xui.Color_White, "LEFT")
    cvsInfo.DrawText("Scale:  " & Density, 20dip, 38dip, fnt, xui.Color_White, "LEFT")
    cvsInfo.DrawText("Width:  " & pnlBackground.Width,20dip, 51dip, fnt, xui.Color_Yellow, "LEFT")
    cvsInfo.DrawText("Height: " & pnlBackground.Height,20dip, 64dip, fnt, xui.Color_Yellow, "LEFT")
    cvsInfo.Invalidate
End Sub

Sub ShowBorders
    cvsBackground.DrawRect(cvsBackground.TargetRect, xui.Color_Black, True, 1)
    Dim rect As B4XRect
    rect.Initialize(1, 1, 1 + cvsBackground.TargetRect.Width - 2, 1 + cvsBackground.TargetRect.Height - 2)
    cvsBackground.DrawRect(rect, xui.Color_Red,False,2)
    cvsBackground.Invalidate
End Sub

@stevel05 code:
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
 
    Dim cvs1,cvs2,cvs3,cvs4 As B4XCanvas
    Private mainPnl As Pane
    Private fnt As Font
    Private Pane1,  Pane2, Pane3, Pane4 As Pane
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
 
    fnt = fx.CreateFont("Monospace",12,True,False)
    cvs1.Initialize(Pane1)
    cvs2.Initialize(Pane2)
    cvs3.Initialize(Pane3)
    cvs4.Initialize(Pane4)
End Sub

Sub MainForm_Resize (Width As Double, Height As Double)
    cvs1.Resize(Width,Height)
    cvs2.Resize(Width,Height)
    cvs3.Resize(Width,Height)
    cvs4.Resize(Width,Height)
 
    DrawBackground
    ShowBorders
    ShowScreenDimensions
    DrawText
End Sub

Sub Clear(Cvs As Int)
    Select Cvs
        Case 1
            cvs1.ClearRect(cvs1.TargetRect)
        Case 2
            cvs2.ClearRect(cvs2.TargetRect)
        Case 3
            cvs3.ClearRect(cvs3.TargetRect)
        Case 4
            cvs4.ClearRect(cvs4.TargetRect)
    End Select
End Sub

Sub DrawBackground
    Clear(1)
    cvs1.DrawRect(cvs1.TargetRect,xui.Color_Black,True,0)
End Sub

Sub ShowBorders
    Clear(2)
    Dim rect As B4XRect
    rect.Initialize(1, 1, 1+cvs2.TargetRect.Width-2, 1+cvs2.TargetRect.Height-2)
    cvs2.DrawRect(rect, xui.Color_Red,False,2)
    cvs2.Invalidate
End Sub

Sub ShowScreenDimensions
    Clear(3)
    cvs3.DrawText("DPI:    " & (96*Density), 20dip, 25dip, fnt, xui.Color_White, "LEFT")
    cvs3.DrawText("Scale:  " & Density, 20dip, 38dip, fnt, xui.Color_White, "LEFT")
    cvs3.DrawText("Width:  " & Round(mainPnl.Width),20dip, 51dip, fnt, xui.Color_Yellow, "LEFT")
    cvs3.DrawText("Height: " & Round(mainPnl.Height),20dip, 64dip, fnt, xui.Color_Yellow, "LEFT")
    cvs3.Invalidate
End Sub

Private Sub DrawText
    Clear(4)
    cvs4.DrawText("I have to stay here when the canvas changes size", 50, 200, fx.CreateFont("Monospace",18,True,False), xui.Color_Cyan, "LEFT")
End Sub

@max123 code:
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
 
    Private PaneCursor, PaneBackground, PaneInfo, PaneDrawing As Pane
    Private cvsCursor, cvsBackground, cvsInfo, cvsDrawing As B4XCanvas

    Private fnt As Font
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
 
    fnt = fx.CreateFont("Monospace",12,True,False)
    cvsCursor.Initialize(PaneCursor)
    cvsBackground.Initialize(PaneBackground)
    cvsInfo.Initialize(PaneInfo)
    cvsDrawing.Initialize(PaneDrawing)
End Sub

Sub MainForm_Resize (Width As Double, Height As Double)
    cvsCursor.Resize(Width,Height)
    cvsBackground.Resize(Width,Height)
    cvsInfo.Resize(Width,Height)
    cvsDrawing.Resize(Width,Height)
     
    DrawBackground
    ShowBorders
    ShowScreenDimensions
    DrawText
End Sub

Sub Clear(Cvs As B4XCanvas)
    Cvs.ClearRect(Cvs.TargetRect)
End Sub

Sub DrawBackground
    Clear(cvsCursor)
    cvsCursor.DrawRect(cvsCursor.TargetRect,xui.Color_Black,True,0)
End Sub

Sub ShowBorders
    Clear(cvsBackground)
    Dim rect As B4XRect
    rect.Initialize(2, 2, 2+cvsBackground.TargetRect.Width-4, 1+cvsBackground.TargetRect.Height-4)
    cvsBackground.DrawRect(rect, xui.Color_Red,False,2)
    cvsBackground.Invalidate
End Sub

Sub ShowScreenDimensions
    Clear(cvsInfo)
    cvsInfo.DrawText("DPI:    " & (96*Density), 20dip, 25dip, fnt, xui.Color_White, "LEFT")
    cvsInfo.DrawText("Scale:  " & Density, 20dip, 38dip, fnt, xui.Color_White, "LEFT")
    cvsInfo.DrawText("Width:  " & Round(PaneInfo.Width),20dip, 51dip, fnt, xui.Color_Yellow, "LEFT")
    cvsInfo.DrawText("Height: " & Round(PaneInfo.Height),20dip, 64dip, fnt, xui.Color_Yellow, "LEFT")
    cvsInfo.Invalidate
End Sub

Private Sub DrawText
    Clear(cvsDrawing)
    cvsDrawing.DrawText("I have to stay here when the canvas changes size", 50, 200, fx.CreateFont("Monospace",18,True,False), xui.Color_Cyan, "LEFT")
End Sub
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
I've found now that @stevel05 code and my simplified version, do not remove the text, because just print out it on the resize sub, if I comment the line and put DrawText on the form create sub, it will be cleared when resize the canvas to a small size, so the @klaus solution result to be the only working but is not usable on my situation, because the drawing size have to be updated or is not possible to draw outside it but only on the original size.

At the moment I don't see any working solution.
 
Last edited:
Upvote 0

stevel05

Expert
Licensed User
Longtime User
If you stop the resizing of the canvas that contains the text, Draw it once in AppStart, and don't redraw the text on resize, then it should work as you expect. I don't understand why you wouldn't want it redrawn.

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
 
    Dim cvs1,cvs2,cvs3,cvs4 As B4XCanvas
    Private mainPnl As Pane
    Private fnt As Font
    Private Pane1,  Pane2, Pane3, Pane4 As Pane
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
 
    fnt = fx.CreateFont("Monospace",12,True,False)
    cvs1.Initialize(Pane1)
    cvs2.Initialize(Pane2)
    cvs3.Initialize(Pane3)
    cvs4.Initialize(Pane4)
    DrawText
End Sub

Sub MainForm_Resize (Width As Double, Height As Double)
    cvs1.Resize(Width,Height)
    cvs2.Resize(Width,Height)
    cvs3.Resize(Width,Height)
    'cvs4.Resize(Width,Height)
 
    DrawBackground
    ShowBorders
    ShowScreenDimensions
    'DrawText
End Sub

Sub Clear(Cvs As Int)
    Select Cvs
        Case 1
            cvs1.ClearRect(cvs1.TargetRect)
        Case 2
            cvs2.ClearRect(cvs2.TargetRect)
        Case 3
            cvs3.ClearRect(cvs3.TargetRect)
        Case 4
            cvs4.ClearRect(cvs4.TargetRect)
    End Select
End Sub

Sub DrawBackground
    Clear(1)
    cvs1.DrawRect(cvs1.TargetRect,xui.Color_Black,True,0)
    cvs1.Invalidate
End Sub

Sub ShowBorders
    Clear(2)
    Dim rect As B4XRect
    rect.Initialize(1, 1, 1+cvs2.TargetRect.Width-2, 1+cvs2.TargetRect.Height-2)
    cvs2.DrawRect(rect, xui.Color_Red,False,2)
    cvs2.Invalidate
End Sub

Sub ShowScreenDimensions
    Clear(3)
    cvs3.DrawText("DPI:    " & (96*Density), 20dip, 25dip, fnt, xui.Color_White, "LEFT")
    cvs3.DrawText("Scale:  " & Density, 20dip, 38dip, fnt, xui.Color_White, "LEFT")
    cvs3.DrawText("Width:  " & Round(mainPnl.Width),20dip, 51dip, fnt, xui.Color_Yellow, "LEFT")
    cvs3.DrawText("Height: " & Round(mainPnl.Height),20dip, 64dip, fnt, xui.Color_Yellow, "LEFT")
    cvs3.Invalidate
End Sub

Private Sub DrawText
    Clear(4)
    cvs4.DrawText("I have to stay here when the canvas changes size", 50, 200, fx.CreateFont("Monospace",18,True,False), xui.Color_Cyan, "LEFT")
    cvs4.Invalidate
End Sub
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
If you stop the resizing of the canvas that contains the text, Draw it once in AppStart, and don't redraw the text on resize, then it should work as you expect. I don't understand why you wouldn't want it redrawn.
I search a way that if the form size is small, if the remote microcontroller draw on a non visible area, when I resize the form bigger I can see here what the microcontroller drawed. Probably I have to place a bigger canvas respect the form size in the resize event as follow:
B4X:
cvs.Resize(Width*4,Height*4)
Can the canvas be bigger than the form ? I think yes, right ? To be resized is the pane where the form is initialized.

And I even search a way that if I resize the form smaller, the canvas content is not deleted by form borders, so they should be bigger and just covered by the form.

Or may I just have to put a big canvas, like 4k resolution and do not resize it at all when resize the form ?
 
Last edited:
Upvote 0

stevel05

Expert
Licensed User
Longtime User
It looks like you can, I did this in the MainForm_resize sub:

B4X:
    cvs4.Resize(2000,2000)    
    Log(Pane4.Width)
    Log(cvs4.TargetRect)
Pane size changes, but the target rect doesn't.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
I can't find the connection between panel size and canvas TargetRect size, that's why I can't figure it out...
I just have to put a panel and then resize the canvas on it bigger or just a fixed size that is a max resolution ?
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Using your advices, this code now works and I can now draw even when resize the form bigger, depending on the MaxResolutionX and MaxResolutionY
Because the canvas is not resized it even mantain the drawings if I resize the form smaller.
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
   
    Private cvsBackground As B4XCanvas  ' Background
    Private cvsInfo As B4XCanvas  ' Infos
    Private cvsDrawing As B4XCanvas  ' Drawing
    Private cvsCursor As B4XCanvas
   
    Private pnlBackground, pnlInfo, pnlDrawing, pnlCursor As B4XView
    Private fnt As Font
   
    Private x1, y1, x2, y2 As Int
   
    Private MaxResolutionX As Int = 1920
    Private MaxResolutionY As Int = 1200
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
   
    fnt = fx.CreateFont("Monospace",12,True,False)
   
    cvsBackground.Initialize(pnlBackground)
    cvsInfo.Initialize(pnlInfo)
    cvsDrawing.Initialize(pnlDrawing)
    cvsCursor.Initialize(pnlCursor)
       
    cvsDrawing.DrawText("I have to stay here when the canvas change size", 40, 200, fx.CreateFont("Monospace",18,True,False), xui.Color_Cyan, "LEFT")
End Sub

Sub MainForm_Resize (Width As Double, Height As Double)
    cvsBackground.Resize(Width,Height)
    cvsInfo.Resize(Width,Height)
    cvsCursor.Resize(Width,Height)
   
    cvsDrawing.Resize(MaxResolutionX, MaxResolutionY)
    Log(pnlDrawing.Width & "," & pnlDrawing.Height)
    Log(cvsDrawing.TargetRect)
   
    ShowBorders
    ShowScreenDimensions
End Sub

Private Sub pnlCursor_Touch (Action As Int, X As Float, Y As Float)
    Select Action
        Case pnlCursor.TOUCH_ACTION_DOWN
            x1 = X
            y1 = Y
        Case pnlCursor.TOUCH_ACTION_MOVE
            cvsCursor.ClearRect(cvsCursor.TargetRect)
            x2 = X
            y2 = Y
            cvsCursor.DrawLine(x1, y1, x2, y2, xui.Color_Red, 1dip)
        Case pnlCursor.TOUCH_ACTION_UP
            cvsCursor.ClearRect(cvsCursor.TargetRect)
            cvsDrawing.DrawLine(x1, y1, x2, y2, xui.Color_Blue, 1dip)
    End Select
End Sub

Sub Clear(Cvs As B4XCanvas)
    Cvs.ClearRect(Cvs.TargetRect)
End Sub

Sub DrawBackground
    Clear(cvsBackground)
    cvsBackground.DrawRect(cvsBackground.TargetRect,xui.Color_Black,True,0)
End Sub

Sub ShowScreenDimensions   
    Clear(cvsInfo) 'sets the background transparent
    cvsInfo.DrawText("DPI:    " & (96*Density), 20dip, 25dip, fnt, xui.Color_White, "LEFT")
    cvsInfo.DrawText("Scale:  " & Density, 20dip, 38dip, fnt, xui.Color_White, "LEFT")
    cvsInfo.DrawText("Width:  " & pnlBackground.Width,20dip, 51dip, fnt, xui.Color_Yellow, "LEFT")
    cvsInfo.DrawText("Height: " & pnlBackground.Height,20dip, 64dip, fnt, xui.Color_Yellow, "LEFT")
    cvsInfo.Invalidate
End Sub

Sub ShowBorders
    DrawBackground   ' May use Clear(cvsBackground) dependig on what you need, to not always draw the background black
    Dim rect As B4XRect
    rect.Initialize(2, 2, 2 + cvsBackground.TargetRect.Width - 4, 1 + cvsBackground.TargetRect.Height - 3)
    cvsBackground.DrawRect(rect, xui.Color_Red,False,2)
    cvsBackground.Invalidate
End Sub
 
Last edited:
Upvote 0

klaus

Expert
Licensed User
Longtime User
This is what i wanted to show you in my last post
I search a way that if the form size is small, if the remote microcontroller draw on a non visible area, when I resize the form bigger I can see here what the microcontroller drawed.

I still do not understand what exactly iyour goal is ?
Do you need the from resizing, do you want it or do you have to consider it because, with B4J, the user can modify the size of the screen ?
Now, in your last code i see these two variables: MaxResolutionX and MaxResolutionY. They were not in your previous code.
Some more questions to better understand.
- What do these variables represent ?
- What information does the microcontroller send ?
- Is your project multi-platform ? In that case you might create a B4XPages project.

If I understand your last code correctly, the microcontroller sends drawing information to draw onto cvsDrawing which is supposed to have a given size defined by MaxResolutionX and MaxResolutionY.
How does the microcontroller get or know the screen size he has to draw on ?
Is the screen size given to it by MaxResolutionX and MaxResolutionY and how are their values defined ?
If MaxResolutionX and MaxResolutionY are the screen dimensions, are these the size of the form when the program is launched ?
If yes, do you really need the resizing in B4J ?
You could bloc the screen resizing with MainForm.SetWindowSizeLimits(MaxResolutionX, MaxResolutionY, MaxResolutionX, MaxResolutionY).

Coming back to your code in post #29.
MaxResolutionX and MaxResolutionY are given.
You can remove the anchors of pnlDrawing in the Designer and resize pnlDrawing directly in AppStart and initialize cvsDrawing to pnlDrawing.
The size of cvsDrawing will directly be the size of pnlDrawing with MaxResolutionX and MaxResolutionY.
Then, no need to resize those.
If my assumtions are correct, you do not need pnlCursoe / csvCursor because i added those to show some drawings dynamically, which is not your case.
And you could also draw the information text directly onto the background because this one is redrawn at every resizing.
And if you bloc the resizing of the form you can forget most all this stuff.
 

Attachments

  • CanvasBorders5.zip
    2.5 KB · Views: 70
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Hi @klaus, many thanks for your interest. 👍
I still do not understand what exactly your goal is ?
I'm sorry, but english is not my main language and this is not even simple to explain in my original language. I will try to reply to your questions.
Do you need the from resizing, do you want it or do you have to consider it because, with B4J, the user can modify the size of the screen ?
I need the form resize, yes, the form does not have to be a fixed size. Actually in my app, the user can resize the form and the microcontroller always know a new size, it happen over wifi in a transparent way for the user. On microcontroller side the user can use:
C++:
unsigned int W = tft.width();
unsigned int H = tft.height();
These will return the remote screen size in a transparent way, if the screen size changes, by calling these two lines, the new will be returned.
Note that actually the screen size is the same as the form size - 22 pixels (in height) that is the top form menù bar. Actually when I resize the form, the canvas will resize with it.
Now, in your last code i see these two variables: MaxResolutionX and MaxResolutionY. They were not in your previous code.
Some more questions to better understand.
- What do these variables represent ?
- What information does the microcontroller send ?
- Is your project multi-platform ? In that case you might create a B4XPages project.
- MaxResolutionX and MaxResolutionY are only in my small test project, not in my app. In this case they rappresent the maximum resolution (horizontal and vertical) the screen can be. Substantially in the resize event I use it to get the cvsDrawing TargetRect to not resize. Outside these is not possible to draw because is the canvas size.
- The microcontroller send commands over wifi, every command match the B4X counterpart, even all arguments are passed, to explain better, this is the function that draw a rectangle from microcontroller side:
C++:
void VirtualDisplay::drawRect(int X, int Y, int Width, int Height, int Color, bool Fill, float LineWidth) {
  String root;
  root.reserve(200);
 
  root = "cmd" + CM + "DrawRect" + CM;
  root += (String)X + CM;
  root += (String)Y + CM;
  root += (String)Width + CM;
  root += (String)Height + CM;
  root += (String)Color + CM;
  root += ((Fill == true) ? "true" : "false") + CM;
  root += (String)LineWidth;
 
  SendCmd(root);
}
note thar CM is static string variable and it is just the argument separator inside a sent message.
And then on B4X side I have a big Select Case that accepts and parse all commands and arguments, in a case to draw a rect:
B4X:
' RECTANGLE
Case "DrawRect"
    Dim rect As B4XRect
    rect.Initialize(Args.Get(0)+0.5, Args.Get(1)+0.5, (Args.Get(0)+Args.Get(2)+0.5), (Args.Get(1)+Args.Get(3)+0.5))
    cvs.DrawRect(rect, Args.Get(4), Args.Get(5), Args.Get(6))
    If AutoRepaint Then cvs.Invalidate
Substantially they are true function calls with all arguments passed, but over network. Some functions will request a parameter that the remote then return, so it is even possible to read, eg. the tft.width() is an example to get the screen width.
- No, my project is not multiplatform, because too much differences between Android an Desktop, I decided to make it separate, so I have two different VirtualDisplay projects, one for B4A and one for B4J, this is not a problem, it is my decision, I even decided to mantain separately because the Desktop app will be released free and the Android will be paid, so better to mantain separately on my opinion. But note that both projects already are B4XPage based.
If I understand your last code correctly, the microcontroller sends drawing information to draw onto cvsDrawing which is supposed to have a given size defined by MaxResolutionX and MaxResolutionY.
This is only on my test project, MaxResolutionX and MaxResolutionY do not exist in my actual apps. On Android the resolution is fixed, is the device full screen resolution, I still to make something different to desktop side, so I want the user can resize the form (not necessarialy the canvas target rect, to avoid strange things may it is better to resize to the max screen resolution that may be 1080p or 4k.
This way may I can get screen dimensions just by form size (not canvas target rect) and mantain a big canvas on it, in a way that if the microcontroller want to draw inside the visible form can use tft.width() and tft.height(), but if it draw outside the form size, when the user resize the form bigger, here can see drawings because a big canvas retained it, even if covered by the form.
How does the microcontroller get or know the screen size he has to draw on ?
Is the screen size given to it by MaxResolutionX and MaxResolutionY and how are their values defined ?
I already explained these ....
- If MaxResolutionX and MaxResolutionY are the screen dimensions, are these the size of the form when the program is launched ?
- If yes, do you really need the resizing in B4J ?
- You could bloc the screen resizing with MainForm.SetWindowSizeLimits(MaxResolutionX, MaxResolutionY, MaxResolutionX, MaxResolutionY).
- No the form is small at startup, the user can decide to resize it smaller or bigger, minimize or maximize it.
- Absolutely yes, the form should be resizable
- Absolutely no, the form should be resizable

I hope I explained a bit better, if you have other questions I will reply.
PS: I not yet tried your last project, I will try it when have some time. The main problem is 🐣🐥🐤 o_O

Thanks
 
Last edited:
Upvote 0

klaus

Expert
Licensed User
Longtime User
Thank you for the detailed explanations.
When i try to help i always want to understand the whole problem or situation and try to find a solution for that problem and not only answer a question.
Quite often, an answer to just a question does not solve the problem.
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Many thanks to you @klaus and even @stevel05, I admit that hearing these words of yours gives me a lot of joy, especially at the gates of Easter, you have always been true Gurus of B4X and I admire you very much for the great contribution you have given that more, you add new things that you have built together with @Erel to create a great and powerful development system. I remember that more than 10 years ago, when I was ready to use B4X the first times (with B4A), you were already doing things that were unreachable for me, and you had already helped many people to appreciate B4X. But now I studied and always used all B4X products (except B4i) so now I developed some things I had in mind for years but very difficult to me in past.

On this direction I recently contributed to B4X with my WebGL library and other small libraries.

Since I saw you both curious about the work I am doing with B4X and ESP8266/ESP32/RP2040/Arduino microcontrollers, and since the VirtualDisplay library written in C++ for Arduino environment will be completely opensource on github next, and also the VirtualDisplay desktop app developed with B4J (not the code but the compiled app) will be free, I decided that I will post here the header file .h of my library so that you can understand what I am trying to do and see all the library commands the library have to iteract with B4X side over network.

Don't be offended @Erel if I post a file not related to B4X but to C++, in that case just let me know and I'll remove it, in any case the library will be available later on github.

If someone is interested (but have knowledge) to convert this library to B4R I can send the full library .h and .cpp files.

My intent, once again at this point, is to make you understand what I'm trying to do, and maybe some of you can give me advice and ideas, I'm always available to evaluate any ideas.

Note that I want release next the VirtuaDisplay Arduino library opensource, but I want to sell on Google Play Store in future the Android counterpart of desktop VirtualDisplay app, it is already developed and working. On C++ side the same codes (sketchs) compiles for now on ESP8266 and ESP32 (in a transparent way) without any modification at all. The library come with approximately 30 demos.

Initially I started to make it possible to have a sort of remote display over wifi on the microcontroller side, then when everything worked well and implemented all the B4X B4XCanvas commands on microcontroller side, to work like all hardware TFT libraries (but remotely), after several months, I started to add particular commands in order to make the microcontroller interact with B4X. In this sense for example the micro can not only use the Canvas, but can do other useful things, such as drawing buttons, sliders, meterbars, leds and more all with feedback, so if the micro will draw eg. 10 buttons, each have it's index, when the user press a button, the micro know what button is pressed by it's index, eg. button[index].value will be 0 or 1. the same things for other controllers like sliders, eg.the micro can draw 10 sliders (customized) and when the user move some sliders, the micro know what slider is moved and it's value. The library for now support max 64 controllers of each type.

After this, on Android, the micro can read all sensors, eg. the accelerometer, gyroscope, e much more, even the GPS, even the battery state.

The micro can use these sensors the same way that have real hardware sensors attached to it, but even works over wifi, non only local, even over internet.
So eg, ESP32 can draw on a remote phone or tablet or PC, in local network or over internet, before of all it know the sceen size of remote device, then can draw everything, read all devices sensors (if it is Android device) and use them to do some other things, like control a motor, a servo and much more.

The same inversed is true, eg. ESP32 can have much more sensors attached, and it print out the values on a remote device screen, or can draw a graph, it even can open web pages, eg. place all sensor values to a Google Chart and display to a remote device the iteractive chart.

As explained, the library iteract with B4X, eg. I even impemented some methods relative to some B4X parts, eg, on the micro there are commands like tft.WriteFileText that from B4X side is recognized like File.WriteString, so the micro can pass just a file name and a file on remote device will be created with the passed text. Note that the text length is limited around 1000 characters only, but append can be used, so add more to existing files.

The library can even create CSV files on remote devices, eg, add headers and datas, can be used as data logger and much more.
Note that the library even have the command tft.deleteFile(FileName) to delete remote unused files.

These are all a small part of what this library can do.
This has much more, if you are curious take a look on it's header file I attached, even if you don't use any microcontroller at all.

I wish you both a happy Easter and thank you very much for your appreciated help that you have given me. I also accept ideas on my app, which perhaps I have missed but are clearer and more evident for B4X Gurus like you.

Bye and thanks
 

Attachments

  • VirtualDisplay.zip
    5.7 KB · Views: 66
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
You seem to be doing a combination of remote control, designer, simulator, and universal hardware supporting system with multiple functions.Perhaps we call it a low code platform?
It is a small framework.

In theory I can implement all B4X core and some libraries remotely, I already call all functions passing all arguments (but not local, over network) but the microcontroller have limted memory, that even is needed for other operations, so at this moment I only implemented what I retained are most important in my opinion.

If you see my library header, there are some B4X parts and libraries like eg. TTS on Android I already implemented it all, see 'speak' commands, this way the microcontroller can speak on remote device in a very simple way, just have to do something lke this:
C++:
tft.speak("Hello World");
It can even decide the language, pitch and more.
After this the remote device will speak Hello World, on local device or over internet do not matter, just use a private or public IP address or a DDNS service.

I implemented some other commands like:
C++:
tft.writeTextFile("fileName.txt", "Hello World");
will create on a remote device a file called fileName.txt and write to it Hello World.
C++:
tft.deleteFile("fileName.txt");
will delete it.

You see 'tft' to point commands, but is not right it is only a TFT, not only the canvas is involved.
 
Last edited:
Upvote 0
Top