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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 14.12.2010, 12:34   #1
Tesmont
Пользователь
 
Регистрация: 12.05.2009
Сообщений: 28
По умолчанию Рисование отдельным потоком в классе. MFC. GDI+

Если я в цикле вызываю метод класса Car.ShowCar, передавая ему всё время новые координаты для рисования, то все работает. Но если я сделаю цикл на рисование в самом методе, то он уже ничего рисовать не хочет. Во время отладки увидел,
arg->g 0x003af0b0 {nativeGraphics=0x02b82f10 lastResult=ObjectBusy } Gdiplus::Graphics *
arg->g 0x003af0b0 {nativeGraphics=0x00000000 lastResult=InvalidParameter } Gdiplus::Graphics *
CCar
Код:
class CCar
{
public:
	CCar(void);
	~CCar(void);
	struct qwerty
	{
		int x, y;
		Graphics *g;
	}*arg;
	void ShowCar(Graphics *g, int x, int y);
	bool TypeOfMove, EndOfMove;
private:
	static unsigned __stdcall NewCar(void *arg);
};

CCar::CCar(void)
{
	arg = new qwerty();
}


CCar::~CCar(void)
{
}


void CCar::ShowCar(Graphics *g, int x, int y)
{
	unsigned int threadID;
	arg->g = g;
	arg->x = x;
	arg->y = y;
	_beginthreadex(NULL, 0, &NewCar, arg, 0, &threadID);
}


unsigned __stdcall CCar::NewCar(void *Parg)
{
	qwerty *arg = (qwerty *)Parg;
	Pen p(Color(255, 255, 0, 0));
	Pen p2(Color(255, 255, 255, 255));
	Point MyPoint[3];
	Point MyPoint2[3];
	while (arg->x <= 150)
	{
		MyPoint[0].X = arg->x;
		MyPoint[0].Y = arg->y;
		MyPoint[1].X = arg->x-5;
		MyPoint[1].Y = arg->y+5;
		MyPoint[2].X = arg->x-5;
		MyPoint[2].Y = arg->y-5;
		MyPoint2[0].X = arg->x-2;
		MyPoint2[0].Y = arg->y;
		MyPoint2[1].X = arg->x-7;
		MyPoint2[1].Y = arg->y+5;
		MyPoint2[2].X = arg->x-7;
		MyPoint2[2].Y = arg->y-5;
		arg->g->DrawPolygon(&p2, MyPoint2, 3);
		arg->g->DrawPolygon(&p, MyPoint, 3);
		arg->x++;
		arg->x++;
		SleepEx(30, FALSE);
	}
	return 0;
}
CThreadsCarDlg
Код:
void CThreadsCarDlg::OnBnClickedOk()
{
	CClientDC dc(this);
	dc.SetBkMode(TRANSPARENT);
	Graphics g(dc);
	CRect rect;
	GetWindowRect(&rect);
	int x, y;
	x = 50;
	y = 500/2 + 20;
	//while(x <= 500)
	//{
		cars->ShowCar(&g, x, y);
		x=x+2;
		SleepEx(30, FALSE);
	//}
}
Tesmont вне форума Ответить с цитированием
Старый 14.12.2010, 17:31   #2
Tesmont
Пользователь
 
Регистрация: 12.05.2009
Сообщений: 28
По умолчанию

Неужели ни кто, не может сказать в чём дело?
Tesmont вне форума Ответить с цитированием
Старый 14.12.2010, 19:30   #3
V0id
Пользователь
 
Регистрация: 12.12.2010
Сообщений: 30
По умолчанию

Код:
qwerty *arg = (qwerty *)Parg;
Попробуй закомментировать эту строчку?)
V0id вне форума Ответить с цитированием
Старый 14.12.2010, 19:41   #4
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Если я не ошибаюсь (а это возможно, т.к. я не уверен), то проблема может быть именно в этом:
Код:
arg->g->DrawPolygon(&p2, MyPoint2, 3);
		arg->g->DrawPolygon(&p, MyPoint, 3);
А именно:
1. arg - указатель на память, в принципе все нормально
2. g - это указатель на графический контекст GDI+ связанный с HDC, а вот HDC то это уже GUI, а рисовать GUI в отдельном потоке, жди беду.

Решением данной проблемы может быть два пути:
1. Рисовать все в главном потоке, отказаться от дочернего потока (реализация через таймеры и др.)
2. Готовить Bitmap (объект GDI+ или тот же HBITMAP (объект GDI)) в главном потоке, после чего передавать указатель на него в дочерний поток, где создается графический контекст GDI+ связанный с данным Bitmap'ом, и соответственно производится отрисовка на данном Bitmap'e. После чего вызывать синхронизацию из дочернего потока в главный (тут надо разобраться), т.е. по сути передача управления главному потоку (методу/функции), который будет выводить (уже готовый и известный) Bitmap на созданный раннее и связанный с HDC окна, графический контекст GDI+.

UPD:
Цитата:
Либо сделать задержку побольше, чтобы потоки успевали завершаться (но это корявый способ =) ).
Зло! Ни в коем случае так не делать.

Последний раз редактировалось BOBAH13; 14.12.2010 в 20:24.
BOBAH13 вне форума Ответить с цитированием
Старый 14.12.2010, 20:08   #5
V0id
Пользователь
 
Регистрация: 12.12.2010
Сообщений: 30
По умолчанию

Точно. Создается до фига потоков, обращающися к одному НЕразделяемому(видимо) ресурсу.
Без синхронизации не обойтись... Либо сделать задержку побольше, чтобы потоки успевали завершаться (но это корявый способ =) ).

2BOBAH13:
Ну конечно, так делать не следует, но для того, чтобы понять, из-за чего ошибка, все-таки можно временно себе позволить))

Последний раз редактировалось V0id; 14.12.2010 в 21:14. Причина: update
V0id вне форума Ответить с цитированием
Старый 14.12.2010, 21:43   #6
Tesmont
Пользователь
 
Регистрация: 12.05.2009
Сообщений: 28
По умолчанию

Эмм народ, вы не так поняли, когда создается куча потоков всё работает отлично, а если всё сделать в 1 потоке, где синхронизировать-то нечего, то уже хрен.
Те если комменты в коде расставлены, как в коде выше, где создается 1 вторичный поток(или как его ещё обозавать) и ничего нихрена не рисуется. А вот если ставить их так:
CCar
Код:
class CCar
{
public:
	CCar(void);
	~CCar(void);
	struct qwerty
	{
		int x, y;
		Graphics *g;
	}*arg;
	void ShowCar(Graphics *g, int x, int y);
	bool TypeOfMove, EndOfMove;
private:
	static unsigned __stdcall NewCar(void *arg);
};

CCar::CCar(void)
{
	arg = new qwerty();
}


CCar::~CCar(void)
{
}


void CCar::ShowCar(Graphics *g, int x, int y)
{
	unsigned int threadID;
	arg->g = g;
	arg->x = x;
	arg->y = y;
	_beginthreadex(NULL, 0, &NewCar, arg, 0, &threadID);
}


unsigned __stdcall CCar::NewCar(void *Parg)
{
	qwerty *arg = (qwerty *)Parg;
	Pen p(Color(255, 255, 0, 0));
	Pen p2(Color(255, 255, 255, 255));
	Point MyPoint[3];
	Point MyPoint2[3];
	//while (arg->x <= 150)
	//{
		MyPoint[0].X = arg->x;
		MyPoint[0].Y = arg->y;
		MyPoint[1].X = arg->x-5;
		MyPoint[1].Y = arg->y+5;
		MyPoint[2].X = arg->x-5;
		MyPoint[2].Y = arg->y-5;
		MyPoint2[0].X = arg->x-2;
		MyPoint2[0].Y = arg->y;
		MyPoint2[1].X = arg->x-7;
		MyPoint2[1].Y = arg->y+5;
		MyPoint2[2].X = arg->x-7;
		MyPoint2[2].Y = arg->y-5;
		arg->g->DrawPolygon(&p2, MyPoint2, 3);
		arg->g->DrawPolygon(&p, MyPoint, 3);
		//arg->x++;
		//arg->x++;
		//SleepEx(30, FALSE);
	//}
	return 0;
}
CThreadsCarDlg
Код:
void CThreadsCarDlg::OnBnClickedOk()
{
	CClientDC dc(this);
	dc.SetBkMode(TRANSPARENT);
	Graphics g(dc);
	CRect rect;
	GetWindowRect(&rect);
	int x, y;
	x = 50;
	y = 500/2 + 20;
	while(x <= 500)
	{
		cars->ShowCar(&g, x, y);
		x=x+2;
		SleepEx(30, FALSE);
	}
}
то создается уже много потоков и это почему-то пашет.
Tesmont вне форума Ответить с цитированием
Старый 14.12.2010, 21:54   #7
Tesmont
Пользователь
 
Регистрация: 12.05.2009
Сообщений: 28
По умолчанию

Щас врубил эту прогу, где создается 1 вторичный поток и будучи растроенным, что эта хрень не пашет, начал очень бысто кликать кнопку запуска этого потока, в надежде, что она запахает и в результате, парочку раз у меня этот чертов треугольник отрисовался. Ну не пиздец-ли (
Tesmont вне форума Ответить с цитированием
Старый 14.12.2010, 21:55   #8
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Логика с первого взгляда запутана, трудно понять код. Еще раз глянул вверх
Цитата:
arg->g 0x003af0b0 {nativeGraphics=0x00000000 lastResult=InvalidParameter } Gdiplus::Graphics *
По моему это очень плохо, видимо объект удален, ваш графический контекст GDI+, и обнулен, после чего вы пытаетесь к нему обратиться.

Исходя из этого, где то нарушена логика программы. А именно очередность создания и удаления графического контекста. Видимо при выполнении в нескольких потоках, происходит торможение главного (фиксация графического контекста), и этого времени хватает на выполнение графических действий. Эта же ситуация может вам выдавать и это
Код:
arg->g	0x003af0b0 {nativeGraphics=0x02b82f10 lastResult=ObjectBusy }	Gdiplus::Graphics *
Теперь еще раз глянул, у вас g в void CThreadsCarDlg::OnBnClickedOk(), локальная переменная, и нигде нет гарантий что все потоки завершаться (cars->ShowCar(&g, x, y) до того как закончится цикл while(x <= 500).

Простое решение, это удостоверится что все потоки завершены, после чего разрешить закончить функцию void CThreadsCarDlg::OnBnClickedOk().

Более сложное решение, это пересмотреть логику приложения.

UPD:
Tesmont советую выражаться по нормальному.
BOBAH13 вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Рисование отдельным поток в классе. MFC. GDI+ Tesmont Помощь студентам 0 14.12.2010 11:17
GDI+ рисование картинки с прозрачным бэкграундом sashonk Общие вопросы C/C++ 1 15.11.2010 22:40
массив отдельным файлом Izlom Помощь студентам 2 31.05.2010 17:25
Работа с отдельным клиентом Rapala Работа с сетью в Delphi 10 31.03.2010 17:29
закачка файла отдельным потоком. ZeitGeist7 Общие вопросы Delphi 12 26.02.2009 20:23