Saving and retreiving window state

Started by Sean Scott, February 16, 2010, 10:46:29 PM

Previous topic - Next topic

Sean Scott

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?

José Roca

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


Rolf Brandt

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
Rolf Brandt
http://www.rbsoft.eu
http://www.taxifreeware.com
I cook with wine, sometimes I even add it to the food.
(W. C. Fields)

Sean Scott

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

Sean Scott

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

Rolf Brandt

This works:
ShowWindow hwndform, %SW_MAXIMIZE
Rolf Brandt
http://www.rbsoft.eu
http://www.taxifreeware.com
I cook with wine, sometimes I even add it to the food.
(W. C. Fields)

Jean-pierre Leroy

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

Dennis Hoskins

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

Paul Squires

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.
Paul Squires
PlanetSquires Software

Jean-pierre Leroy

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

Cho Sing Kum

#10
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.


Jean-pierre Leroy

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

Paul Squires

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.
Paul Squires
PlanetSquires Software

Jean-pierre Leroy

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

Rolf Brandt

Nice piece of code as always, Jean-Pierre.

Rolf
Rolf Brandt
http://www.rbsoft.eu
http://www.taxifreeware.com
I cook with wine, sometimes I even add it to the food.
(W. C. Fields)