You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义PictureBox:鼠标离开时关闭放大图片窗口的实现问题

解决自定义PictureBox放大窗口自动关闭问题

问题说明

我实现了一个继承自PictureBox的自定义控件,鼠标悬停时会弹出无框窗口放大显示图片。当前所有功能正常,但关闭放大窗口必须点击窗口外部,希望实现鼠标离开原PictureBox或放大窗口时自动关闭窗口。

原代码

Public Class CtrlNoticePictureBox
    Inherits PictureBox
    Private frmPicExtended As New Form
    Public Sub New()
        AddHandler Me.MouseEnter, New System.EventHandler(AddressOf Me.PictureBox_MouseEnter)
        AddHandler Me.MouseLeave, New System.EventHandler(AddressOf Me.PictureBox_MouseLeave)
    End Sub
    Private Sub PictureBox_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim screenCurrent As Screen = Screen.FromControl(Me)
        Dim workingArea As Rectangle = screenCurrent.WorkingArea
        Dim locationForm As Point = Me.TopLevelControl.Location

        frmPicExtended = New Form With {
            .ShowInTaskbar = False,
            .MaximizeBox = False,
            .ControlBox = False,
            .Location = New Point(Me.Width + locationForm.X, Me.Height + locationForm.Y),
            .StartPosition = FormStartPosition.Manual,
            .FormBorderStyle = FormBorderStyle.None
        }
        Dim picBoxExtended = New PictureBox With {
            .Name = "pictureBox",
            .Image = Me.Image,
            .SizeMode = PictureBoxSizeMode.Zoom,
            .Dock = DockStyle.Fill
        }
        frmPicExtended.Controls.Add(picBoxExtended)
        frmPicExtended.BringToFront()
        frmPicExtended.Show()
    End Sub
    Private Sub PictureBox_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim rectPicArea As New Rectangle With {.Location = Me.PointToScreen(Point.Empty), .Size = Me.Size}
        If IsNothing(frmPicExtended) = False Then
            If Not rectPicArea.Contains(Cursor.Position) Then
                frmPicExtended.Dispose()
            End If
        End If
    End Sub
    Function PointToCurrentScreen(ByVal self As Control, ByVal location As Point) As Point
        Dim screenBounds = Screen.FromControl(self).Bounds
        Dim globalCoordinates = self.PointToScreen(location)
        Return New Point(globalCoordinates.X - screenBounds.X, globalCoordinates.Y - screenBounds.Y)
    End Function
End Class

修改后的代码

Public Class CtrlNoticePictureBox
    Inherits PictureBox
    Private frmPicExtended As Form
    ' 跟踪鼠标是否在放大窗口上
    Private _isMouseOverExtended As Boolean = False

    Public Sub New()
        AddHandler Me.MouseEnter, AddressOf PictureBox_MouseEnter
        AddHandler Me.MouseLeave, AddressOf PictureBox_MouseLeave
    End Sub

    Private Sub PictureBox_MouseEnter(ByVal sender As Object, ByVal e As EventArgs)
        Dim screenCurrent As Screen = Screen.FromControl(Me)
        Dim locationForm As Point = Me.TopLevelControl.Location

        frmPicExtended = New Form With {
            .ShowInTaskbar = False,
            .MaximizeBox = False,
            .ControlBox = False,
            .Location = New Point(Me.Width + locationForm.X, Me.Height + locationForm.Y),
            .StartPosition = FormStartPosition.Manual,
            .FormBorderStyle = FormBorderStyle.None,
            .Size = New Size(Me.Image.Width \ 2, Me.Image.Height \ 2) ' 可根据需要调整窗口大小
        }

        Dim picBoxExtended = New PictureBox With {
            .Name = "pictureBox",
            .Image = Me.Image,
            .SizeMode = PictureBoxSizeMode.Zoom,
            .Dock = DockStyle.Fill
        }

        ' 给放大窗口和内部PictureBox添加鼠标事件
        AddHandler frmPicExtended.MouseEnter, AddressOf ExtendedControl_MouseEnter
        AddHandler frmPicExtended.MouseLeave, AddressOf ExtendedControl_MouseLeave
        AddHandler picBoxExtended.MouseEnter, AddressOf ExtendedControl_MouseEnter
        AddHandler picBoxExtended.MouseLeave, AddressOf ExtendedControl_MouseLeave

        frmPicExtended.Controls.Add(picBoxExtended)
        frmPicExtended.BringToFront()
        frmPicExtended.Show()
    End Sub

    Private Sub PictureBox_MouseLeave(ByVal sender As Object, ByVal e As EventArgs)
        ' 延迟判断,避免鼠标从原控件移到放大窗口时误关闭
        Task.Delay(100).ContinueWith(Sub()
                                         If Not _isMouseOverExtended AndAlso Not Me.ClientRectangle.Contains(Me.PointToClient(Cursor.Position)) Then
                                             Me.Invoke(Sub()
                                                           If frmPicExtended IsNot Nothing Then
                                                               frmPicExtended.Dispose()
                                                               frmPicExtended = Nothing
                                                           End If
                                                       End Sub)
                                         End If
                                     End Sub)
    End Sub

    Private Sub ExtendedControl_MouseEnter(ByVal sender As Object, ByVal e As EventArgs)
        _isMouseOverExtended = True
    End Sub

    Private Sub ExtendedControl_MouseLeave(ByVal sender As Object, ByVal e As EventArgs)
        ' 判断鼠标是否真的离开放大窗口区域
        If Not frmPicExtended.ClientRectangle.Contains(frmPicExtended.PointToClient(Cursor.Position)) Then
            _isMouseOverExtended = False
            ' 关闭窗口
            frmPicExtended.Dispose()
            frmPicExtended = Nothing
        End If
    End Sub

    Function PointToCurrentScreen(ByVal self As Control, ByVal location As Point) As Point
        Dim screenBounds = Screen.FromControl(self).Bounds
        Dim globalCoordinates = self.PointToScreen(location)
        Return New Point(globalCoordinates.X - screenBounds.X, globalCoordinates.Y - screenBounds.Y)
    End Function
End Class

修改说明

  1. 新增_isMouseOverExtended变量,跟踪鼠标是否停留在放大窗口内
  2. 给放大窗口和内部的PictureBox都添加鼠标进入/离开事件,确保鼠标在窗口区域内时不会触发关闭
  3. 在原PictureBox的MouseLeave事件中加入延迟判断,避免鼠标从原控件移到放大窗口时误关闭
  4. 放大窗口的MouseLeave事件中,判断鼠标是否真的离开窗口区域,确认后关闭窗口并释放资源

内容的提问来源于stack exchange,提问作者8oris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:32:02