I would like to save the size, position, and state for my main form when I exit, then put the form back the way it was the next time the program is run. I have the size and position working, but I can't get it to maximize the window with FF_Control_ShowState( hWndForm, %SW_MAXIMIZE ), nor can I figure out how to determine whether the form is maximized in order to save the state when the form unloads. What am I missing?
Call the API function GetWindowPlacement to retrieve the show state and the restored, minimized, and maximized positions of the specified window.
DIM WinPla AS WINDOWPLACEMENT
GetWindowPlacement hWnd, WinPla
where hwnd is the handle of your form.
Later, restore it filling the WinPla structure with the saved values and call the API function SetWindowPlacement:
SetWindowPlacement hWnd, WinPla
TYPE WINDOWPLACEMENT
length AS DWORD ' UINT
flags AS DWORD ' UINT
showCmd AS DWORD ' UINT
ptMinPosition AS POINT ' POINT
ptMaxPosition AS POINT ' POINT
rcNormalPosition AS RECT ' RECT
END TYPE
Since you might not want to save the position if the window state is either maximized (zoomed) or minimized (iconic) you could use this function to determine the window state:
'--------------------------------------------------------------------------------
' GetWindowState
' Is dialog minimized (iconic = 1) or maximized (zoomed = 2)
'--------------------------------------------------------------------------------
Function GetWindowState( DlgHWnd As Dword ) As Long
Function = 0
If IsIconic(DlgHWnd) Then
Function = IsIconic(DlgHWnd)
ElseIf IsZoomed(DlgHWnd) Then
Function = IsZoomed(DlgHWnd)
End If
End Function
Thanks. It looks like I have a choice between super-easy and more powerful--cool.
For future reference, if anyone wants to try Jose's suggestion, here is a link to the WINDOWPLACEMENT structure:
http://msdn.microsoft.com/en-us/library/ms632611(VS.85).aspx
Both of these suggestions worked fine to get the window state, but I can't get the window state to set properly. When I set the window state to MAXIMIZED, the form changes size to the size of the screen, but it doesn't actually maximize as I can move the form and double-click the title bar to make it actually maximize.
Here is the code I am using:
Dim WinPla As WINDOWPLACEMENT
GetWindowPlacement hWndForm, WinPla
winpla.showCmd = %SW_MAXIMIZE
SetWindowPlacement hWndForm, WinPla
What am I missing now?
Sean
This works:
ShowWindow hwndform, %SW_MAXIMIZE
I try also to implement some codes to save the position and size of FORMs when the user exit my project and then to restore them when the application start again; I have a few questions:
Q1. Where is the best place to save the current position and size of a FORM? in which message handler: WM_CLOSE or WM_DESTROY ?
Q2. Where is the best place to restore the current position and size of a FORM? in which message handler: WM_CREATE ?
Thanks for your help.
Jean-Pierre
Hi,
I don't know if this is the best approach but the following code works for me.
The sub is called from both WM_CREATE and WM_DESTROY with the window handle and a task string "get" or "save"
If the ini file does not exist it is created.
'==============================================================================
' Sub Name: Do_INI
'
' Purpose: Save or get info from app INI file
'
' Parameters:
' Inputs:
' hWnd: handle of main form
' Task: string indicating get or save
'
' Outputs: None
'
' Notes: get function called from WM_CREATE
' save function called from WM_DESTROY
'
' Author: Dennis Hoskins
' Date: 3/17/2010
'
' Changes:
' Date Ver By Description
'
'------------------------------------------------------------------------------
'
SUB DO_INI(hWnd AS DWORD, Task AS STRING)
LOCAL x AS LONG, y AS LONG
LOCAL xResult AS STRING, yResult AS STRING
LOCAL temp AS ASCIIZ * %Max_Path, INI_File AS STRING
INI_File = EXE.PATH$ & "MethDataFilter2.ini"
'Check if INI file exists
IF ISFALSE(ISFILE(INI_File)) THEN 'doesn't exist
'create file and then exit
OPEN INI_File FOR OUTPUT AS #1
CLOSE #1
DataDir = "C:\" 'Default dir to global
EXIT SUB
END IF
IF Task = "get" THEN
xResult = FF_INI_GETKEY(INI_File, "All", "Left", "300")
yResult = FF_INI_GETKEY(INI_File, "All", "Top", "300")
FF_CONTROL_SETLOC( hWnd, VAL(xResult), VAL(yResult) )
xResult = FF_INI_GETKEY(INI_File, "All", "Width", "844")
yResult = FF_INI_GETKEY(INI_File, "All", "Height", "643")
FF_CONTROL_SETSIZE( hWnd, VAL(xResult), VAL(yResult) )
DataDir = FF_INI_GETKEY(INI_File, "All", "LastDir", "C:\")
END IF
IF Task = "save" THEN
IF ISFALSE(ISICONIC(hWnd) OR ISZOOMED(hWnd)) THEN
FF_CONTROL_GETLOC( hWnd, x, y )
FF_INI_SETKEY(INI_File, "All", "Left", STR$(x))
FF_INI_SETKEY(INI_File, "All", "Top", STR$(y))
FF_CONTROL_GETSIZE( hWnd, x, y )
FF_INI_SETKEY(INI_File, "All", "Width", STR$(x))
FF_INI_SETKEY(INI_File, "All", "Height", STR$(y))
FF_INI_SETKEY(INI_File, "All", "LastDir", DataDir)
END IF
END IF
END SUB
Dennis
I always save the code in WM_DESTROY and restore the code in WM_CREATE. You may want to test for IsIconic and IsZoomed like in Rolf's post above and allow those settings to override any specific windowrect coordinates.
Dennis thank you for your code.
Based on your code I write two separate functions in order to save the location and size of all the forms of my application; in the INI file I create a section for each Form name.
As you can see below in these functions I have to pass two parameters; the first one is the handle of the Form; the second one is the name of the Form; I'm just curious to know if I would be able the retrieve the name of the Form using the handle of the Form; Is-there any FireFly function like ...
FormName = FF_FormName(hWndForm)
Paul any idea about that ?
Sub SaveLocationAndSize(hWndForm As Dword, pFormName As String)
Local lFileIni As String : lFileIni = Exe.PATH$ + Exe.Name$ + ".ini"
Local lLeft As Long
Local lTop As Long
Local lWidth As Long
Local lHeight As Long
If IsFalse(IsIconic(hWndForm) Or IsZoomed(hWndForm)) Then
' Location of the Form
FF_Control_GetLoc(hWndForm, lLeft, lTop)
FF_INI_SetKey(lFileIni, pFormName, "Left", Str$(lLeft))
FF_INI_SetKey(lFileIni, pFormName, "Top" , Str$(lTop))
' Size of the Form
FF_Control_GetSize(hWndForm, lWidth, lHeight)
FF_INI_SetKey(lFileIni, pFormName, "Width" , Str$(lWidth))
FF_INI_SetKey(lFileIni, pFormName, "Height", Str$(lHeight))
End If
End Sub
Sub GetLocationAndSize(hWndForm As Dword, pFormName As String)
Local lFileIni As String : lFileIni = Exe.PATH$ + Exe.Name$ + ".ini"
Local lLeft As Long
Local lTop As Long
Local lWidth As Long
Local lHeight As Long '
' only if a section exists for this Form Name
If FF_INI_SectionExists(lFileIni,pFormName) = %TRUE Then
' Location of the Form
lLeft = Val(FF_INI_GetKey(lFileIni, pFormName, "Left", ""))
lTop = Val(FF_INI_GetKey(lFileIni, pFormName, "Top" , ""))
FF_Control_SetLoc(hWndForm, lLeft, lTop )
' Size of the Form
lWidth = Val(FF_INI_GetKey(lFileIni, pFormName, "Width" , ""))
lHeight = Val(FF_INI_GetKey(lFileIni, pFormName, "Height", ""))
FF_Control_SetSize(hWndForm, lWidth, lHeight)
End If
End Sub
Thanks,
Jean-Pierre
If the subroutines are called from the individual forms' WM_DESTROY and WM_CREATE, then:
A) maybe you can have the variable strFormName in each form and assigned the strFormName accordingly:
In Form1, strFormName = Form1,
In Form2, strFormName = Form2,
and so on...
or
B) maybe don't even need the variables but just substitute your pFormName with Form1 or Form2 when you make the calls.
Hi Cho,
Thank you for your help; the fact is that I don't want to pass these two variables, handle of the form and the form name in order to avoid any error typing; so I found a solution; I put a new function in each of my FF project; this function called HandleToFormName() returns the FORM name associated to the handle of the FORMs of my project.
Function HandleToFormName(ByVal hWndForm As Dword) As String
Select Case hWndForm
Case HWND_FORM1
Function = "Form1"
Case HWND_FORM2
Function = "Form2"
Case HWND_SETTINGS
Function = "Settings"
Case Else
ZTRACE("Unknown Form Handle:"+Str$(hWndForm))
End Select
End Function
Here are the updated subs SaveLocationAndSize() and GetLocationAndSize() to be used with this new function HandleToFormName()
Sub SaveLocationAndSize(ByVal hWndForm As Dword)
Local lFileIni As String : lFileIni = Exe.PATH$ + Exe.Name$ + ".ini"
Local lLeft As Long
Local lTop As Long
Local lWidth As Long
Local lHeight As Long
Local lFormName As String
' retrieve the name associated to this handle; this function is specific to each FF project
lFormName = HandleToFormName(hWndForm)
If IsFalse(IsIconic(hWndForm) Or IsZoomed(hWndForm)) Then
' Location of the Form
FF_Control_GetLoc(hWndForm, lLeft, lTop)
FF_INI_SetKey(lFileIni, lFormName, "Left", Str$(lLeft))
FF_INI_SetKey(lFileIni, lFormName, "Top" , Str$(lTop))
' Size of the Form
FF_Control_GetSize(hWndForm, lWidth, lHeight)
FF_INI_SetKey(lFileIni, lFormName, "Width" , Str$(lWidth))
FF_INI_SetKey(lFileIni, lFormName, "Height", Str$(lHeight))
End If
Sub GetLocationAndSize(ByVal hWndForm As Dword)
Local lFileIni As String : lFileIni = Exe.PATH$ + Exe.Name$ + ".ini"
Local lLeft As Long
Local lTop As Long
Local lWidth As Long
Local lHeight As Long
Local lFormName As String
' retrieve the name associated to this handle; this function is specific to each FF project
lFormName = HandleToFormName(hWndForm)
' only if a section exists for this Form Name
If FF_INI_SectionExists(lFileIni,lFormName) = %TRUE Then
' Location of the Form
lLeft = Val(FF_INI_GetKey(lFileIni, lFormName, "Left", ""))
lTop = Val(FF_INI_GetKey(lFileIni, lFormName, "Top" , ""))
FF_Control_SetLoc(hWndForm, lLeft, lTop )
' Size of the Form
lWidth = Val(FF_INI_GetKey(lFileIni, lFormName, "Width" , ""))
lHeight = Val(FF_INI_GetKey(lFileIni, lFormName, "Height", ""))
FF_Control_SetSize(hWndForm, lWidth, lHeight)
End If
End Sub
Maybe you could store the Form name in the Tag or Tag2 property of the Form and then use the FF functions to retrieve that value at runtime.
Dear FF users,
You will find below new versions of the subs SaveLocationAndSize() and GetLocationAndSize(); these new versions manage also an IsZoomed flag in the .ini file in order to maximize the window if it was the case before.
Sub SaveLocationAndSize(ByVal hWndForm As Dword)
Local lFileIni As String : lFileIni = AppIniFile()
Local lLeft As Long
Local lTop As Long
Local lWidth As Long
Local lHeight As Long
Local lFormName As String
' retrieve the name associated to this handle; this function is specific to each FF project
lFormName = HandleToFormName(hWndForm)
If IsFalse(IsIconic(hWndForm) Or IsZoomed(hWndForm)) Then
' Location of the Form
FF_Control_GetLoc(hWndForm, lLeft, lTop)
FF_INI_SetKey(lFileIni, lFormName, "Left", Str$(lLeft))
FF_INI_SetKey(lFileIni, lFormName, "Top" , Str$(lTop))
' Size of the Form
FF_Control_GetSize(hWndForm, lWidth, lHeight)
FF_INI_SetKey(lFileIni, lFormName, "Width" , Str$(lWidth))
FF_INI_SetKey(lFileIni, lFormName, "Height", Str$(lHeight))
End If
' to know if the windows is maximized
If IsTrue(IsZoomed(hWndForm)) Then FF_INI_SetKey(lFileIni, lFormName, "IsZoomed", "1") Else FF_INI_SetKey(lFileIni, lFormName, "IsZoomed", "0")
End Sub
Sub GetLocationAndSize(ByVal hWndForm As Dword)
Local lFileIni As String : lFileIni = AppIniFile()
Local lLeft As Long
Local lTop As Long
Local lWidth As Long
Local lHeight As Long
Local lFormName As String
' retrieve the name associated to this handle; this function is specific to each FF project
lFormName = HandleToFormName(hWndForm)
' only if a section exists for this Form Name
If FF_INI_SectionExists(lFileIni,lFormName) = %TRUE Then
' Location of the Form
lLeft = Val(FF_INI_GetKey(lFileIni, lFormName, "Left", ""))
lTop = Val(FF_INI_GetKey(lFileIni, lFormName, "Top" , ""))
FF_Control_SetLoc(hWndForm, lLeft, lTop )
' Size of the Form
lWidth = Val(FF_INI_GetKey(lFileIni, lFormName, "Width" , ""))
lHeight = Val(FF_INI_GetKey(lFileIni, lFormName, "Height", ""))
FF_Control_SetSize(hWndForm, lWidth, lHeight)
' maximize the windows if it was the case before
If FF_INI_GetKey(lFileIni, lFormName, "IsZoomed", "") = "1" Then ShowWindow(hWndForm, %SW_MAXIMIZE)
End If
End Sub
Your comments and feedback are welcome
Jean-Pierre
Nice piece of code as always, Jean-Pierre.
Rolf
Jean-Pierre,
Nice work, thanks!
A question about:
lFileIni = AppIniFile()
Does that simply translate the application's filename from ".exe" to ".ini" ? Or is there something else special going on, like checking file location, etc.?
Thanks,
-John
Yes you're right John it's a just a translation of the application's filename ... here is the function I use:
Function AppIniFile() As String
Function = Exe.PATH$ + Exe.Name$ + ".ini"
End Function
Thanks,
Jean-Pierre