Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > C++ Builder
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 23.01.2011, 11:20   #1
Koshmarovsky
Пользователь
 
Аватар для Koshmarovsky
 
Регистрация: 09.05.2009
Сообщений: 25
По умолчанию Проблемы с рисованием в Canvas из отдельного потока

Значится так...
Работаю в BDS 2006, C++ Builder.
Рисую на канвасе картинку, которая динамически создается при работе программы. Что бы прорисовка работала не зависимо от моих действий над формой, рисую в отдельном потоке. Если ничего не трогать, все работает отлично, но если, скажем, начать шевелить мышкой, то через некоторое рандомное время картинка перестает перерисовываться. Поток продолжает работать, все счетчики пересчитываются, никаких екзепшенов не посылается, просто не перерисовывается канвас.
Провел кучу экспериментов, что бы хоть как-то вычислить событие, после которого возникает косяк (ну, там, при наведении курсора на канвас или нажатие кнопки), никаких причинно-следственных связей не обнаружил.

Немного кода:
Консруктор класса Demonstration
Код:
Demonstration::Demonstration ()
{
Thread = CreateThread (NULL, 0,	&Demonstration::ThreadLoop, (unsigned long*)this, NULL, &idThread);
}
Собсна функция потока.
Код:
DWORD WINAPI Demonstration::ThreadLoop(LPVOID thisDemo)
{
Demonstration* Demo =((Demonstration*)thisDemo);
while(1)
	{
	Demo->Picture->NextStep();
	some_counter++;
	Sleep(100);
	}
}
Функция NextStep() вызывает функцию прорисовки.
Код:
void Frap::NextStep()
{
//различные махинации с данными
this->Draw();
}
Функция Draw() (ни за что не поверите) рисует в Canvas:
Код:
void Frap::Draw()
{
//Ну например
for (int i=0; i<PH; i++)
	{
	int* line = (int*)pBitmap->ScanLine[i];
	for (int j=0; j<PW; j++)
		line[j] = RGB(rand()%255, rand()%255, rand()%255);
	}

draw_box->Lock();
draw_box->Draw(0, 0, pBitmap);
draw_box->Unlock();
}
Хелп ми плиз!
Иногда мне кажется, что компилятор просто игнорирует все мои комментарии. (с) Bash.org.ru

Последний раз редактировалось Koshmarovsky; 23.01.2011 в 11:23.
Koshmarovsky вне форума Ответить с цитированием
Старый 23.01.2011, 11:44   #2
Koshmarovsky
Пользователь
 
Аватар для Koshmarovsky
 
Регистрация: 09.05.2009
Сообщений: 25
По умолчанию

Опытным путем было выяснено, что косяк возникает при каких-либо действиях с формой, например при движении курсора над ней. Однако от случая к случаю можно с полминуты жимкать на все кнопки и сворачивать-разворачивать окно, и все будет ок, а бывает, что при сдвиге курсора на пиксел картинка замирает (даже если окно не активно). Если курсор в область формы не попадает, все работает.
Иногда мне кажется, что компилятор просто игнорирует все мои комментарии. (с) Bash.org.ru

Последний раз редактировалось Koshmarovsky; 23.01.2011 в 11:47.
Koshmarovsky вне форума Ответить с цитированием
Старый 23.01.2011, 12:32   #3
Koshmarovsky
Пользователь
 
Аватар для Koshmarovsky
 
Регистрация: 09.05.2009
Сообщений: 25
По умолчанию

Дописал прогу малость. Если поток перезапустить (старый снести, новый начать), все снова работает нормально. До поры до времени...
Иногда мне кажется, что компилятор просто игнорирует все мои комментарии. (с) Bash.org.ru
Koshmarovsky вне форума Ответить с цитированием
Старый 23.01.2011, 12:50   #4
Koshmarovsky
Пользователь
 
Аватар для Koshmarovsky
 
Регистрация: 09.05.2009
Сообщений: 25
По умолчанию

Ан нет! Поток пересоздавать необязательно, можно просто битмап новый сделать в классе Frap... Вот такую функцию написал и на кнопку назначил:
Код:
void Frap::Refresh()
{
pBitmap = new Graphics::TBitmap();
pBitmap->PixelFormat = pf32bit;
pBitmap->Height = PH;
pBitmap->Width = PW;
}
Но это костыль получается. Что за дела?
Иногда мне кажется, что компилятор просто игнорирует все мои комментарии. (с) Bash.org.ru
Koshmarovsky вне форума Ответить с цитированием
Старый 23.01.2011, 13:03   #5
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

а другой поток вообще не должен рисовать
максимум обновлять переменные по которым главный поток сможет перерисовать все как надо, ну и дать главному потоку знать что пора перерисоватся.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 23.01.2011, 13:11   #6
Koshmarovsky
Пользователь
 
Аватар для Koshmarovsky
 
Регистрация: 09.05.2009
Сообщений: 25
По умолчанию

Усмысле?
Не должен - в смысле не будет работать, или в смысле не стоит так делать?
Рисовать-то он рисует. Временно сделал так: создаю новый pBitmap каждый раз в функции Draw(), использую, и удаляю. Все работает, на быстродействии никак не сказалось. Но это опять таки костыль, хотя получше, чем предыдущий.
Проблем в том, что pBitmap перестает правильно фунциклировать... Хотя указатель на него никуда не девается (ставил BreakPoint, проверял). В чем может быть причина?
Иногда мне кажется, что компилятор просто игнорирует все мои комментарии. (с) Bash.org.ru
Koshmarovsky вне форума Ответить с цитированием
Старый 23.01.2011, 18:21   #7
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Frap::Draw() следует вызывать через Synchronize().
Т.к. у вас свой поток, а не потомок от TThread, то вместо Synchronize() синхронизируйте 2 потока через 2 события, например. Смысл в том, что вся работа с VCL должна выполняться только из главного потока, иначе будут лезть глюки, описанные в вашем первом сообщении.

Кстати, интересно как у вас Demonstration::ThreadLoop() будет работать, ведь при выходе из неё стек очистится на 4 лишних байта.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 23.01.2011, 18:49   #8
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Цитата:
Кстати, интересно как у вас Demonstration::ThreadLoop() будет работать, ведь при выходе из неё стек очистится на 4 лишних байта.
static как я понимаю
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 23.01.2011, 19:07   #9
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Блин, логично )

Ну или надежда на while(1) и TerminateThread()..
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Проблемы с рисованием на TStringGrid megachuhancer Общие вопросы Delphi 10 09.02.2011 04:36
Многопоточность. Ведение логов из каждого потока. Проблемы Человек_Борща Общие вопросы Delphi 3 07.01.2011 18:22
Как узнать номер потока из самого потока? GaMeSTeR Помощь студентам 0 03.12.2010 09:50
Thread. проблемы с работой потока. Моментально исчезают созданные в потоке формы. Casper-SC Общие вопросы .NET 3 24.04.2010 12:28
Проблема с рисованием на canvas`e Timage (Delphi) Dalagardi Помощь студентам 9 25.03.2010 20:55