|
22.02.2013, 00:57
|
#1
|
ПроЭктировщик
Регистрация: 20.06.2009
Адрес: Україна
Сообщений: 152
Написано 10 полезных сообщений (для 24 пользователей)
|
Доступ к GUI с иного потока
Добрый вечер вам!
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;
}
Но сразу же после старта потока вылетает екзепшн:
Пожалуйста подскажите, как это лучше исправить! Можно ли обойтись без множества блоков try-catch?
Заранее спасибо!
__________________
Blitz3D, XNA, WebGL, OpenGL, Unity3D
PC: ASUS A55VM Core i3 (2.4Ghz), 6 Gb RAM, Nvidia GF 630M GT 2Gb
|
(Offline)
|
|
22.02.2013, 13:20
|
#2
|
Бывалый
Регистрация: 19.06.2008
Сообщений: 679
Написано 264 полезных сообщений (для 450 пользователей)
|
Ответ: Доступ к GUI с иного потока
Invoke();
__________________
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
22.02.2013, 19:51
|
#3
|
ПроЭктировщик
Регистрация: 20.06.2009
Адрес: Україна
Сообщений: 152
Написано 10 полезных сообщений (для 24 пользователей)
|
Ответ: Доступ к 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;
__________________
Blitz3D, XNA, WebGL, OpenGL, Unity3D
PC: ASUS A55VM Core i3 (2.4Ghz), 6 Gb RAM, Nvidia GF 630M GT 2Gb
|
(Offline)
|
|
22.02.2013, 23:12
|
#4
|
Бывалый
Регистрация: 19.06.2008
Сообщений: 679
Написано 264 полезных сообщений (для 450 пользователей)
|
Ответ: Доступ к 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);
и не парюсь о потоках.
__________________
|
(Offline)
|
|
24.02.2013, 00:07
|
#5
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Ответ: Доступ к GUI с иного потока
[критикан]
Всё какие-то свиристелки. Почему б не использовать WinAPI? Или тут что-то про кросплатформенность - тогда Boost?[/критикан]
В своё время, когда решал подобную задачу (два потока - один постоянно крутит цикл с рассчётами, второй - ГУИ: обрабатывает кнопочки и с некоторой невысокой частотой обновляет данные о работе первого потока) опирался на статью "Организация межпотокового взаимодействия с использованием объектов ядра операционной системы" (в журнале "Вестник компьютерных и информационных технологий")
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
24.02.2013, 18:20
|
#6
|
Бывалый
Регистрация: 19.06.2008
Сообщений: 679
Написано 264 полезных сообщений (для 450 пользователей)
|
Ответ: Доступ к GUI с иного потока
Сообщение от impersonalis
[критикан]
Всё какие-то свиристелки. Почему б не использовать WinAPI? Или тут что-то про кросплатформенность - тогда Boost?[/критикан]
В своё время, когда решал подобную задачу (два потока - один постоянно крутит цикл с рассчётами, второй - ГУИ: обрабатывает кнопочки и с некоторой невысокой частотой обновляет данные о работе первого потока) опирался на статью "Организация межпотокового взаимодействия с использованием объектов ядра операционной системы" (в журнале "Вестник компьютерных и информационных технологий")
|
CLR приложение (.Net средствами С++).
|
..
__________________
|
(Offline)
|
|
26.02.2013, 18:20
|
#7
|
ПроЭктировщик
Регистрация: 20.06.2009
Адрес: Україна
Сообщений: 152
Написано 10 полезных сообщений (для 24 пользователей)
|
Ответ: Доступ к 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;
}
__________________
Blitz3D, XNA, WebGL, OpenGL, Unity3D
PC: ASUS A55VM Core i3 (2.4Ghz), 6 Gb RAM, Nvidia GF 630M GT 2Gb
|
(Offline)
|
|
26.02.2013, 18:37
|
#8
|
Мастер
Регистрация: 09.05.2010
Адрес: Самара
Сообщений: 1,083
Написано 254 полезных сообщений (для 533 пользователей)
|
Ответ: Доступ к GUI с иного потока
.NET CLR зло ИМХО, юзай шарп
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо pozitiffcat за это полезное сообщение:
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 06:30.
|