在每个FOR循环中在屏幕上显示结果

本文关键字:显示 结果 屏幕 循环 FOR | 更新日期: 2023-09-27 18:08:43

我正在为飞机编写一个随机座位生成器,并在其中使用for循环。问题是,只有当一切都完成后,才会显示已占用的座位。我想让它在每次迭代中,显示随机选择的座位。怎么做呢?

这是我正在使用的代码。飞机有118个座位,每个座位都有一个名为"img_Seat_X"的图片框。我知道有更好的方法,但这是我能在一个小时内想到的。提前感谢!

private void btn_WeightBalance_Populate_Click(object sender, EventArgs e)
{
                int passengers = Convert.ToInt32(txt_WeightBalance_Passengers.Text);
                List<int> seats = new List<int> { }; numberofSeats = 119;
                if (rdb_WeightBalance_190.Checked == true)
                    numberofSeats = 107;
                for (int x = 0; x < Passengers; x++)
                {
                    int randomNumber = RandomNumber(1, numberofSeats);
                    if (seats.Contains(randomNumber))
                        x--;
                    else
                    {
                        seats.Add(randomNumber);
                        Control[] seat = this.panWeightBalance.Controls.Find("img_Seat_" + randomNumber, true);
                        seat[0].Visible = true;
                        seat[0].Refresh();
                    }
                }
}

明白了!每次迭代中的一个简单的Refresh()就完成了这项工作!我还用if语句替换了while循环。

在每个FOR循环中在屏幕上显示结果

必读:Windows消息循环

@rice指出了我明显的错误,抱歉把你引到错误的道路上,谢谢rice。

无论如何,你可以在一个单独的线程中执行工作,并使用BackgroundWorker类向UI trhead发布更新。下面是一个简单的示例,它在响应按钮点击时更新表单上的标签100次:

public partial class Form1 : Form
{
    BackgroundWorker _worker;
    public Form1()
    {
        InitializeComponent();
        _worker = new BackgroundWorker();
        _worker.WorkerReportsProgress = true;
        _worker.DoWork += _worker_DoWork;
        _worker.ProgressChanged += _worker_ProgressChanged;
    }
    private void _worker_ProgressChanged( object sender, ProgressChangedEventArgs e )
    {
        label1.Text = e.UserState.ToString();
    }
    private void _worker_DoWork( object sender, DoWorkEventArgs e )
    {
        for( int i = 0; i < 100; ++i )
        {
            _worker.ReportProgress( i, i );
            // allow some time between each update,
            // for demonstration purposes only.
            System.Threading.Thread.Sleep( 15 );
        }
    }   
    private void button1_Click( object sender, EventArgs e )
    {
        _worker.RunWorkerAsync();
    }
}

本质上,您需要生成一个后台线程来进行处理,然后每次使用BeginInvoke来更新用户界面元素。在这个解决方案中有一些问题需要解决。用户现在可以继续点击按钮,它将产生额外的后台线程。最常见的机制是弹出一个进度对话框(我讨厌模态对话框,所以不要这样做),或者通过禁用按钮来防止用户执行两次操作,直到工作完成。

    private void btn_WeightBalance_Populate_Click(object sender, EventArgs e)
    {
        int passengers = Convert.ToInt32(txt_WeightBalance_Passengers.Text);
        List<int> seats = new List<int> { }; numberofSeats = 119;
        if (rdb_WeightBalance_190.Checked == true)
            numberofSeats = 107;
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += delegate
        {
            for (int x = 0; x < passengers; x++)
            {
                int randomNumber = RandomNumber(1, numberofSeats);
                while (seats.Contains(randomNumber))
                {
                    randomNumber = RandomNumber(1, numberofSeats);
                }
                seats.Add(randomNumber);
                UpdateSeat(randomNumber);
            }
        };
        worker.RunWorkerAsync();
    }
    /// <summary>
    /// Update a seat control in the correct UI thread. If this
    /// method is invoked in a thread besides the UI thread it will use
    /// BeginInvoke to put it on the UI thread queue.
    /// </summary>
    /// <param name="seatNumber"></param>
    private void UpdateSeat (int seatNumber)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke((Action)(() => UpdateSeat(seatNumber)));
        }
        else
        {
            Control[] seat = this.Controls.Find("img_Seat_" + seatNumber, true);
            seat[0].Visible = true;
        }
    }

还有其他问题需要解决。例如,当调用FindControl而不处理txt_WeightBalance_Passengers中的畸形数字文本时,假设控件将始终存在。

更新'cute'答案

    private void btn_WeightBalance_Populate_Click(object sender, EventArgs e)
    {
        var passengers = Convert.ToInt32(txt_WeightBalance_Passengers.Text);
        numberofSeats = rdb_WeightBalance_190.Checked ? 107 : 119;
        var worker = new BackgroundWorker();
        worker.DoWork += delegate
        {
            var random = new Random();
            foreach (var seatNumber in Enumerable.Range(1, Int32.MaxValue).Select(r => random.Next(numberofSeats)).Distinct())
            {
                var randomSeat = seatNumber;
                BeginInvoke((Action)(() =>
                {
                    var seat = this.Controls.Find("img_Seat_" + randomSeat, true);
                    seat[0].Visible = true;
                }));                    
                if (--passengers <= 0) break;
            }
        };
        worker.RunWorkerAsync();
    }

不是获得一个随机数,检查它是否被占用,然后分配它,而是获取一个列表1 thru numberOfSeats并对其进行洗牌,并开始按这种随机洗牌的顺序分配座位。这样可以避免while (Seats.Contains(randomNumber)){...}的恶性循环。

您正在编写的代码仅从最多119个座位中随机选择座位。即使您使用的是旧硬件,它也应该运行速度非常快,所以我不明白为什么您需要显示每个座位的分配情况。在我看来,你应该把代码拆分。计算座位分配,然后按你喜欢的方式显示。

下面是随机选择座位的代码:

var passengers = Convert.ToInt32(txt_WeightBalance_Passengers.Text);
var numberofSeats = rdb_WeightBalance_190.Checked ? 107 : 119;
// Creates an array from 0 .. numberofSeats - 1
var seats = Enumerable.Range(0, numberofSeats).ToArray();
//Shuffle the first "passengers" elements of the array
for (var i = 0; i < passengers; i++)
{
    var j = RandomNumber(0, numberofSeats);
    var x = seats[i];
    seats[i] = seats[j];
    seats[j] = x;
}
//Find the first "passengers" count of seat controls
var controls = (
        from i in seats.Take(passengers)
        let c = this.Controls.Find("img_Seat_" + i, true).FirstOrDefault()
        where c != null
        select c
    ).ToArray();

现在要将座椅控制设置为可见,只需执行以下操作:

foreach (var c in controls)
{
    c.Visible = true;
}

如果你有一个特定的需要在后台运行这个并更新UI,你可以这样做:

var t = new System.Threading.Thread(new ThreadStart(() =>
{
    foreach (var c in controls)
    {
        this.Invoke(new Action(() => c.Visible = true));
        // Thread.Sleep(100); // Slow it down if you wish...
    }
}));
t.Start();

这个对你有用吗?

问题是,只有当所有的事情都完成了,才会显示出有人坐。

这是在for循环中看到的while循环:

while (Seats.Contains(randomNumber))
{
    randomNumber = RandomNumber(1, numberofSeats);
}
Seats.Add(randomNumber); 

你可能忘记在while循环中添加"Add"方法。还要检查退出条件-我猜您想要在Contains返回true时退出while循环。