【问题标题】:Why is the text not showing up on screen?为什么文字没有显示在屏幕上?
【发布时间】:2021-10-09 08:09:24
【问题描述】:

我正在尝试创建一个倒计时,其中显示文本“GAME STARTS IN:”,并使用 for 循环和 Thread.Sleep 变量从三个倒计时。我首先使用设计器创建“游戏开始于:”部分,但在变量不显示后,我将其移至代码中。现在什么都没有出现。这就是我现在的计时器方法中的内容:
如果 (!countedDown)
倒计时();

Countdown.Hide();

然后在 DoCountdown 方法中:

this.Countdown.BackColor = System.Drawing.Color.Transparent;                                                               
this.Countdown.ForeColor = System.Drawing.Color.White;
this.Countdown.Location = new System.Drawing.Point(360, 17);
this.Countdown.Name = "Countdown";
this.Countdown.Font = new System.Drawing.Font("Segoe UI", 12F, 
System.Drawing.FontStyle.Regular, 
System.Drawing.GraphicsUnit.Point);
this.Countdown.Size = new System.Drawing.Size(185, 24);
this.Countdown.TabIndex = 6;
                       
 countedDown = true;
 for (int i = 3; i > 0; i--)
 {
    Countdown.Text = "GAME STARTS IN: " + i;
    System.Threading.Thread.Sleep(1000);
 }

我在 System.Threading.Thread.Sleep(100) 处设置了一个断点,一切看起来都很正常。 Countdown.Text 等于“GAME STARTS IN: 3”。尝试集成解决方案后,文本未显示。这是我的代码中的更多上下文:

这是我的开始屏幕表单

   private void QuitGame(object sender, EventArgs e)
   {
      Application.Exit();
   }

    private void StartMultiplayerGame(object sender, EventArgs e)
    {
        GameScreen startGame = new GameScreen();
        startGame.Show();
        Hide();
    }

【问题讨论】:

  • Countdown.Text = "GAME STARTS IN: " + i;for 循环完成之前不会更新。
  • 您可以在循环中添加一个 Countdown.Refresh()...但是像这样锁定主线程是不好的做法...尝试使用带有事件的 Timer。
  • 我建议启动Timer,它每 1000 毫秒触发一次,并简单地保持全局计数...当它达到 3 时,停止计时器并继续。
  • 我会试试这个,但我可能会遇到一些麻烦,对 c# 和 winForms 不是很熟悉。
  • 或许可以考虑微软的响应式框架,你可以这样做:Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1.0)).Take(3).ObserveOn(this).Subscribe(x => Countdown.Text = $"GAME STARTS IN: {3 - x}", () => Countdown.Text = $"Started");

标签: c# string winforms variables textlabel


【解决方案1】:

试试下面的方法。一个按钮用于启动计时器并设置初始值。

int count = 3;
private void button2_Click(object sender, EventArgs e) {
  timer1.Interval = 1000;
  count = 3;
  label1.Text = "GAME STARTS IN: " + count;
  timer1.Start();
}

private void timer1_Tick(object sender, EventArgs e) {
  count--;
  if (count != 0) {
    label1.Text = "GAME STARTS IN: " + count;
  }
  else {
    timer1.Stop();
    label1.Text = "GAME STARTED";
    MessageBox.Show(" -> GO");
  }
}

按 OP cmets 编辑。

在开始屏幕表单中尝试这样的代码...

private void StartMultiplayerGame(object sender, EventArgs e) {
  count = 3;
  label1.Text = "GAME STARTS IN: " + count;
  timer1.Start();
}

然后把定时器代码改成……

private void timer1_Tick(object sender, EventArgs e) {
  count--;
  if (count != 0) {
     label1.Text = "GAME STARTS IN: " + count;;
  }
  else {
    timer1.Stop();
    label1.Text = "Game Started";
    GameScreen startGame = new GameScreen();
    startGame.Show();
    this.Hide();
  }
}

【讨论】:

  • 是否有可能有一种方法来创建计时器,因为我希望倒计时发生多次?我正在做一个乒乓球比赛,所以当球离开屏幕时它会重置,计时器从三开始倒计时,然后计时器结束比赛继续进行。
  • 你可以使用同样的Timer...只需调用它的timer1.Start()方法再次使用它。
  • 显示给您带来问题的代码。我测试了代码,它按预期工作,所以我只能猜测你做错了什么。而且你在自相矛盾......首先你说...... “我希望有一种方法可以让它工作而无需点击任何东西。”......然后下一句......。 “我希望有一个延迟,这样当你在主菜单中点击开始游戏时……”……?您可以在任何地方启动计时器。此外,当您启动计时器时......您需要在启动计时器之前设置count = 3。请显示您更新的代码。 edit你的问题添加代码。
  • 如果您希望游戏在倒计时后开始...那么您需要在计数达到零 (0) 时在 TIMER 中开始游戏。换句话说......在我的代码中,你看到MessageBox.Show(" -> GO");......这是你开始游戏的地方。
  • 我有一个包含开始游戏按钮的 startScreen 表单。由于倒计时和计时器采用单独的形式,我如何在没有 CS0103 错误的情况下实现您的代码?
【解决方案2】:

循环阻塞主线程以刷新 UI,因此可以通过将循环移动到单独的方法来归档所需的场景

void doCountDown()
        {
            for (int i = 10; i > 0; i--)
            {
                setCountDownText( "GAME STARTS IN: " + i);
                System.Threading.Thread.Sleep(1000);
            }
        }

创建启动此方法的新线程

 new System.Threading.Thread(new System.Threading.ThreadStart(doCountDown)).Start();

并且由于需要在另一个线程中更新 UI 并使其安全地将 setText 分隔在一个单独的方法中,该方法基于调用属性所需的检查进行更新,这将使其在所有情况下都可以工作

 void setCountDownText(string txtValue)
        {
            if (Countdown.InvokeRequired)
            {
                Action safeWrite = delegate { setCountDownText(txtValue); };
                Countdown.Invoke(safeWrite);
            }
            else
                Countdown.Text = txtValue;
        } 

【讨论】:

  • 我尝试了这个解决方案,虽然游戏确实等待了三秒钟,但很遗憾,没有显示任何文字。
  • @ineedhelp 请检查我的存储库中附加的运行示例github.com/mhassanshaker/GameCountDown
【解决方案3】:

执行此操作的“现代”方式是使用 async/await。

例如,从按钮处理程序启动 DoCountdown() 可能如下所示:

async void testBtn_Click(object sender, EventArgs e)
{
    await DoCountdown();
}

async Task DoCountdown()
{
    // <Initialisation of Countdown elided for brevity>

    for (int i = 3; i > 0; i--)
    {
        Countdown.Text = "GAME STARTS IN: " + i;
        await Task.Delay(1000);
    }
}

但是,任何调用 DoCountdown() 都需要声明为 async,等等调用树。

请注意,将async void 而不是async Task 作为异步方法的返回类型的唯一可接受的地方是该方法是事件处理程序,例如上例中的按钮处理程序。

【讨论】:

  • 再一次,这里没有显示任何文字:(
  • @ineedhelp 我发布的代码运行良好(我已经尝试过了)所以我想你在做一些不同的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-20
  • 2020-04-28
相关资源
最近更新 更多