Форум программистов
 
О проблемах, например, с регистрацией пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail, а тут можно восстановить пароль.

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

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

Здесь нужно купить рекламу за 20 тыс руб в месяц! ) пишите сюда - alarforum@yandex.ru
Без учёта ботов - 20000 человек в день, 350000 в месяц.

Ответ
 
Опции темы
Старый 04.04.2012, 10:24   #1
Iosimo
Пользователь
 
Регистрация: 26.03.2012
Сообщений: 10
По умолчанию рисование мышью с использованием BitBlt

Доброго времени суток!
Пытаюсь изучить работу с функцией BitBlt при рисовании мышью, столкнулся с проблемой, что вместо линии стало выводить квадраты, подскажите пожалуйста в чем ошибка

Код:
#include "stdafx.h"
#include "draw_line.h"

#define MAX_LOADSTRING 100

// Глобальные переменные:
HINSTANCE hInst;								// текущий экземпляр
TCHAR szTitle[MAX_LOADSTRING];					// Текст строки заголовка
TCHAR szWindowClass[MAX_LOADSTRING];			// имя класса главного окна

// Отправить объявления функций, включенных в этот модуль кода:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);


int x, y, x2, y2;//ДОЛЖНЫ БЫТЬ
bool bDraw;		//ГЛОБАЛЬНЫМИ 
HBITMAP hDrawingBitmap;

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)

{...}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= 0;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DRAW_LINE));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_DRAW_LINE);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;
   HDC hDC, hMemDC;
   HBITMAP hOldBmp;
   HBRUSH hTmpBrush;
   RECT rcClient;

   hInst = hInstance; // Сохранить дескриптор экземпляра в глобальной переменной

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }


   hDC = GetDC(hWnd);
   GetClientRect(hWnd, &rcClient);


   hDrawingBitmap	= CreateCompatibleBitmap(
	   hDC, 
	   rcClient.right - rcClient.left, 
	   rcClient.bottom - rcClient.top);

   hMemDC = CreateCompatibleDC(hDC);

   hOldBmp = (HBITMAP)SelectObject(hMemDC, hDrawingBitmap);
   SelectObject(hMemDC, hOldBmp);
   ReleaseDC(hWnd, hMemDC);

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	hdc = GetDC(hWnd);

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Разобрать выбор в меню:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;

	case WM_LBUTTONDOWN:
	case WM_RBUTTONDOWN:
		SetCapture(hWnd);
		bDraw = true;
		x = LOWORD(lParam);
		y = HIWORD(lParam);
	

		break;
	case WM_LBUTTONUP:
	case WM_RBUTTONUP:
		if (!bDraw)
			return FALSE;
		ReleaseCapture();
		bDraw = false;
		break;

	case WM_MOUSEMOVE:
		RECT rcClient;
		HDC hDC, hMemDC;
		HBITMAP hOldBmp;
		HBRUSH hTmpBrush, hOldBrush;
		hDC = GetDC(hWnd);
		if (!bDraw)
			break;
		x2 = (signed short)LOWORD(lParam);
		y2 = (signed short)HIWORD(lParam);

		GetClientRect(hWnd, &rcClient);
		hMemDC = CreateCompatibleDC(hDC);
		hOldBmp = (HBITMAP)SelectObject(hMemDC, hDrawingBitmap);

		MoveToEx(hMemDC, x, y, NULL);
		LineTo(hMemDC, x2, y2);

		x = x2;
		y = y2;
		
		ReleaseDC(hWnd, hdc);
		SelectObject(hMemDC, hOldBmp);
		DeleteDC(hMemDC);
		ReleaseDC(hWnd, hDC);
		InvalidateRect(hWnd, NULL, FALSE);

		break;

	case WM_PAINT:
		HDC hTmpDC;
		HBITMAP hTmpBmp;
		hdc = BeginPaint(hWnd, &ps);

		GetClientRect(hWnd, &rcClient);
		hTmpDC = CreateCompatibleDC(hdc);
		hTmpBmp = (HBITMAP)SelectObject(hTmpDC, hDrawingBitmap);
		BitBlt(	hdc,0,	0,x,y,hTmpDC, 0,0,	SRCCOPY);

		SelectObject(hTmpDC, hTmpBmp);
		DeleteDC(hTmpDC);
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}
Iosimo вне форума Ответить с цитированием
Старый 04.04.2012, 16:39   #2
EUGY
Форумчанин
 
Аватар для EUGY
 
Регистрация: 11.07.2010
Сообщений: 913
По умолчанию

Вы создаете hDrawingBitmap, он выполняет роль буфера.
Рисуете по нему в WM_MOUSEMOVE, а потом выводите при WM_PAINT.

Но много ошибок, и первая, hDrawingBitmap при создании имеет черный фон, и вы рисуете по нему черные линии, а потом BitBlt в контекст окна.
Какой же будет эффект?

Тогда уж залейте его фоном в начале:
Код:
hOldBmp = (HBITMAP)SelectObject(hMemDC, hDrawingBitmap);
FillRect(hMemDC, &rcClient,(HBRUSH) GetStockObject(WHITE_BRUSH));
EUGY вне форума Ответить с цитированием
Старый 04.04.2012, 22:08   #3
Iosimo
Пользователь
 
Регистрация: 26.03.2012
Сообщений: 10
По умолчанию

Спасибо за ответ, сделал заливку как вы сказали, все стало гораздо лучше, хотя странности при рисовке остались, как я понимаю это связанно с case WM_PAINT
Iosimo вне форума Ответить с цитированием
Старый 04.04.2012, 22:43   #4
EUGY
Форумчанин
 
Аватар для EUGY
 
Регистрация: 11.07.2010
Сообщений: 913
По умолчанию

Эти странности связаны с непонятно заданной логикой рисования. И шквалом порождаемых объектов GDI и с их неосвобождением.
Откройте диспетчер задач, добавьте столбец "объекты GDI". Ужаснетесь. )
EUGY вне форума Ответить с цитированием
Старый 06.04.2012, 10:28   #5
Iosimo
Пользователь
 
Регистрация: 26.03.2012
Сообщений: 10
По умолчанию

Все получилось вроде ) подправил WM_PAINT,хотя мне лично причина ошибки не очень ясна
Код:
case WM_PAINT:
		HDC hTmpDC;
		HBITMAP hTmpBmp;

		hdc = BeginPaint(hWnd, &ps);

		GetClientRect(hWnd, &rcClient);
		hTmpDC = CreateCompatibleDC(hdc);
		hTmpBmp = (HBITMAP)SelectObject(hTmpDC, hDrawingBitmap);
		BitBlt(hdc,0,0,rcClient.right ,rcClient.bottom,hTmpDC, 0,0,	SRCCOPY);

		SelectObject(hTmpDC, hTmpBmp);
		DeleteDC(hTmpDC);
		EndPaint(hWnd, &ps);
		break;
т.е. ошибка была тут
BitBlt(hdc,0,0,rcClient.right ,rcClient.bottom,hTmpDC, 0,0, SRCCOPY);
не очень ясно по чему я не мог использовать
x = LOWORD(lParam);
y = HIWORD(lParam);
Iosimo вне форума Ответить с цитированием
Старый 06.04.2012, 13:33   #6
EUGY
Форумчанин
 
Аватар для EUGY
 
Регистрация: 11.07.2010
Сообщений: 913
По умолчанию

Дело хозяйское, но Вы выводите всю клиентскую область, когда надо и когда не надо.
Структуру PAINTSTRUCT раскройте, в ней будет RECT который действительно нуждается в перерисовке, его координаты и надо задействовать, а не брать полные габариты клиента.
EUGY вне форума Ответить с цитированием
Старый 06.04.2012, 15:06   #7
Iosimo
Пользователь
 
Регистрация: 26.03.2012
Сообщений: 10
По умолчанию

Вы не можете подсказать книгу, в которой хорошо описана работа с этой функцией ?
Iosimo вне форума Ответить с цитированием
Старый 06.04.2012, 15:35   #8
EUGY
Форумчанин
 
Аватар для EUGY
 
Регистрация: 11.07.2010
Сообщений: 913
По умолчанию

Кроме банального ответа - MSDN - ничего в голову не приходит.
Если задача: не сдать и забыть, а понять, то только собственный опыт.
EUGY вне форума Ответить с цитированием
Старый 06.04.2012, 15:46   #9
Iosimo
Пользователь
 
Регистрация: 26.03.2012
Сообщений: 10
По умолчанию

тут именно понять, по этому и взялся за простой пример, который как оказался таит в себе множество подводных камней, переход с Билдера на win api сложная штука как оказалось )
Сравнил по загруженности диспетчера задач оба варианта
Код:
BitBlt(hdc,0,0,ps.rcPaint.right ,ps.rcPaint.bottom,hTmpDC, 0,0,	SRCCOPY);
BitBlt(hdc,0,0,rcClient.right ,rcClient.bottom,hTmpDC, 0,0,	SRCCOPY);
на первый взгляд разница не существенна, вариант с rcClient занимает немного меньше памяти, но я сравнивал пустые окна, те без рисунка в них

Последний раз редактировалось Iosimo; 06.04.2012 в 16:14.
Iosimo вне форума Ответить с цитированием
Старый 06.04.2012, 16:57   #10
EUGY
Форумчанин
 
Аватар для EUGY
 
Регистрация: 11.07.2010
Сообщений: 913
По умолчанию

Значица так.
Код:
void NormalizeRect(RECT* prect)
{
	int tmp;
	if ( prect->left > prect->right)
	{
		tmp = prect->right;
		prect->right = prect->left;
		prect->left = tmp;
	}
	if ( prect->top > prect->bottom)
	{
		tmp = prect->bottom;
		prect->bottom = prect->top;
		prect->top = tmp;
	}
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HDC hmemDC = CreateCompatibleDC(NULL);
	static HBITMAP hprv = NULL;
	static POINT starter;
	switch (uMsg)
	{
	case WM_CREATE:
		{
			HDC descDC = GetDC(NULL);
			HBITMAP hmemBMP = CreateCompatibleBitmap(descDC, GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN));
			ReleaseDC(NULL, descDC);
			hprv = (HBITMAP) SelectObject(hmemDC, hmemBMP);
			RECT rc = {0,0, GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN)};
			FillRect(hmemDC, &rc, (HBRUSH) GetStockObject(WHITE_BRUSH));
		}
		break;
	case WM_DESTROY:
		{
			DeleteObject(SelectObject(hmemDC, hprv));
			DeleteDC(hmemDC);
			PostQuitMessage(0);
		}
		 break;
	case WM_ERASEBKGND: 
		return 0;
	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			BeginPaint(hWnd, &ps);
			BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top,  ps.rcPaint.right - ps.rcPaint.left,  ps.rcPaint.bottom - ps.rcPaint.top,
 hmemDC, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
			EndPaint(hWnd, &ps);
		}
		break;
	case WM_LBUTTONDOWN:
		SetCapture(hWnd);
		MoveToEx(hmemDC, LOWORD(lParam), HIWORD(lParam), &starter);
		break;
	case WM_LBUTTONUP:
		ReleaseCapture();
		break;
	case WM_MOUSEMOVE:
		if (hWnd == GetCapture())
		{
			LineTo(hmemDC, LOWORD(lParam), HIWORD(lParam));
			RECT rc  = {starter.x, starter.y,  LOWORD(lParam), HIWORD(lParam)};
			NormalizeRect(&rc);
			rc.bottom++;
			rc.right++;
			starter.x = LOWORD(lParam); 
			starter.y = HIWORD(lParam);
			InvalidateRect(hWnd, &rc, TRUE);
		}
		break;
	case WM_CLOSE:
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

Это конечно еще довести до ума, но принцип должен быть понятен

Последний раз редактировалось EUGY; 06.04.2012 в 17:00.
EUGY вне форума Ответить с цитированием
Ответ

Здесь нужно купить рекламу за 20 тыс руб в месяц! ) пишите сюда - alarforum@yandex.ru
Без учёта ботов - 20000 человек в день, 350000 в месяц.

Опции темы


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
BitBlt прозрачное рисование Alex Cones Общие вопросы Delphi 2 29.06.2010 19:38
BitBlt, вывод изображения zotox Win Api 5 22.04.2010 21:43
BitBlt из памяти на экран Марин Win Api 6 25.01.2010 01:50
BitBlt ZotaC Gamedev - cоздание игр: Unity, OpenGL, DirectX 14 16.01.2010 20:04
BitBlt на контекст DC и его альтернатива notHaker Мультимедиа в Delphi 7 03.12.2009 02:04


Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru
Пеллетный котёл Emtas
котлы EMTAS