2013-04-11 3 views
0

В настоящее время я работаю над приложением, которое должно использовать форму, чтобы заблокировать пользователя от использования основной формы на несколько секунд. Хотя запуск кода в основном потоке, похоже, в порядке, метки в всплывающей форме не отображаются примерно в течение секунды, когда появляется форма. Я думал, что если я запустил эту форму в отдельном потоке, рендеринг будет намного более гладким. Теперь рендеринг настолько плавный, что форма исчезает сразу после рендеринга. Таймер установлен на пять секунд, при этом на экране отображается метка. Вот соответствующий код, вызывающий новую нить и форму:WinForm исчезает в многопоточном приложении C++/CLI

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 по-прежнему выполняется, и таймер по-прежнему работает с Объединением, блокируя ввод пользователя в течение пяти секунд, но блокировать экран нечем.
  3. Я прочитал несколько вопросов о SO, я думаю, что наиболее актуальным является WinForms multithreading issue - хотя я чувствую, что это может быть излишним для этой ситуации.

Если у вас есть идеи относительно того, что мне нужно сделать, чтобы иметь гладкую визуализацию для обеих форм, пожалуйста, дайте мне знать. Благодаря!

+0

Вы установили свойство _Interval_ таймера?Он не показан в примере кода. – Jairo

+0

Извините - он был установлен в 1000 в дизайнере формы. 'this-> timerPrep-> Interval = 1000; \t \t \t это-> timerPrep-> Tick + = gcnew System :: EventHandler (это и & GetReady :: timerPrep_Tick); ' – floppsb

ответ

1

Отображение пользовательского интерфейса на рабочем потоке заполнено ловушками и сюрпризами. Основная проблема, с которой вы сталкиваетесь, заключается в том, что поток не перекачивает контур сообщения. Необходимо, прежде всего, убедиться, что окно может получать сообщения Windows и гарантировать, что поток не будет немедленно завершен. Помимо рекомендации Хаиро использовать ShowDialog(), решение шаблонным является:

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

Там же, поток, который отображает окна всегда должен быть STA нити. Деталь реализации для COM и требуется, чтобы получить такие вещи, как буфер обмена, перетаскивание + каплю и диалоговые окна оболочки операционное правильно:

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

И вообще есть проблема Z-порядка с окнами, которые отображаются в главном потоке. С неприятной привычкой ваше окно исчезает за окном, принадлежащим основной теме. Нет хорошего решения для этого.

+0

Упс, я не знал о потоках сообщений и потоках STA. Каждый ответ, который вы публикуете, является для меня новой нотой. Спасибо, Ханс. – Jairo

1

Проблема заключается в том showModalPopup использует Показать метод вместо ShowDialog. Поток начинается, показывает форму (она не блокирует выполнение), запускает таймер, заканчивается и присоединяется к основному потоку. Тема, в которой была создана форма, была завершена, и она здесь, где возникают проблемы многопоточности winforms.

Сначала запустите таймер, а затем покажите модальное окно с ShowDialog. Что-то вроде этого:

System::Void showModalPopup() 
{    
    startTimer(); 
    this->ShowDialog(); 
} 
Смежные вопросы