0

我目前正在开发一个需要使用表单来阻止用户在几秒钟内使用主表单的应用程序。尽管在主线程上运行代码似乎没问题,但当表单首次出现时,弹出表单上的标签不会呈现大约一秒钟。我认为如果我在单独的线程上运行该表单,渲染会更加流畅。渲染现在非常流畅,渲染后表单立即消失。计时器设置为五秒钟,屏幕上的标签倒计时。这是调用新线程和表单的相关代码:

System::Void MainScreen::runGame(int playerTurn) {
    Thread ^ t = gcnew Thread(gcnew ThreadStart(gcnew MainScreen(),
        &MainScreen::showModalDialog));
        t->Start();
        t->Join();

        InitializeDice();
        startTimer();
}

System::Void MainScreen::showModalDialog() {
    GetReady ^ gr = gcnew GetReady();
    gr->showModalPopup();
}

这是表单内的代码:

public:
    GetReady(void)
    {
        InitializeComponent();
    }

    System::Void showModalPopup() {
            this->Show();
            startTimer();

        }
private: System::Void timerPrep_Tick(System::Object^  sender, System::EventArgs^  e) {
         ts = ts->Subtract(TimeSpan(0, 0, 1));
         if (ts->TotalSeconds <= 0) {
             finishTimer();
         } else {
             lblTimer->Text = ts->ToString("mm\\:ss");
         }
    }

    System::Void startTimer() {
         array<String ^>^ minSec = gcnew array<String ^>(2);
         minSec = lblTimer->Text->Split(':');
         ts = gcnew TimeSpan(0, Convert::ToInt32(minSec[0]), Convert::ToInt32(minSec[1]));
         Thread::Sleep(900);
         timerPrep->Start();
     }

     System::Void finishTimer() {
         timerPrep->Stop();
         lblTimer->Text = "GO!!!";
         Thread::Sleep(900);
         this->Close();
     }

我理想的解决方案是使用线程生成新表单,以便在主表单和弹出表单中的渲染都很流畅。

我尝试过的事情:

  1. 将 this->Show() 移动到我能想到的所有地方。
  2. 我添加了 t->Join() 以查看主线程是否试图使主窗口重新成为焦点。线程 t 仍然执行,并且计时器仍然与 Join 一起正常运行,阻止用户输入五秒钟 - 但没有任何东西可以阻止屏幕。
  3. 我已经阅读了一些关于 SO 的问题,我认为最相关的是WinForms 多线程问题——尽管我觉得这对于这种情况来说可能是矫枉过正的。

如果您对我需要做些什么来为两种表单进行平滑渲染有任何想法,请告诉我。谢谢!

4

2 回答 2

1

问题是 showModalPopup 使用Show方法而不是ShowDialog。线程启动,显示表单(它不会阻止执行),启动计时器,结束并加入主线程。创建表单的线程已经完成,winforms多线程问题就在这里。

首先启动计时器,然后使用ShowDialog显示模式窗口。像这样的东西:

System::Void showModalPopup() 
{            
   startTimer();
   this->ShowDialog();
}
于 2013-04-12T10:25:32.757 回答
1

在工作线程上显示 UI 充满了陷阱和惊喜。您在这里遇到的主要问题是线程不会发送消息循环。首先需要确保窗口可以接收 Windows 消息并确保线程不会立即终止。除了 Jairo 建议使用 ShowDialog() 之外,样板解决方案是:

System::Void MainScreen::showModalDialog() {
    Application::Run(gcnew GetReady);
}

此外,显示窗口的线程应该始终是 STA 线程。COM 的实现细节,需要让剪贴板、拖放和 shell 对话框等内容正常运行:

Thread ^ t = gcnew Thread(gcnew ThreadStart(this, &MainScreen::showModalDialog));
t->SetApartmentState(ApartmentState::STA);    
t->Start();

而且您通常在主线程上显示的窗口存在 Z 顺序问题。一个讨厌的习惯是你的窗口消失在主线程拥有的窗口后面。没有好的解决方案。

于 2013-04-12T12:49:29.253 回答