B4J Question save load form position

Mikelgiles

Active Member
Licensed User
Longtime User
When closing my app I need to save the form position and when running the app use that saved position. ie, remember where the form is located on the screen. So far I have not even figured out how to set the position by code. Any help appreciated.
 

EnriqueGonzalez

Well-Known Member
Licensed User
Longtime User
Ey mikel

To get/set the form position:

B4X:
Mainform.left
Mainform.top

There is an event for FORM_CLOSING, here you can save the form position and load it on creation.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
See this example: depends on JavaObject and jRandomAccessFile libs.
B4X:
Sub Process_Globals
   Private fx As JFX
   Private MainForm As Form
   Private SettingsFolder As String
   Private Const SettingsFile As String = "settings.dat"
End Sub

Sub AppStart (Form1 As Form, Args() As String)
   SettingsFolder = File.DirData("MyApp")
   MainForm = Form1
   LoadSettings
   MainForm.Show
End Sub

Sub LoadSettings
   If File.Exists(SettingsFolder, SettingsFile) Then
     Try
       Dim r As RandomAccessFile
       r.Initialize(SettingsFolder, SettingsFile, True)
       Dim m As Map = r.ReadB4XObject(r.CurrentPosition)
       SetFormFromMap(m, MainForm)
     Catch
       Log(LastException)
     End Try
   End If
End Sub


Sub MainForm_Closed
   Dim r As RandomAccessFile
   r.Initialize(SettingsFolder, SettingsFile, False)
   r.WriteB4XObject(FormToMap(MainForm), 0)
   r.Close
End Sub

Sub SetFormFromMap(m As Map, f As Form)
   f.WindowLeft = m.Get("left")
   f.WindowTop = m.Get("top")
   f.WindowWidth = m.Get("width")
   f.WindowHeight = m.Get("height")
   Dim iconified As Boolean = m.Get("iconified")
   If iconified Then
     Dim jo As JavaObject = f
     jo.GetFieldJO("stage").RunMethod("setIconified", Array(iconified))
   End If
   'check that left and top are in screen boundaries
   Dim goodLeft, goodTop As Boolean
   For Each screen As Screen In fx.Screens
     If f.WindowLeft >= screen.MinX And f.WindowLeft <= screen.MaxX Then
       goodLeft = True
     End If
     If f.WindowTop >= screen.MinY And f.WindowTop <= screen.MaxY Then
       goodTop = True
     End If
   Next
   If Not(goodLeft) Then f.WindowLeft = 0
   If Not(goodTop) Then f.WindowTop = 0
End Sub

Sub FormToMap (f As Form) As Map
   Dim m As Map = CreateMap("left": f.WindowLeft, "top": f.WindowTop, "width": f.WindowWidth, _
     "height": f.WindowHeight)
   Dim jo As JavaObject = f
   m.Put("iconified", jo.GetFieldJO("stage").RunMethod("isIconified", Null))
   Return m
End Sub
 
Last edited:
Upvote 0

Mikelgiles

Active Member
Licensed User
Longtime User
Thanks Erel, This looks to be exactly what I need. However i have a problem in that i cannot get the _Closed event called when closing my form window. This is supposed to get fired whenever I click the 'X' on my window isnt it? The event does get fired when I close the sample app you sent so I must have something messed up in my code. Any thoughts on what I should look for?


See this example: depends on JavaObject and jRandomAccessFile libs.
B4X:
Sub Process_Globals
   Private fx As JFX
   Private MainForm As Form
   Private SettingsFolder As String
   Private Const SettingsFile As String = "settings.dat"
End Sub

Sub AppStart (Form1 As Form, Args() As String)
   SettingsFolder = File.DirData("MyApp")
   MainForm = Form1
   LoadSettings
   MainForm.Show
End Sub

Sub LoadSettings
   If File.Exists(SettingsFolder, SettingsFile) Then
     Try
       Dim r As RandomAccessFile
       r.Initialize(SettingsFolder, SettingsFile, True)
       Dim m As Map = r.ReadB4XObject(r.CurrentPosition)
       SetFormFromMap(m, MainForm)
     Catch
       Log(LastException)
     End Try
   End If
End Sub


Sub MainForm_Closed
   Dim r As RandomAccessFile
   r.Initialize(SettingsFolder, SettingsFile, False)
   r.WriteB4XObject(FormToMap(MainForm), 0)
   r.Close
End Sub

Sub SetFormFromMap(m As Map, f As Form)
   f.WindowLeft = m.Get("left")
   f.WindowTop = m.Get("top")
   f.WindowWidth = m.Get("width")
   f.WindowHeight = m.Get("height")
   Dim iconified As Boolean = m.Get("iconified")
   If iconified Then
     Dim jo As JavaObject = f
     jo.GetFieldJO("stage").RunMethod("setIconified", Array(iconified))
   End If
   'check that left and top are in screen boundaries
   Dim goodLeft, goodTop As Boolean
   For Each screen As Screen In fx.Screens
     If f.WindowLeft >= screen.MinX And f.WindowLeft <= screen.MaxX Then
       goodLeft = True
     End If
     If f.WindowTop >= screen.MinY And f.WindowTop <= screen.MaxY Then
       goodTop = True
     End If
   Next
   If Not(goodLeft) Then f.WindowLeft = 0
   If Not(goodTop) Then f.WindowTop = 0
End Sub

Sub FormToMap (f As Form) As Map
   Dim m As Map = CreateMap("left": f.WindowLeft, "top": f.WindowTop, "width": f.WindowWidth, _
     "height": f.WindowHeight)
   Dim jo As JavaObject = f
   m.Put("iconified": jo.GetFieldJO("stage").RunMethod("isIconified", Null))
   Return m
End Sub
 
Upvote 0

Mikelgiles

Active Member
Licensed User
Longtime User
Thanks Enrique! I cannot get the closing event to fire. I have tried both form_Closed and form_Closing and neither fires when I close the Window ( using the 'X' at the top right). Any thoughts?
 
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Hi,

try:
B4X:
'Handle form closing via system close (top right X button)
Sub MainForm_CloseRequest (EventData As Event)
    ' Add closing activities
End Sub
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
You should post your code so we could see what you have done.
What is the name of the Form ?
If it's MainForm, Sub MainForm_Closed is fired.
Or you must use Sub YourFormName_Closed.
An advantage with rwblinn' routine is that you cane
 
Upvote 0

Mikelgiles

Active Member
Licensed User
Longtime User
I have tried _CloseRequest, _Closing, and _Closed with no success. My form name is frmMaster and frmDetail. When using the code that Erel posted it does trigger the _Closed event so I am sure I am doing something wrong. I have removed all of the code that does not show my problem so it should be a lot easier to look at. Code is attached .
 

Attachments

  • CFTest.zip
    4 KB · Views: 360
Upvote 0

EnriqueGonzalez

Well-Known Member
Licensed User
Longtime User
Mikel

this are the correct names for the subs.

When you initialize the form you can write your prefered event name for every form except the mainform, mainform event will always be mainForm.

B4X:
Sub mainForm_CloseRequest (EventData As Event)
    Log (EventData)
    SaveFormSettings(frmMaster)
End Sub

Sub mainForm_Closed
    Log("closed")
    SaveFormSettings(frmMaster)
End Sub

Sub Detail_CloseRequest (EventData As Event)
    Log (EventData)
    SaveFormSettings(frmDetail)
End Sub

Sub Detail_Closed
    Log("closed")
    SaveFormSettings(frmDetail)
End Sub
 
Upvote 0

Mikelgiles

Active Member
Licensed User
Longtime User
FIXED!!

Thanks Enrique, It works now that I renamed frmMaster to MainForm. What controls which form is the mainform? And do I always have to have it named MainForm? I thought I had tried renaming it to MainForm and it didnt work. But now it does so I must have had some other setting wrong. Anyway, thanks a bunch for the help. The longer I work in B4J the dumber I think I am LOL
 
Upvote 0

EnriqueGonzalez

Well-Known Member
Licensed User
Longtime User
Ey Mikel you are welcome

The mainform is the one that you called masterform. I have naver changed the name but after your example I understood that its possible.

The event name doesn't come from that mainform but from the form on the sub of appstart (that is why you cannot change the event name)

Programming is a mix of feelings where sometimes you feel like a demi god and others ... The dumbest.

Just recently I spent 2 hours looking why my code was not printing when I realized that I forgot to put the actual line to print. Lol
 
Upvote 0
Top