如何在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
相关产品推荐
相关产品推荐

