Results 1 to 18 of 18

Thread: Client Area

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Client Area

    I have never been sure using system metrics how to align objects on a form correctly. I always seem to find myself adding a fudge here and there to get things just perfect.



    To align things horizontally I use the following:


    Code:
    (SM_CXEDGE + SM_CXFRAME) object (SM_CXFRAME + SM_CXEDGE)

    To align things vertically I use the following:


    Code:
                SM_CYEDGE 
                     +
                SM_CYFRAME
                     +
               SM_CYCAPTION
             
                  object
    
                SM_CYFRAME
                     +
                SM_CYEDGE

    Is this the correct way to center objects on a form?

    Thanks.

  2. #2
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Client Area

    Here's how I'd usually do it:

    Code:
    With Object
        .Move (ScaleWidth - .Width) / 2!, (ScaleHeight - .Height) / 2!
    End With
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  3. #3

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: Client Area

    Sorry I didn't do a very good job of describing what I was trying to ask. For centering I do the same as the post from Bonnie, but when there are several objects on a form and your trying to get consistent border widths around everything, form edges to objects and objects to objects. You need to know the widths and heights of all the pieces and parts of a form. After scrounging through documentation using system metrics I still find myself adding pixels here and there to tweak things.

    If you were to use all of what one might consider pertinent to a forms horizontal 'widths/dimensions' the numbers don't add up. Some of them must need to be excluded but I don't understand the correct combination to use.

    SM_CXBORDER
    SM_CXEDGE
    SM_CXFIXEDFRAME
    SM_CXFRAME

    Same goes for the vertical elements, if you use all of them the value for the forms height end up to large, so only a subset needs to be used.

    SM_CYBORDER
    SM_CYCAPTION
    SM_CYEDGE
    SM_CYFIXEDFRAME
    SM_CYFRAME


    There are two other elements but I'm not sure they are part of the forms frame/border or not.

    SM_CXSIZEFRAME
    SM_CYSIZEFRAME

  4. #4
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Client Area

    Can you post a screenshot or illustration of what you're trying to do?
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  5. #5
    PowerPoster
    Join Date
    Jul 2001
    Location
    Tucson, AZ
    Posts
    2,166

    Re: Client Area

    Bonnie:

    Thought I'd pass on that if you multiply rather than divide IMO it will execute faster.

    Do this:
    Code:
     .Move (ScaleWidth - .Width) * .5, (ScaleHeight - .Height) * .5
    Instead of:
    Code:
     .Move (ScaleWidth - .Width) / 2!, (ScaleHeight - .Height) / 2!

  6. #6
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Client Area

    Quote Originally Posted by Bonnie West View Post
    Can you post a screenshot or illustration of what you're trying to do?
    Curious, myself.

    Non-client metrics are needed possibly if trying to resize the non-client area to ensure a specific client area rect is visible. Also useful if subclassing WM_NCCALCSIZE and/or tweaking/positioning the client rect within the non-client rect.

    One does not need to be concerned with non-client metrics when positioning client objects. They are different 'containers'.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  7. #7
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Client Area

    Quote Originally Posted by dw85745 View Post
    Bonnie:

    Thought I'd pass on that if you multiply rather than divide IMO it will execute faster.
    Yes, I know. I intentionally chose the division method because I think it helps make the formula more readable. I lied a bit when I said that's "how I'd usually do it". Actually, in most of my code, I also prefer the multiplication method and I even invent a constant name just to make the code more readable:

    Code:
    Const HALF = 0.5!
    
    With Object
        .Move (ScaleWidth - .Width) * HALF, (ScaleHeight - .Height) * HALF
    End With
    When I'm writing scratch code, however, I just use the easiest method (division) in order to save time.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  8. #8

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: Client Area

    Well in starting a project all of the alignment of controls is done through the IDE. Then during a form re-size event, some controls grow and stretch while others are static. To keep the alignment exact so that all of the spacing stays consistent across the entire form, I use the forms new width and height in the Form_Resize event to calculate them. To do this I make use of the forms edge, frame and caption widths and heights to get the proper sizing.

  9. #9
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Client Area

    I use the forms new width and height in the Form_Resize event to calculate them. To do this I make use of the forms edge, frame and caption widths and heights to get the proper sizing.
    And that's your mistake in my opinion. The form's ScaleWidth & ScaleHeight are what you want when positioning/sizing controls. Those dimensions are the viewable area of the client area, after the non-client metrics have been applied. Use ScaleWidth,ScaleHeight as your real estate
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  10. #10
    PowerPoster
    Join Date
    Jul 2001
    Location
    Tucson, AZ
    Posts
    2,166

    Re: Client Area

    There's been a lot of discussion regarding "Resizing Forms" and controls thereon.
    Martin Liss (sp?) came up with a proportional method.
    There are others methods about that try and segment the form into areas.
    Others still that try and identify whether the control is static or to be resized.
    I have yet to find one that works in all cases.
    In addition to the control, resizing text is the biggest problem.
    Some controls such as comboboxes are a particular problem to resize.
    I came up with an API method a while back that allows a combobox and its text to be resized as well as other control text but ran out of time to apply to other controls.
    I'll see if I can find it and post. Give me a day or two.

    ===============
    Take a look at this and see if it helps.
    Credit for part of code belongs to others downloaded over the years and which I've cut and pasted.
    My apologizes to anyone whos code I used that is Not given credit.
    Zip file was created using 7 Zip.
    Forum with NOT accept a 7z extention, so extention changed to zip for upload.
    If you improve on it, please post in codebank for others.
    Attached Files Attached Files
    Last edited by dw85745; Dec 17th, 2015 at 09:15 AM.

  11. #11
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,439

    Re: Client Area

    I'll agree that a combination of the IDE's format tools (Menu/Format/...) and the ScaleWidth and ScaleHeight during runtime (with ScaleMode possibly set to pixels) is the way I'd tend to do it.

    However, I have messed with the form's client and non-client area in the past, and it would be interesting to completely work out how to do it that way. It's been a while since I've messed with those API calls, but I'd think that you could get precisely corresponding information to the ScaleWidth and ScaleHeight properties.

    Also, to my consternation, many of my clients don't run in 100% on their DPI mode and/or don't run in their monitors' native screen resolution. I'm also wondering how these things affect both the API calls and the ScaleWidth and ScaleHeight properties. Since I virtually always run my development machines at DPI 100% and all monitors in native resolution, I've never even tested to see how changing these settings affect things.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  12. #12
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Client Area

    Here's another vote to stick to ScaleWidth and ScaleHeight. Non-client measurements are a can of worms.

    GetSystemMetrics with the constants you've listed works okay for Win XP-era "classic theming". Custom user themes can and will mess up these measurements, however.

    To get accurate measurements of the "chunky" window borders used since Vista, you need a separate Vista+ API called DwmGetWindowAttribute, which has its own list of special constants. You're looking for the DWMWA_EXTENDED_FRAME_BOUNDS measurement.

    On Windows 10 (and probably 8.1?) border styles changed YET AGAIN, to a new thin style that lies somewhere between the chunky Aero sizes and the original "classic" sizes. Neither API returns pixel-exact measurements on Windows 10, and I'll admit that I haven't searched all the documentation to find a fix.

    In other words, stick to client measurements only. If you want pixel-perfect measurements regardless of DPI, you'll need to include a DPI-aware manifest and possibly rely on GetClientRect instead of VB's internal ScaleWidth/Height measurements. Search the forums for "DPI" and you'll find many discussions on this topic.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  13. #13
    Frenzied Member
    Join Date
    Mar 2008
    Posts
    1,210

    Re: Client Area

    Yes stick to ScaleWidth and ScaleHeight, and use Scalemode vbTwips on Forms where possible because it is more DPI friendly.
    If you need Pixels or want to convert to/ from them you have Screen.TwipsPerPixel and the Form.ScaleX/Y Methods.

  14. #14
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,439

    Re: Client Area

    Okay, if we insist on using API calls to get it done, this would seem to take care of everything with respect to centering controls on a form:

    Code:
    Option Explicit
    '
    Private Type RECT
      Left As Long
      Top As Long
      Right As Long
      Bottom As Long
    End Type
    Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
    '
    
    Private Sub Form_Activate()
        Dim ClientRect As RECT
        Dim PelX As Long
        Dim PelY As Long
    
        Me.ScaleMode = vbPixels
        
        GetClientRect Me.hwnd, ClientRect
        PelX = ClientRect.Right - ClientRect.Left
        PelY = ClientRect.Bottom - ClientRect.Top
        
        
        MsgBox "ScaleWidth: " & Me.ScaleWidth & vbCrLf & _
               "ScaleHeight: " & Me.ScaleHeight & vbCrLf & _
               "Client Width: " & PelX & vbCrLf & _
               "Client Height: " & PelY & vbCrLf
    
    
    End Sub
    I tested this on a Win7 and a Win10 machine, and it worked fine on both.

    I'm sure I've run across this before, but one thing that did strike me as curious is that I didn't have to go...
    PelX = ClientRect.Right - ClientRect.Left + 1
    ...when figuring the client width.

    Here's the screen-shot of my message box (both Win7 and Win10):
    Name:  Scale.gif
Views: 502
Size:  4.5 KB

    And I checked with a screen capture and precise measurement tool, and the client area is 108 pixels wide. This suggests that (for the API return) ClientRect.Left is zero-based and ClientRect.Right is one-based, which seems quite strange to me.

    Now, if we're talking about precisely centering a form on the screen (with respect to the form's full size and the screen's usable area (excluding taskbar)), that's an entirely different issue.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  15. #15
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,439

    Re: Client Area

    Also, for certain tablets (and other monitors) that you can turn 90 degrees, VB6 has some problems. In fact, to avoid these problems, I've had to write my own versions of:

    ScreenWidth
    ScreenHeight
    TwipsPerPixelX
    TwipsPerPixelY

    VB6 just doesn't seem to pick up when the screen is rotated.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  16. #16
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Client Area

    Quote Originally Posted by Elroy View Post
    I'm sure I've run across this before, but one thing that did strike me as curious is that I didn't have to go...
    PelX = ClientRect.Right - ClientRect.Left + 1
    ...when figuring the client width.

    . . .

    This suggests that (for the API return) ClientRect.Left is zero-based and ClientRect.Right is one-based, which seems quite strange to me.
    According to RECT structure:

    Quote Originally Posted by MSDN
    Remarks

    By convention, the right and bottom edges of the rectangle are normally considered exclusive. In other words, the pixel whose coordinates are ( right, bottom ) lies immediately outside of the rectangle. For example, when RECT is passed to the FillRect function, the rectangle is filled up to, but not including, the right column and bottom row of pixels.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  17. #17
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,439

    Re: Client Area

    That totally explains it. Thanks Bonnie.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  18. #18
    Addicted Member
    Join Date
    Aug 2009
    Location
    Anywhere I want to.
    Posts
    167

    Re: Client Area

    On Win XP Pro
    Missing declarations and toooo slow in the IDE and when compiled the cursor disconnects from the form so only on resize happens.
    Also things like textboxes fold over and text font is not considered.

    Have a new version?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width