问题描述
好的,首先是 28x28 正方形的按钮。当我使用递归函数禁用所有没有文本的按钮(button.Name = string.Empty
)时,例如当我单击图像中的 8x2 按钮时,递归函数禁用从 8x2 到 8x8 的所有按钮一个一个地向东环形。 (代码 1)
但是当我向 LoopControlEmpty
函数添加更多递归方式时,以不同的方式禁用更多块,如 N、NW、SE 等。程序给了我一个 StackOverFlow 错误。 (代码 2)
我需要找到一种方法来调用带有名称的按钮,而不是将所有 81 个按钮都转入 foreach 循环 但可能它会再次给我同样的错误,因为很多时候它会去递归。或者我需要找到另一种算法来禁用按钮。
按钮名称就是这样 => 用于 0x0 中的按钮 button.Name = "button0x0"
代码 1
private void btn_Click(object sender,EventArgs e)
{
// Using sender as Button because i need to reach that buttons properties.
Button btn = sender as Button;
if (btn.Text == "M")
{
btn.BackColor = Color.FromArgb(255,0);
foreach (Button button in this.Controls)
{
button.Enabled = false;
}
}
else if (btn.Text == string.Empty)
{
btn.Enabled = false;
LoopControlEmpty(btn);
}
else
btn.Enabled = false;
}
public void LoopControlEmpty(Button btn)
{
foreach (Button btnIn in this.Controls)
{
// Going East
if (btn.Location.X + 28 == btnIn.Location.X && btn.Location.Y == btnIn.Location.Y && btnIn.Text == string.Empty)
{
btnIn.Enabled = false;
LoopControlEmpty(btnIn);
continue;
}
}
return;
}
代码 2
public void LoopControlEmpty(Button btn)
{
foreach (Button btnIn in this.Controls)
{
// Going East
if (btn.Location.X + 28 == btnIn.Location.X && btn.Location.Y == btnIn.Location.Y && btnIn.Text == string.Empty)
{
btnIn.Enabled = false;
LoopControlEmpty(btnIn);
continue;
}
//Going north
if (btn.Location.X == btnIn.Location.X && btn.Location.Y + 28 == btnIn.Location.Y && btnIn.Text == string.Empty)
{
btnIn.Enabled = false;
LoopControlEmpty(btnIn);
continue;
}
//Goint South-West
if (btn.Location.X - 28 == btnIn.Location.X && btn.Location.Y -28 == btnIn.Location.Y && btnIn.Text == string.Empty)
{
btnIn.Enabled = false;
LoopControlEmpty(btnIn);
continue;
}
}
return;
}
解决方法
原因是,如果你向东走,然后向西南走,然后向北走,就会到达起点。这将永远持续下去。
您需要跟踪哪些按钮已被处理。这可以例如使用列表完成:您将所有 81 个按钮都放入列表中,然后从列表中删除已处理的按钮。
public IList<Button> GetAllButtons()
{
var buttonsToProcess = new List<Button>();
foreach (Button btnIn in this.Controls)
{
buttonsToProcess.Add(btnIn);
}
return buttonsToProcess;
}
public void LoopControlEmpty(Button btn,IList<Button> buttonsToProcess)
{
var neighbors = new List<Button>();
foreach (Button btnIn in buttonsToProcess)
{
if (btnIn.Text != string.Empty) continue;
// Going East
if (btn.Location.X + 28 == btnIn.Location.X && btn.Location.Y == btnIn.Location.Y)
{
neighbors.Add(btnIn);
}
//Going North
if (btn.Location.X == btnIn.Location.X && btn.Location.Y + 28 == btnIn.Location.Y)
{
neighbors.Add(btnIn);
}
//Goint South-West
if (btn.Location.X - 28 == btnIn.Location.X && btn.Location.Y -28 == btnIn.Location.Y)
{
neighbors.Add(btnIn);
}
}
// Make sure to not process them again
foreach(Button neighbor in neighbors)
{
buttonsToProcess.Remove(neighbor);
}
// Process the neighbors
foreach(Button neighbor in neighbors)
{
neighbor.Enabled = false;
LoopControlEmpty(neighbor,buttonsToProcess);
}
}
,
这不是一个好方法。在您的按钮矩阵中创建您自己的具有逻辑坐标属性的按钮。
public class MineButton : Button
{
public int Row { get; set; }
public int Column { get; set; }
}
您还可以将其添加为具有枚举类型的状态属性。
然后以编程方式创建按钮并将它们添加到二维数组(矩阵)中。
private const int FieldWidth = 28,FieldHeight = 28;
private MineButton[,] Field = new MineButton[FieldWidth,FieldHeight];
在表单构造函数中
InitializeComponent();
for (int row = 0; row < FieldWidth; x++) {
for (int col = 0; col < FieldHeight; col++) {
var btn = new MineButton{
Row = row,Column = col,Location = new Point(10 + 28 * col,10 + 28 * row),Size = new Size(24,24)
}
Field[col,row] = btn;
Controls.Add(btn);
}
}
现在查找和处理按钮变得更加容易。
private void btn_Click(object sender,EventArgs e)
{
var btn = sender as MineButton;
int row = btn.Row;
int col = btn.Col;
...
}
既然您有了坐标,就可以轻松地在 Field
矩阵中找到相邻的按钮。
if (col < FieldWidth - 1) {
var buttonToTheRight = Field[col + 1,row];
...
}
您还应该仅处理未处理的按钮以停止递归。例如
if (btn.Enabled) {
btn.Enabled = false;
do recursive calls,etc.
}
如果按钮有一个状态属性,你也可以根据它的状态做出这个决定。