Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Visual Basic
  4. Stay inside MDI Client Area

Stay inside MDI Client Area

Scheduled Pinned Locked Moved Visual Basic
question
4 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Michael Russell
    wrote on last edited by
    #1

    In MDI applications, it is a common occurance for the user to open several different forms. However, even if one form is closed, the "offset" used to place the subsequent forms is remembered, so each form is gradually shifted down and to the right until it shifts partially or fully outside of the MDI client area. I'd like to ensure that the MDI clients are always completely within the MDI client area upon first being opened. I have come up with a hack involving the OnVisibleChanged event and two helper functions (listed below), but is there a more graceful way of doing this?

    ' In each form
        Protected Overrides Sub OnVisibleChanged(ByVal e As System.EventArgs)
            EnsureInsideMDIArea(Me)
        End Sub
    
    ' Helper functions in a module
        Public Function GetMDIClientRect(ByVal frm As Form) As Rectangle
            Dim pr As Rectangle = Rectangle.Empty
            For Each c As Control In frm.Controls
                If TypeOf c Is MdiClient Then pr = c.ClientRectangle
            Next
            Return pr
        End Function
    
        Public Sub EnsureInsideMDIArea(ByVal frm As Form)
            ' Ignore if not an MDI client
            If Not (frm.MdiParent Is Nothing) Then
    
                ' Get parent rect
                Dim pr As Rectangle = GetMDIClientRect(frm.MdiParent)
    
                Dim r, b As Integer
                r = frm.Size.Width + frm.Left
                b = frm.Size.Height + frm.Top
    
                If r > pr.Right Or b > pr.Bottom Then
                    frm.Top = 0
                    frm.Left = 0
                End If
    
            End If
        End Sub
    
    D 1 Reply Last reply
    0
    • M Michael Russell

      In MDI applications, it is a common occurance for the user to open several different forms. However, even if one form is closed, the "offset" used to place the subsequent forms is remembered, so each form is gradually shifted down and to the right until it shifts partially or fully outside of the MDI client area. I'd like to ensure that the MDI clients are always completely within the MDI client area upon first being opened. I have come up with a hack involving the OnVisibleChanged event and two helper functions (listed below), but is there a more graceful way of doing this?

      ' In each form
          Protected Overrides Sub OnVisibleChanged(ByVal e As System.EventArgs)
              EnsureInsideMDIArea(Me)
          End Sub
      
      ' Helper functions in a module
          Public Function GetMDIClientRect(ByVal frm As Form) As Rectangle
              Dim pr As Rectangle = Rectangle.Empty
              For Each c As Control In frm.Controls
                  If TypeOf c Is MdiClient Then pr = c.ClientRectangle
              Next
              Return pr
          End Function
      
          Public Sub EnsureInsideMDIArea(ByVal frm As Form)
              ' Ignore if not an MDI client
              If Not (frm.MdiParent Is Nothing) Then
      
                  ' Get parent rect
                  Dim pr As Rectangle = GetMDIClientRect(frm.MdiParent)
      
                  Dim r, b As Integer
                  r = frm.Size.Width + frm.Left
                  b = frm.Size.Height + frm.Top
      
                  If r > pr.Right Or b > pr.Bottom Then
                      frm.Top = 0
                      frm.Left = 0
                  End If
      
              End If
          End Sub
      
      D Offline
      D Offline
      Dave Kreskowiak
      wrote on last edited by
      #2

      Graceful is in the eye of the beholder. If what you wrote works for you, great! Another method, though, would be to put this kind of code entirely in the MDI Parent and when you create the new child form, you can get it's size and make sure that it is inside the MDI Parent's client window without iterating through all the controls...

      ' In MDI Parent
       
      Private Sub MenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem2.Click
      Dim newChild As New frmChild
      newChild.MdiParent = Me

          ' You must show the form before it will receive its Top and Left values.  If you send
          ' the new form to EnsureChildInClientArea first, its Top and Left will always be 0,0.
          newChild.Show()
          EnsureChildInClientArea(newChild)
      End Sub
      

      Private Sub EnsureChildInClientArea(ByRef frmChild As Form)
      Dim r, b As Integer
      r = frmChild.Width + frmChild.Left
      b = frmChild.Height + frmChild.Top
      If r > Me.ClientSize.Width Or b > Me.ClientSize.Height Then
      frmChild.Top = 0
      frmChild.Left = 0
      End If
      End Sub

      RageInTheMachine9532

      M 1 Reply Last reply
      0
      • D Dave Kreskowiak

        Graceful is in the eye of the beholder. If what you wrote works for you, great! Another method, though, would be to put this kind of code entirely in the MDI Parent and when you create the new child form, you can get it's size and make sure that it is inside the MDI Parent's client window without iterating through all the controls...

        ' In MDI Parent
         
        Private Sub MenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem2.Click
        Dim newChild As New frmChild
        newChild.MdiParent = Me

            ' You must show the form before it will receive its Top and Left values.  If you send
            ' the new form to EnsureChildInClientArea first, its Top and Left will always be 0,0.
            newChild.Show()
            EnsureChildInClientArea(newChild)
        End Sub
        

        Private Sub EnsureChildInClientArea(ByRef frmChild As Form)
        Dim r, b As Integer
        r = frmChild.Width + frmChild.Left
        b = frmChild.Height + frmChild.Top
        If r > Me.ClientSize.Width Or b > Me.ClientSize.Height Then
        frmChild.Top = 0
        frmChild.Left = 0
        End If
        End Sub

        RageInTheMachine9532

        M Offline
        M Offline
        Michael Russell
        wrote on last edited by
        #3

        That would almost work. We'd need an Application.DoEvents after the newChild.Show because the top/left are not set until the new form is actually visible (very frustrating trying to figure THAT out...), and we'd actually need to check the MdiClient size, not just the ClientSize, or else status bars and what not would not be taken into account. The biggest problem I have with the current solution is that when the form is created, it shows at the original location for 1/60th of a second, and the flicker looks bad.

        D 1 Reply Last reply
        0
        • M Michael Russell

          That would almost work. We'd need an Application.DoEvents after the newChild.Show because the top/left are not set until the new form is actually visible (very frustrating trying to figure THAT out...), and we'd actually need to check the MdiClient size, not just the ClientSize, or else status bars and what not would not be taken into account. The biggest problem I have with the current solution is that when the form is created, it shows at the original location for 1/60th of a second, and the flicker looks bad.

          D Offline
          D Offline
          Dave Kreskowiak
          wrote on last edited by
          #4

          It was quick and dirty, but it worked. No intensive testing on it though... It was just an idea! :) RageInTheMachine9532

          1 Reply Last reply
          0
          Reply
          • Reply as topic
          Log in to reply
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes


          • Login

          • Don't have an account? Register

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • World
          • Users
          • Groups