如何检测面板是否在可视窗口中?

时间:2015-09-30 14:47:36

标签: vb.net scroll panel

使用Winforms和vb.net VS 2012:

如果我有一个大型可滚动面板,我在较大的面板内放了一堆较小的面板。当我向上或向下滚动较大的面板时,一些较小的面板将滚出视图。我的问题是,我可以在较小的面板上放置一个监听器,以便较小的面板知道它何时滚出视图?

我无法使用.visible属性,因为即使面板不在窗口中,它也始终设置为true。我也知道我可以设置.focus属性将其恢复到视图中,但只要其他东西成为焦点,它仍然会在可视窗口中失去焦点。

当面板滚出视图时,是否有可以侦听的属性或其他内容?如果没有,我还能做些什么来检测这个?

感谢。

1 个答案:

答案 0 :(得分:0)

从Panel的Scroll()和MouseWheel()事件中,使用如下代码:

Private Sub Panel1_Scroll(sender As Object, e As ScrollEventArgs) Handles Panel1.Scroll
    CheckVisibility(sender)
End Sub

Private Sub Panel1_MouseWheel(sender As Object, e As MouseEventArgs) Handles Panel1.MouseWheel
    CheckVisibility(sender)
End Sub

Private Sub CheckVisibility(ByVal pnl As Panel)
    Dim results As New List(Of String)

    Dim pnlRectScreen As Rectangle = pnl.Parent.RectangleToScreen(pnl.Bounds)
    For Each child As Control In pnl.Controls
        Dim childRectScreen As Rectangle = pnl.RectangleToScreen(child.Bounds)
        If pnlRectScreen.IntersectsWith(childRectScreen) Then
            If pnlRectScreen.Contains(childRectScreen) Then
                results.Add(child.Name & ": Completely Visible")
            Else
                results.Add(child.Name & ": Partially Visible")
            End If
        Else
            results.Add(child.Name & ": Not Visible")
        End If
    Next

    ListBox1.DataSource = Nothing
    ListBox1.DataSource = results
End Sub

如果您想知道它何时变为隐藏,则使用Dictionary()跟踪当前可见性,并在其变为隐藏时执行某些操作。这是一个更强大的例子:

Public Enum ControlVisibility
    Hidden
    PartialyVisible
    FullyVisible
End Enum

Private VisibiltyState As New Dictionary(Of Control, ControlVisibility)

Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
    Dim pnl As Panel = Panel1
    Dim pnlRectScreen As Rectangle = pnl.Parent.RectangleToScreen(pnl.Bounds)
    For Each child As Control In pnl.Controls
        Dim childRectScreen As Rectangle = Panel2.RectangleToScreen(child.Bounds)
        If pnlRectScreen.IntersectsWith(childRectScreen) Then
            If pnlRectScreen.Contains(childRectScreen) Then
                VisibiltyState.Add(child, ControlVisibility.FullyVisible)
            Else
                VisibiltyState.Add(child, ControlVisibility.PartialyVisible)
            End If
        Else
            VisibiltyState.Add(child, ControlVisibility.Hidden)
        End If
    Next
End Sub

Private Sub Panel1_Scroll(sender As Object, e As ScrollEventArgs) Handles Panel1.Scroll
    CheckVisibility(sender)
End Sub

Private Sub Panel1_MouseWheel(sender As Object, e As MouseEventArgs) Handles Panel1.MouseWheel
    CheckVisibility(sender)
End Sub

Private Sub CheckVisibility(ByVal pnl As Panel)
    Dim NewVisibility As ControlVisibility
    Dim pnlRectScreen As Rectangle = pnl.Parent.RectangleToScreen(pnl.Bounds)
    For Each child As Control In pnl.Controls
        Dim childRectScreen As Rectangle = pnl.RectangleToScreen(child.Bounds)
        If pnlRectScreen.IntersectsWith(childRectScreen) Then
            If pnlRectScreen.Contains(childRectScreen) Then
                NewVisibility = ControlVisibility.FullyVisible
            Else
                NewVisibility = ControlVisibility.PartialyVisible
            End If
        Else
            NewVisibility = ControlVisibility.Hidden
        End If

        ' has it changed?
        If VisibiltyState(child) <> NewVisibility AndAlso NewVisibility = ControlVisibility.Hidden Then
            Debug.Print(child.Name & " has become hidden: " & DateTime.Now.ToString("h:mm:ss.ffff"))
        End If

        VisibiltyState(child) = NewVisibility
    Next
End Sub