Announcement

Collapse
No announcement yet.

Anchor logic

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Anchor logic

    Winforms (.NET) has a great feature.. an anchor property for controls.
    When properly set it will reposition or size controls on a logic location.

    I wrote something for my designer which almost works but i have trouble with the previous size for dialog client area.
    The previous size is required to calculate the current (right-side) offset.

    Minimizing the form and restoring it makes it currently messing things up.
    I was able to prevent it a little but i find it unstable.
    Any idea how to use this on WM_SIZE and still being able to reliably measure the right side offset for a control which should be anhor'd right+bottom ?

    Here is an executable, it's almost good.
    The button and tab control resizes well, even when you maximize the form, minimize it and restore it.

    http://www.hellobasic.com/trials/Anchortest1.zip

    The tab control is set to resize to all sides, problem will arise when the form get's to small.
    The buttons do well.
    On form3 the groupbox is in fact very small.
    Due unpredictable resizing it fails to maintain the size.

    Thanks!
    hellobasic

  • #2
    I didn't check the demo, but it sounds as if you should be checking fwSizeType of WM_SIZE and not resize the controls under certain values. Obviously if you don't process the parent's WM_SIZE then it won't work.
    kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

    Comment


    • #3
      I have updated the exe.
      It works better now but i seen .NET winforms behaving better on critical sizes.
      I suspect they maintain a last known good offset and use that when the control can be resized properly again.

      Check out the exe, it's fun to see
      hellobasic

      Comment


      • #4
        Real Men use MoveWindow() on WM_SIZE
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          The controls *are* moved on WM_SIZE
          hellobasic

          Comment


          • #6
            Edwin

            Here is how i am doing it myself:

            Code:
            ' ANCHOR Flags:
              %ANCHOR_NONE                = 0
              %ANCHOR_LEFT                = %ANCHOR_NONE
              %ANCHOR_WIDTH               = 1
              %ANCHOR_RIGHT               = 2
              %ANCHOR_CENTER_HORZ         = 3
              %ANCHOR_HEIGHT              = 4
              %ANCHOR_HEIGHT_WIDTH        = 5
              %ANCHOR_HEIGHT_RIGHT        = 6
              %ANCHOR_BOTTOM              = 7
              %ANCHOR_BOTTOM_WIDTH        = 8
              %ANCHOR_BOTTOM_RIGHT        = 9
              %ANCHOR_CENTER_HORZ_BOTTOM  = 10
              %ANCHOR_CENTER_VERT         = 11
              %ANCHOR_CENTER_VERT_RIGHT   = 12
              %ANCHOR_CENTER              = 13
            '****************************************************************************
            
            TYPE ZIMAGEPROP
                hWnd        AS LONG
                anchor      AS LONG
                rc          AS RECT
                TiledBitmap AS LONG
            '// order       AS STRING * 512  '//3.02 Before it was 128 objects and now 256 objects
                order       AS STRING * 2048 '//3.57 Before it was 256 and now 1024 objects
                ordersize   AS LONG
            
                WMBit(25)   AS LONG          '//4.02
                WMCodePtr(25*32) AS DWORD    '//4.02
            END TYPE
            
            GLOBAL WinProp() AS ZIMAGEPROP
            
            FUNCTION zPropertyItem(BYVAL hWnd AS LONG) AS LONG
                IF UBOUND(WinProp) > 0 THEN
                   ARRAY SCAN WinProp(), FROM 1 TO 4, = MKL$(hWnd), TO Item&
                END IF
                FUNCTION = Item&
            END FUNCTION
            
            FUNCTION ZI_SetAnchorMode ALIAS "ZI_SetAnchorMode" (BYVAL hWnd AS LONG, BYVAL AnchorMode AS LONG) EXPORT AS LONG
                LOCAL pZP AS LONG
                IF IsWindow(hWnd) THEN
                   LOCAL rc AS RECT, pr AS RECT, p AS POINTAPI
            
                   pZP = zPropertyItem(hWnd)
                   IF pZP = 0 THEN ' If the object already exist then we ReUse it
                      pZP = MAX&(UBOUND(WinProp) + 1, 1)
                      REDIM PRESERVE WinProp(1 TO pZP) AS ZIMAGEPROP
                   END IF
                   WinProp(pZP).hWnd = hWnd
                   CALL GetWindowRect(hWnd, rc)
                   p.X = rc.nLeft: p.Y = rc.nTop
                   CALL ScreenToClient(Getparent(hWnd), p)
                   CALL GetClientRect(Getparent(hWnd), pr)
                   WinProp(pZP).anchor     = MIN&(MAX&(AnchorMode, %ANCHOR_NONE), %ANCHOR_CENTER)
                   WinProp(pZP).rc.nLeft   = p.X
                   WinProp(pZP).rc.nTop    = p.Y
                   WinProp(pZP).rc.nRight  = pr.nRight - (rc.nRight - rc.nLeft + p.X)
                   WinProp(pZP).rc.nBottom = pr.nBottom - (rc.nBottom - rc.nTop + p.Y)
                   FUNCTION = -1
                END IF
            END FUNCTION
            
            FUNCTION EnumChildProc(BYVAL hWnd AS LONG, BYVAL lParam AS LONG) AS LONG
                LOCAL zChildClass AS ASCIIZ * 32
                LOCAL pr AS RECT, rc AS RECT, pZP AS LONG
            
                IF GetClassName(hWnd, zChildClass, SIZEOF(zChildClass)) THEN
                   pZP = zPropertyItem(hWnd)
                   IF pZP THEN
                      IF WinProp(pZP).anchor > %ANCHOR_NONE THEN
                         CALL GetWindowRect(hWnd, rc)
                         WidthIs&  = rc.nRight - rc.nLeft
                         HeightIs& = rc.nBottom - rc.nTop
                         CALL GetClientRect(GetParent(hWnd), pr)
                         x& = 0: y& = 0: xW& = 0: yH& = 0
                         SELECT CASE LONG WinProp(pZP).anchor
                        'CASE %ANCHOR_NONE                '= 0
                         CASE %ANCHOR_WIDTH               '= 1
                              x&  = WinProp(pZP).rc.nLeft
                              y&  = WinProp(pZP).rc.nTop
                              xW& = MAX&(pr.nRight - WinProp(pZP).rc.nLeft - WinProp(pZP).rc.nRight, 0)
                              yH& = HeightIs&
                         CASE %ANCHOR_RIGHT               '= 2
                              x&  = pr.nRight - WidthIs& - WinProp(pZP).rc.nRight
                              y&  = WinProp(pZP).rc.nTop
                              xW& = WidthIs&
                              yH& = HeightIs&
                         CASE %ANCHOR_CENTER_HORZ         '= 3
                              x&  = (pr.nRight - WidthIs&) \ 2
                              y&  = WinProp(pZP).rc.nTop
                              xW& = WidthIs&
                              yH& = HeightIs&
                         CASE %ANCHOR_HEIGHT              '= 4
                              x&  = WinProp(pZP).rc.nLeft
                              y&  = WinProp(pZP).rc.nTop
                              xW& = WidthIs&
                              yH& = MAX&(pr.nBottom - WinProp(pZP).rc.nTop - WinProp(pZP).rc.nBottom, 0)
                         CASE %ANCHOR_HEIGHT_WIDTH        '= 5
                              x& = WinProp(pZP).rc.nLeft
                              y& = WinProp(pZP).rc.nTop
                              xW& = MAX&(pr.nRight - WinProp(pZP).rc.nLeft - WinProp(pZP).rc.nRight, 0)
                              yH& = MAX&(pr.nBottom - WinProp(pZP).rc.nTop - WinProp(pZP).rc.nBottom, 0)
                         CASE %ANCHOR_HEIGHT_RIGHT        '= 6
                              x&  = pr.nRight - WidthIs& - WinProp(pZP).rc.nRight
                              y&  = WinProp(pZP).rc.nTop
                              xW& = WidthIs&
                              yH& = MAX&(pr.nBottom - WinProp(pZP).rc.nTop - WinProp(pZP).rc.nBottom, 0)
                         CASE %ANCHOR_BOTTOM              '= 7
                              x&  = WinProp(pZP).rc.nLeft
                              y&  = pr.nBottom - WinProp(pZP).rc.nBottom - HeightIs&
                              xW& = WidthIs&
                              yH& = HeightIs&
                         CASE %ANCHOR_BOTTOM_WIDTH        '= 8
                              x&  = WinProp(pZP).rc.nLeft
                              y&  = pr.nBottom - WinProp(pZP).rc.nBottom - HeightIs&
                              xW& = MAX&(pr.nRight - WinProp(pZP).rc.nLeft - WinProp(pZP).rc.nRight, 0)
                              yH& = HeightIs&
                         CASE %ANCHOR_BOTTOM_RIGHT        '= 9
                              x&  = pr.nRight - WidthIs& - WinProp(pZP).rc.nRight
                              y&  = pr.nBottom - WinProp(pZP).rc.nBottom - HeightIs&
                              xW& = WidthIs&
                              yH& = HeightIs&
                         CASE %ANCHOR_CENTER_HORZ_BOTTOM  '= 10
                              x&  = (pr.nRight - WidthIs&) \ 2
                              y&  = pr.nBottom - WinProp(pZP).rc.nBottom - HeightIs&
                              xW& = WidthIs&
                              yH& = HeightIs&
                         CASE %ANCHOR_CENTER_VERT         '= 11
                              x&  = WinProp(pZP).rc.nLeft
                              y&  = (pr.nBottom - HeightIs&) \ 2
                              xW& = WidthIs&
                              yH& = HeightIs&
                         CASE %ANCHOR_CENTER_VERT_RIGHT   '= 12
                              x&  = pr.nRight - WidthIs& - WinProp(pZP).rc.nRight
                              y&  = (pr.nBottom - HeightIs&) \ 2
                              xW& = WidthIs&
                              yH& = HeightIs&
                         CASE %ANCHOR_CENTER              '= 13
                              x&  = (pr.nRight - WidthIs&) \ 2
                              y&  = (pr.nBottom - HeightIs&) \ 2
                              xW& = WidthIs&
                              yH& = HeightIs&
                         END SELECT
                         CALL MoveWindow(hWnd, x&, y&, xW&, yH&, 1)
                      END IF
                   END IF
                END IF
                FUNCTION = %TRUE ' Continue enumeration of children..
            END FUNCTION
            
            FUNCTION zGetMsgProc(BYVAL nCode AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                LOCAL pCWP AS CWPSTRUCT PTR
                IF nCode = 0 THEN
                   IF lParam THEN
                      pCWP = lParam
                      IF LOWRD(@pCWP.message) = %WM_SIZE THEN
                         CALL EnumChildWindows(@pCWP.hWnd, CODEPTR(EnumChildProc), 0)
                      END IF
                   END IF
                END IF
                FUNCTION = CallNextHookEx(gChildHookPtr, nCode, wParam, lParam)
            END FUNCTION
            Note: i am using a HOOK procedure to monitor the %WM_SIZE message and the EnumChildProc callback to move the controls to their new location.


            Added (the Hook management)
            Code:
            ' LIBMAIN
            FUNCTION DllMain (BYVAL DllInstance AS LONG, BYVAL Reason AS LONG, BYVAL Reserved AS LONG) EXPORT AS LONG
            
                LOCAL Ret AS LONG
            
                Ret = %TRUE
            
                IF Reason& = %DLL_PROCESS_ATTACH THEN
            
                   IF gChildHookPtr = 0 THEN gChildHookPtr = SetWindowsHookEx (%WH_CALLWNDPROC, CODEPTR(zGetMsgProc), 0&, GetCurrentThreadID)
                   IF gKeybHookPtr = 0 THEN gKeybHookPtr = SetWindowsHookEx(%WH_KEYBOARD, CODEPTR(zKeybProc), 0&, GetCurrentThreadID)
            
            
                ELSEIF Reason& = %DLL_PROCESS_DETACH THEN
            
                   IF gChildHookPtr THEN CALL UnhookWindowsHookEx(gChildHookPtr): gChildHookPtr = 0
                   IF gKeybHookPtr THEN CALL UnhookWindowsHookEx(gKeybHookPtr): gKeybHookPtr = 0
            
                END IF
            
                FUNCTION = Ret
            
            END FUNCTION
            Last edited by Patrice Terrier; 7 Aug 2008, 10:38 AM. Reason: added the hook management
            Patrice Terrier
            www.zapsolution.com
            www.objreader.com
            Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

            Comment


            • #7
              Code:
              IF gChildHookPtr = 0 THEN gChildHookPtr = [B]SetWindowsHookEx[/B] (....
              SetWindowsHookEx in USER32.DLL; USER32.DLL <> KERNEL32.DLL; Not supposed to be used on DLL_PROCESS_ATTACH.

              Probably safe if this library loaded dynamically, as I cannot imagine any program NOT loading USER32.DLL.

              MCM
              Michael Mattias
              Tal Systems (retired)
              Port Washington WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                http://msdn.microsoft.com/en-us/libr...90(VS.85).aspx
                http://msdn.microsoft.com/en-us/libr...60(VS.85).aspx
                Patrice Terrier
                www.zapsolution.com
                www.objreader.com
                Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

                Comment


                • #9
                  Nice links: they reinforce what I cautioned:
                  An alternative method for installing a global hook procedure is to provide an installation function in the DLL, along with the hook procedure [italics mine]...
                  Note: Separate installation function recommended!
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment

                  Working...
                  X