C# WinForm中如何判断鼠标位于TableLayoutPanel单元格边框附近
在WinForms中实现TableLayoutPanel鼠标靠近单元格边框时显示十字光标
需求:在Windows窗体的TableLayoutPanel控件中,当鼠标指针位于或靠近单元格边框时,将光标样式切换为十字形。
最初尝试通过MouseMove事件获取鼠标所在单元格位置,但没法实现需求,后来发现问题和单元格尺寸类型(Absolute/Percent)有关,最终解决后分享可用代码:
bool calcCells = false; List<float> XCoordinates = new List<float>(); List<float> YCoordinates = new List<float>(); public Form3() { InitializeComponent(); // 通过反射设置DoubleBuffered属性(按需使用) var flags = BindingFlags.Instance | BindingFlags.NonPublic; tlp1.GetType().GetProperty("DoubleBuffered", flags).SetValue(tlp1, true); tlp1.Layout += tlp1_Layout; tlp1.CellPaint += tlp1_CellPaint; tlp1.MouseMove += tlp1_MouseMove; } // 生成单元格边框的X坐标列表 private void CreateXCoordinateList() { XCoordinates.Clear(); // 假设首列和末列的尺寸类型为Absolute float tlpWidth = tlp1.Width - tlp1.ColumnStyles[0].Width - tlp1.ColumnStyles[tlp1.ColumnCount - 1].Width; float x = 0; for (int i = 0; i < tlp1.ColumnCount; i++) { if(tlp1.ColumnStyles[i].SizeType == SizeType.Absolute) x += tlp1.ColumnStyles[i].Width; else if(tlp1.ColumnStyles[i].SizeType == SizeType.Percent) { double k = tlpWidth * tlp1.ColumnStyles[i].Width * 0.01; x += Convert.ToSingle(k); } XCoordinates.Add(x); } } // 生成单元格边框的Y坐标列表 private void CreateYCoordinateList() { YCoordinates.Clear(); // 假设首行和末行的尺寸类型为Absolute float tlpHeight = tlp1.Height - tlp1.RowStyles[0].Height - tlp1.RowStyles[tlp1.RowCount - 1].Height; float y = 0; for (int i = 0; i < tlp1.RowCount; i++) { if (tlp1.RowStyles[i].SizeType == SizeType.Absolute) y += tlp1.RowStyles[i].Height; else if (tlp1.RowStyles[i].SizeType == SizeType.Percent) { double k = tlpHeight * tlp1.RowStyles[i].Height * 0.01; y += Convert.ToSingle(k); } YCoordinates.Add(y); } } private void tlp1_Layout(object sender, LayoutEventArgs e) => calcCells = true; private void tlp1_CellPaint(object sender, TableLayoutCellPaintEventArgs e) { if (calcCells) { CreateXCoordinateList(); CreateYCoordinateList(); // 最后一个单元格绘制完成后停止计算 if (e.Column == tlp1.ColumnCount - 1 && e.Row == tlp1.RowCount - 1) calcCells = false; } } private void tlp1_MouseMove(object sender, MouseEventArgs e) { // 对比鼠标位置与边框坐标,误差≤4像素时切换光标 if (MouseNearCellBorderXAxis(e) || MouseNearCellBorderYAxis(e)) tlp1.Cursor = Cursors.Cross; else tlp1.Cursor = Cursors.Default; } private bool MouseNearCellBorderXAxis(MouseEventArgs e) { float x = e.Location.X; foreach (float border in XCoordinates) { double difference = Math.Abs(x - border); if (difference <= 4) return true; } return false; } private bool MouseNearCellBorderYAxis(MouseEventArgs e) { float y = e.Location.Y; foreach (float border in YCoordinates) { double difference = Math.Abs(y - border); if (difference <= 4) return true; } return false; }
关键逻辑说明
- 用
XCoordinates和YCoordinates两个列表存储所有单元格边框的精确坐标,适配Absolute和Percent两种尺寸类型 - 控件布局变更时(如窗口大小调整),通过
Layout事件标记需要重新计算坐标,在CellPaint事件中完成计算(确保所有单元格布局完成后停止) MouseMove事件中实时判断鼠标位置是否靠近边框,误差范围设为4像素,兼顾操作灵敏度和误触率- 通过反射设置
DoubleBuffered属性,避免控件重绘时出现闪烁
内容的提问来源于stack exchange,提问作者Gokhan
相关产品推荐
相关产品推荐

