自定义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
修改说明
- 新增
_isMouseOverExtended变量,跟踪鼠标是否停留在放大窗口内 - 给放大窗口和内部的PictureBox都添加鼠标进入/离开事件,确保鼠标在窗口区域内时不会触发关闭
- 在原PictureBox的
MouseLeave事件中加入延迟判断,避免鼠标从原控件移到放大窗口时误关闭 - 放大窗口的
MouseLeave事件中,判断鼠标是否真的离开窗口区域,确认后关闭窗口并释放资源
内容的提问来源于stack exchange,提问作者8oris
相关产品推荐
相关产品推荐

