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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 06:05:55