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

如何在C# WinForms中创建响应式可点击单败淘汰赛对阵图

C# WinForms单败淘汰赛对阵图实现方案

一、按X/Y坐标顺序生成对阵按钮

要实现规则的对阵布局,核心是先计算淘汰赛的轮次结构,再按轮次横向排列、按对阵关系纵向对齐按钮:

1. 先梳理淘汰赛的轮次与参赛结构

单败淘汰赛需处理非2的幂次参赛人数(比如100人),步骤如下:

  • 计算总轮次:int totalRounds = (int)Math.Ceiling(Math.Log(participantCount, 2));
  • 每轮参赛数:第一轮为participantCount,后续每轮为上一轮参赛数向上取整除以2(奇数时1人轮空直接晋级)
  • 每轮比赛数:上一轮参赛数除以2后向上取整

2. 按坐标生成按钮

固定轮与轮之间的横向间距(比如150px),第一轮按钮垂直均匀分布(比如间距60px),后续轮次的按钮Y坐标为对应上一轮两个按钮的中点:

private void GenerateBracket(int participantCount)
{
    int roundSpacing = 150; // 轮与轮的横向间距
    int buttonHeight = 40;
    int buttonWidth = 120;
    int firstRoundTop = 20;
    int firstRoundSpacing = 60; // 第一轮按钮垂直间距

    // 清空已有控件
    panelBracket.Controls.Clear();

    // 计算每轮的参赛人数
    List<int> participantsPerRound = new List<int>();
    int current = participantCount;
    while (current > 1)
    {
        participantsPerRound.Add(current);
        current = (current + 1) / 2; // 向上取整除以2
    }
    participantsPerRound.Add(1); // 最终冠军

    // 逐轮生成按钮
    for (int roundIndex = 0; roundIndex < participantsPerRound.Count; roundIndex++)
    {
        int count = participantsPerRound[roundIndex];
        int x = roundIndex * roundSpacing + 20;

        // 计算当前轮按钮的Y坐标起始点
        int totalHeight = (count - 1) * firstRoundSpacing + buttonHeight;
        int startY = (panelBracket.Height - totalHeight) / 2;
        if (startY < 20) startY = 20;

        for (int i = 0; i < count; i++)
        {
            Button btn = new Button();
            btn.Size = new Size(buttonWidth, buttonHeight);
            btn.Location = new Point(x, startY + i * firstRoundSpacing);
            btn.Text = $"Round {roundIndex + 1} - {i + 1}";
            btn.Click += BracketButton_Click;
            panelBracket.Controls.Add(btn);
        }

        // 调整下一轮的垂直间距(每轮间距翻倍,保证上下对齐)
        firstRoundSpacing *= 2;
    }
}

private void BracketButton_Click(object sender, EventArgs e)
{
    Button btn = sender as Button;
    btn.BackColor = Color.Green;
    // 可扩展:记录该按钮对应的选手,用于后续轮次的关联逻辑
}

二、大数量参赛的响应式适配方案

针对100人这类大规模参赛场景,可采用以下几种适配方式:

1. 滚动容器方案

将所有对阵按钮放在Panel控件中,开启自动滚动:

  • 设置panelBracket.Dock = DockStyle.Fill;
  • 开启panelBracket.AutoScroll = true;
  • 生成按钮时无需考虑窗体大小,超出部分通过滚动条查看

2. 缩放功能方案

通过自定义绘制实现整体缩放:

  • 使用Panel作为绘制容器,在Paint事件中绘制对阵图(包括按钮和连接线)
  • 监听鼠标滚轮事件,调整缩放比例,用Matrix实现绘制缩放:
private float zoomFactor = 1.0f;

private void panelBracket_MouseWheel(object sender, MouseEventArgs e)
{
    if (e.Delta > 0)
        zoomFactor += 0.1f;
    else
        zoomFactor = Math.Max(0.5f, zoomFactor - 0.1f);
    panelBracket.Invalidate();
}

private void panelBracket_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.ScaleTransform(zoomFactor, zoomFactor);
    // 在这里绘制所有按钮、连接线等内容
}

3. 轮次折叠方案

只显示当前进行的轮次,其他轮次可折叠:

  • 为每轮添加折叠/展开按钮,点击时隐藏/显示对应轮次的所有按钮
  • 适合关注当前赛程的场景,减少界面拥挤

4. 自适应布局调整

窗体大小变化时,重新计算按钮位置和大小:

  • 监听窗体Resize事件,调用GenerateBracket重新生成布局
  • 将轮间距、按钮大小设置为窗体宽度/高度的比例值,而非固定像素

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 11:01:01