forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   C++ (http://forum.boolean.name/forumdisplay.php?f=22)
-   -   Доступ к GUI с иного потока (http://forum.boolean.name/showthread.php?t=17920)

ІГРОГРАЙКО 22.02.2013 00:57

Доступ к GUI с иного потока
 
Вложений: 1
Добрый вечер вам!

CLR приложение (.Net средствами С++).
У меня есть форма, в форме есть контролы такие как кнопка, прогрес-бар, дата-грид-виев (таблица).
Все ето создавалось в основном потоке.
У меня появился новый поток после клика на кнопку и етот поток должен:
  • перерисовывать прогрес-бар
  • добавлять ечейки в дата-грид-виев
  • установить доступность (Enabled) кнопки в значение "true"
Вот код где состоялся клик и запустился новый поток:
Код:

        public:
                Thread^ processing;
                FileBase^ fileBase;

...

        private: System::Void buttonStart_Click(System::Object^  sender, System::EventArgs^  e) {
                                buttonStart->Enabled = false;
                                resultView->Rows->Clear();
                                array<String^>^ tmp = gcnew array<String^>(directoryList->Items->Count);
                                directoryList->Items->CopyTo(tmp,0);
                                fileBase = gcnew FileBase(tmp, checkboxSearchSubdir->Checked);
                                ThreadStart^ fileBaseDelegate = gcnew ThreadStart(this, &mainForm::DoProcessing);
                                processing = gcnew        Thread(fileBaseDelegate);
                                processing->Start();

                        }

Вот код функции что будет выполнять поток:
Код:

        public: void DoProcessing()
                        {
                                progressBar->Value = 0;
                                progressBar->Maximum = fileBase->candidates->Count;
                                for each(KeyValuePair<String^,Int64> iCandidate in fileBase->candidates)
                                {
                                        if (fileBase->IsDuplicate(iCandidate))
                                        resultView->Rows->Add(iCandidate.Key , iCandidate.Value.ToString());
                                        progressBar->Value++;
                                }
                                buttonStart->Enabled = true;
                        }

Но сразу же после старта потока вылетает екзепшн:
Вложение 18837

Пожалуйста подскажите, как это лучше исправить! Можно ли обойтись без множества блоков try-catch?
Заранее спасибо!

h1dd3n 22.02.2013 13:20

Ответ: Доступ к GUI с иного потока
 
Invoke();

ІГРОГРАЙКО 22.02.2013 19:51

Ответ: Доступ к GUI с иного потока
 
Да! Спасибочки!
Но как пользоваться этим Invoke() ???

Уже настрочил делегатов:
Код:

public: delegate void MyDel();
...
        public: void DoProcessing()
                        {
                                MyDel^ DelInst = gcnew MyDel(this, &mainForm::CleanProgressBar);
                                if (progressBar->InvokeRequired)
                                        DelInst->Invoke();
                                DelInst = gcnew MyDel(this, &mainForm::ResetProgressBar);
                                if (progressBar->InvokeRequired)
                                        DelInst->Invoke();


                                for each(KeyValuePair<String^,Int64> iCandidate in fileBase->candidates)
                                {
                                        if (fileBase->IsDuplicate(iCandidate))
                                        resultView->Rows->Add(iCandidate.Key , iCandidate.Value.ToString());
                                        progressBar->Value++;
                                }
                                buttonStart->Enabled = true;
                        }

...

        public: void CleanProgressBar()
                        {
                                progressBar->Value = 1;
                        }

        public: void ResetProgressBar()
                        {
                                progressBar->Maximum = fileBase->candidates->Count;
                        }

Но все тот же екзепшн вылазит!
Сразу же при: progressBar->Value = 1; :(

h1dd3n 22.02.2013 23:12

Ответ: Доступ к GUI с иного потока
 
В принципе правильное решение - это события, но когда тебе просто надо обновить прогресс бар, воротить систему событий как-то не хочется, поэтому проще воспользоваться методом Invoke.
Скопировал из своего (Это C#, но суть все равно одна):
Код:

public partial class MainForm : Form
{
//Вот сюда стоит обратить внимание
    private delegate void LogDelegate(string loginfo, Color clr);
    private readonly LogDelegate _logPtr; //readonly не обязательно
   
    public MainForm()
    {
        _logPtr = Log; //И сюда
    }
    private void Log(string loginfo, Color clr)
    {
        textboxLogConnection.SelectionStart = textboxLogConnection.Text.Length;
        textboxLogConnection.SelectionColor = clr;
        textboxLogConnection.SelectionFont = new Font(textboxLogConnection.SelectionFont, FontStyle.Bold);
        textboxLogConnection.AppendText(string.Format("[{0:00}:{1:00}:{2:00}] ", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second));
        textboxLogConnection.AppendText(loginfo + "\n");
    }

Далее там где мне надо что-то занести в лог я просто пишу
Код:

Invoke(_logPtr, "SOME MESSAGE", Color.Black);
и не парюсь о потоках.

impersonalis 24.02.2013 00:07

Ответ: Доступ к GUI с иного потока
 
[критикан]
Всё какие-то свиристелки. Почему б не использовать WinAPI? Или тут что-то про кросплатформенность - тогда Boost?[/критикан]
В своё время, когда решал подобную задачу (два потока - один постоянно крутит цикл с рассчётами, второй - ГУИ: обрабатывает кнопочки и с некоторой невысокой частотой обновляет данные о работе первого потока) опирался на статью "Организация межпотокового взаимодействия с использованием объектов ядра операционной системы" (в журнале "Вестник компьютерных и информационных технологий")

h1dd3n 24.02.2013 18:20

Ответ: Доступ к GUI с иного потока
 
Цитата:

Сообщение от impersonalis (Сообщение 253631)
[критикан]
Всё какие-то свиристелки. Почему б не использовать WinAPI? Или тут что-то про кросплатформенность - тогда Boost?[/критикан]
В своё время, когда решал подобную задачу (два потока - один постоянно крутит цикл с рассчётами, второй - ГУИ: обрабатывает кнопочки и с некоторой невысокой частотой обновляет данные о работе первого потока) опирался на статью "Организация межпотокового взаимодействия с использованием объектов ядра операционной системы" (в журнале "Вестник компьютерных и информационных технологий")

Цитата:

CLR приложение (.Net средствами С++).
..

ІГРОГРАЙКО 26.02.2013 18:20

Ответ: Доступ к GUI с иного потока
 
Спасибо большое за розяснения.
У меня было времени в обрез потому, я все переделал на BackgroundWorker...

Вот пример:
Код:

private: System::ComponentModel::BackgroundWorker^  backgroundWorker;
FileBase^ fileBase;

...

        private: System::Void buttonStart_Click(System::Object^  sender, System::EventArgs^  e) {
                                buttonStart->Enabled = false;
                                buttonCancel->Enabled = true;
                                resultView->Rows->Clear();
                                array<String^>^ tmp = gcnew array<String^>(directoryList->Items->Count);
                                directoryList->Items->CopyTo(tmp,0);
                                fileBase = gcnew FileBase(tmp, checkboxSearchSubdir->Checked);
                                progressBar->Value = 0;
                                backgroundWorker->RunWorkerAsync();
                        }

        private: System::Void buttonCancel_Click(System::Object^  sender, System::EventArgs^  e) {
                                backgroundWorker->CancelAsync();
                                buttonCancel->Enabled = false;
                                buttonStart->Enabled = true;
                                progressBar->Value = 0;
                        }

        private: System::Void backgroundWorker_DoWork(System::Object^  sender, System::ComponentModel::DoWorkEventArgs^  e) {
                                int counter = 0;
                                int percentsComplited = 0;
                                for each(KeyValuePair<String^,Int64> iCandidate in fileBase->candidates)
                                {
                                        if (backgroundWorker->CancellationPending)
                                        {
                                                return;
                                        }

                                        counter++;
                                        percentsComplited = (counter * 100)/fileBase->candidates->Count;
                                        if (fileBase->IsDuplicate(iCandidate))
                                                backgroundWorker->ReportProgress(percentsComplited,iCandidate.Key + "*" + iCandidate.Value.ToString());
                                        else
                                                backgroundWorker->ReportProgress(percentsComplited,"");
                                }
                        }

        private: System::Void backgroundWorker_ProgressChanged(System::Object^  sender, System::ComponentModel::ProgressChangedEventArgs^  e) {
                                if(e->UserState != "")
                                {
                                        array<String^>^ cellValue = e->UserState->ToString()->Split('*');
                                        resultView->Rows->Add(cellValue[0], cellValue[1]);
                                }
                                progressBar->Value = e->ProgressPercentage;
                        }

        private: System::Void backgroundWorker_RunWorkerCompleted(System::Object^  sender, System::ComponentModel::RunWorkerCompletedEventArgs^  e) {
                                buttonCancel->Enabled = false;
                                buttonStart->Enabled = true;
                        }


pozitiffcat 26.02.2013 18:37

Ответ: Доступ к GUI с иного потока
 
.NET CLR зло ИМХО, юзай шарп


Часовой пояс GMT +4, время: 04:55.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Перевод: zCarot