Пример работы с BackgroundWorker C++ и заставляем работать Refresh
Потоки – одна из самых популярных тем в программировании. На самом деле в них ничего особо сложного нет, разобравшись с реализацией на одном языке программирования высокого уровня, вы уже и в другом сможете реализовать поток. Но есть несколько но. В этой заметке мы поговорим о реализации потоков с помощью встроенного элемента Visual studio C++ - это BackgroundWorker, а также при обход проблемы прорисовки и работы с элементами GUI.
Итак, попробуем на примере конкретной задачи разобраться потоками и отрисовкой их в визуал студио C++. Предположим, что на форме у нас есть pictureBox, на котором мы что-то рисуем. И нам требуется обновлять это что-то с частотой раз в полсекунды. Оператор Sleep(500) прекрасно справится с этой задачей, но до конца процесса визуализации мы увы, ничего не сможем сделать с нашей формой. Это некритично, если не требуется ставить паузу и процесс занимает немного времени. А нам нужна именно пауза.
В одной своей работе мне потребовалось сделать реализацию алгоритма сортировки Шелла с визуализацией оной. Алгоритм легко программируется на C++, визуализацию тоже, не мудрствуя лукаво, я сделал с помощью прямоугольников, высота которых была пропорционально чисел в массиве.
Теперь надо, собственно говоря, и поработать с потоками. Кидаем на форму элемент backgroundWorker1, а когда требуется его запустить, вызываем метод:
backgroundWorker1->RunWorkerAsync();В самом потоке что-то делаем:
private: System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) { //что-то делаем, вычисляем и тд. Sleep (5000); }И никакого подвисания не будет – в данном потоке выполняется одно, а форма и элементы управления работают.
Но у нас же визуализация алгоритма – давайте попробуем встроить в наш поток метод принудительной перерисовки pictureBox:
pictureBox1->Refresh();И что мы видим? А ничего. Метод не будет отрабатывать. Не будет не выбрасывания ошибки, ничего – простой дойдет до этой строчки и перестанет работать данный поток. Почему так? В двух словах: нельзя управлять элементами формы из другого потока без некоторых ухищрений. Надо сделать так. Создадим еще один метод:
System::Void RefFre() { pictureBox1->Refresh(); }И вызовем его через Invoke:
pictureBox1->Invoke(gcnew Action(this, &Form1:: RefFre));Если надо передать какую либо переменную, то делаем так
pictureBox1->Invoke(gcnew Action<int>(this, &Form1:: RefFre), 0);Соответственно, входящие параметры функции тоже надо изменить.
Вот теперь у нас все отлично скомпилируется, а перерисовка будет происходить тогда, когда надо – в фоновом потоке и расчет тогда же. Для остановки данного потока поставьте флаг WorkerSupportsCancellation true, а в нужном месте:
if (backgroundWorker1->CancellationPending) { //прерываем, например… break; }Вызов прерывания:
backgroundWorker1->CancelAsync();Как видите, ничего особо сложного нет, но незнающий таких тонкостей человек может потратить немало времени для решения такой простой задачи. Если у вас что-то не получается, то вы можете написать мне. Не бесплатно, но недорого я помогу вам.
Кстати, напоминаю, что могу сделать для вас курсовые, лабораторные, практические и дипломные работы на C++, Java, C#, PHP. Так как я занимаюсь данной деятельностью не первый год, помогаю студентам, то у меня накопилась и продолжает копиться база решений (программ) по самым разным тематикам: от администрирования баз данных и до высшей математики. Так что заказывая программу для курсовой по программированию у меня, вы можете рассчитывать на самые низкие цены, если подобное я уже делал.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.
Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.