Προς το περιεχόμενο

Απορια με GDI win32


Evgenios1

Προτεινόμενες αναρτήσεις

Δημοσ.

Βασικα δεν μπορω να καταλαβω ακομα πως ακριβος δουλευει αυτη η μηχανη. Διαβασα σχετικα με αυτη και εκανα μια προσπαθεια να ζωγραφισω μια γραμμη και πετυχε. Τωρα ομως θελω να φτιαξω ενα paint app, απλα πραματα, να ζωγραφιζω με το ποντικι. Ο κωδικας ειναι 5 γραμμες, αλλα για καποιο λογο δεν ζωγραφιζει οταν το βαλω στο win mess mousemove. Παραθετω το κωδικα μπας και μου εξηγησει κανεις για ποιο λογο δεν κανει αυτο που θελω στο Mouse event.

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

switch (message)
{
case WM_COMMAND:
	wmId    = LOWORD(wParam);
	wmEvent = HIWORD(wParam);
	// Parse the menu selections:
	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_PAINT:
	{
	hdc = BeginPaint(hWnd, &ps);
	
	EndPaint(hWnd, &ps);
}
	break;
case WM_DESTROY:
	PostQuitMessage(0);
	break;
[color="Blue"]	case WM_MOUSEMOVE:
	{
		if(wParam == MK_LBUTTON)
		{
			hdc = BeginPaint(hWnd, &ps);
			HPEN hPen = CreatePen(0,5,RGB(22,111,22));
			hPen = (HPEN)SelectObject(hdc,hPen);
			MoveToEx(hdc,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y,0);
			LineTo(hdc,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			EndPaint(hWnd, &ps);
		}
	}
	break;[/color]
default:
	return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

Δημοσ.

Μια παρατηρήση μιας και δεν ξέρω από C. Να μάθω και κάτι...

Όταν ζωγραφίζεις μια γραμμή, δεν θα πρέπει αφετερία και τέλος να διαφέρουν τουλάχιστον κατά ένα; πχ moveto(...x,y) lineto(...x+1,y)

Δημοσ.
...

>HPEN hPen = CreatePen(0,5,RGB(22,111,22));
[color="Red"]/*hPen = (HPEN)*/[/color]SelectObject(hdc,hPen);

 

το hpen είναι handle, μην το ξανααποθηκευεις...δεν χρειάζεται

Ελεγξε και τις τιμές που πέρνεις ακόμα και αν είσαι σίγουρος για το οτι θα παρεις σωστο αποτέλεσμα

π.χ.

>
#include <assert.h>
...
HPEN hPen = CreatePen(0,5,RGB(22,111,22));
assert(hPen!=NULL);
...

τις παραμέτρους του raw win32 gdi δεν τις θυμάμε απ'εξω, καθότι έχω objects να κάνουν αυτή τη δουλεια για μένα εδω και αρκετό καιρό, αν δεν βγάλεις άκρη, πες να ψάξω τι είχα γραψει στα class αυτά.

Δημοσ.

Ωπ, καμπανάκια χτυπάνε ;)

Εδωσες την απάντηση μόνος σου.

 

An application should not call BeginPaint except in response to a WM_PAINT message. Each call to BeginPaint must have a corresponding call to the EndPaint function.

απο εδώ.

Αν δεν κάνω λάθος θέλει CreateDC για ζωγραφισμα έξω απο WM_PAINT, θα το δω και θα σου πω.

Φυσικά παίζει και με invalidateRect (θα σου έρθει μετά στο WM_PAINT).

 

---------- Προσθήκη στις 23:09 ---------- Προηγούμενο μήνυμα στις 23:03 ----------

 

Ένα κομάτι απο κώδικα που χρησιμοποιώ για ζωγράφισμα εκτός wm_paint.

 

 

 

>
int mdisplay::__GetDC(){
register HDC hdc = GetDC((HWND)owner()->getHwnd());
massert(((HDC)(mword)hdc) == hdc);//check for data loss
set_hdc((mword)hdc);
return hdc ? TRUE : FALSE;
}

void mdisplay::__ReleaseDC(){
if(hdc()){
	int bReleased = ReleaseDC((HWND)owner()->getHwnd(),(HDC)hdc());
#ifdef _DEBUG
	//if(_u_winapi_getFlag("ReleaseDCLog",FALSE)){
	//	writeDebug(
	//		"ReleaseDC(owner=%x, hdc=%x, returned %s)\n",
	//			(mword)owner()->getHwnd(),
	//			(mword)hdc(),
	//			bReleased ? "RELEASES" : "NOT RELEASED"
	//	);
	//}
#endif
	set_hdc(NULL);
}
}

Αυτές είναι οι low level συναρτησεις του class που χρησιμοποιώ σε windows.

Θα βγάλεις άκρη πιστευώ, εχω κρατήσει και τα "ονόματα" των windows (hdc,hwnd...) στα εσωτερικά members

 

 

Δημοσ.

Ωραια αφου θελει να ειναι στο WM_PAINT τοτε γτ δεν δουλευει αυτο?

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

switch (message)
{
case WM_COMMAND:
	wmId    = LOWORD(wParam);
	wmEvent = HIWORD(wParam);
	// Parse the menu selections:
	switch (wmId)
	{
	case IDM_ABOUT:
		DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
		break;
	case IDM_EXIT:
		DestroyWindow(hWnd);
		break;
	case ID_FILE_TEST:
		{


		}
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	break;
case WM_PAINT:
	{
	[color="blue"]		hdc = BeginPaint(hWnd, &ps);
			assert(hdc!=NULL);
			HPEN hPen = CreatePen(PS_SOLID,50,RGB(22,111,22));
		    SelectObject(hdc,hPen);
			assert(hPen != NULL);
			if(lParam!=NULL){
				MoveToEx(hdc,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y,NULL);
				LineTo(hdc,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			}
			EndPaint(hWnd, &ps);[/color]
	}
	break;
case WM_DESTROY:
	PostQuitMessage(0);
	break;
case WM_MOUSEMOVE:
	{
		if(wParam == MK_LBUTTON)
		{
			[color="Blue"]SendMessage(hWnd,WM_PAINT,0,lParam);[/color]
		}
	}
	break;
default:
	return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

Δημοσ.

Δεν μπορείς να στείλεις SendMessage με WM_PAINT.

Το WM_PAINT κάνει και clipping στο invalid rect αρα δεν έχεις InvalidRect αρα δεν μπορείς να ζωγραφίσεις.

 

Μονο το InvalidateRect θα ετοιμάσει σωστα το WM_PAINT.

 

Ο κώδικας με CreateDC/ReleaseDC δεν σου κάνει;

Τρεχει οπουδήποτε, όχι μονο σε WM_PAINT.

Δημοσ.

Με πρόλαβε ο bxenos :-)

 

--

Μίας και έχω καιρό να ασχοληθώ με καθαρό WinAPI (ελέω .NET/VCL/Qt) αποφάσισα να γραψω το πρόγραμμα έτσι ώστε να σχεδιάζει πάνω σε ένα Bitmap (Backbuffer) το οποίο θα κάνει BitBlt στην επιφάνεια (DC) του παραθύρου ώστε τα περιεχόμενα να διατηρούνται συνεχώς. Το δεξί πλήκτρο του Mouse καθαρίζει ολόκληρο το παράθυρο. Το πρόγραμμα σχεδιάζει αμέσως με το πάτημα του αριστερού πλήκτρου του Mouse στο παράθυρο ένα Line ώστε να μην είναι απαραίτητη η μετακίνηση του mouse (βλ. WM_LBUTTONDOWN).

 

Το πρόγραμμα έχει δοκιμασθεί επιτυχώς σε C++ Builder 2009, φυσικά μπορεί να υπάρχουν σφάλματα ή άλλες αβλεψίες.

 

>
/*
* Simple Draw using Bitmap by directx.
*/

#include <windows.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif

#define	MYCLASS	"MYCLASS"

//---------------------------------------------------------------------------
LRESULT CALLBACK WProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

#ifdef __BORLANDC__
#pragma argsused
#endif
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
/* Setup window class. */
WNDCLASS WC;

ZeroMemory(&WC, sizeof(WC));
WC.lpfnWndProc = (WNDPROC)WProc;
WC.style = CS_HREDRAW | CS_VREDRAW;
WC.hInstance = hInstance;
WC.hCursor = LoadCursor(NULL, IDC_ARROW);
WC.hbrBackground = GetStockObject(WHITE_BRUSH);
WC.lpszClassName = MYCLASS;

if(!RegisterClass(&WC))
{
	MessageBox(NULL, "RegisterClass failed!", NULL, MB_ICONSTOP);
	return	1;
}

/* Setup window. */
HWND hWnd = CreateWindow(MYCLASS, "Draw",
						 WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,
						 CW_USEDEFAULT, CW_USEDEFAULT,
						 640, 480,
						 NULL, NULL,
						 hInstance,
						 NULL);
if(hWnd == NULL)
	MessageBox(NULL, "CreateWindow error!", NULL, MB_ICONSTOP);
else
{
	MSG myMsg;

	/* Kickstart window. */
	ShowWindow(hWnd, SW_NORMAL);
	UpdateWindow(hWnd);

	/* Setup window message-loop (not the MS way!). */
	while(GetMessage(&myMsg, NULL, 0, 0))
	{
		TranslateMessage(&myMsg);
		DispatchMessage(&myMsg);
	}
}

/* End of program. */
return 0;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK WProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
static POINT Pos;
static HDC hSurfaceDC = NULL;
static HPEN hPen = NULL, hPenBak = NULL;
static HBITMAP hSurface = NULL;
static RECT rcClient;
PAINTSTRUCT PS;
POINT POS;
HDC hDC;

switch(Msg)
{
	case WM_CREATE:
           /* Grab window bitmap. */
		if((hDC = GetDC(hWnd)) == NULL)
		{
			MessageBox(hWnd, "GetDC failed!", NULL, MB_ICONSTOP);
			PostQuitMessage(0);
			return	0;
           }
		/* Setup Bitmap DC. */
		if((hSurfaceDC = CreateCompatibleDC(hDC)) == NULL)
		{
			MessageBox(hWnd, "CreateCompatibleDC failed!", NULL, MB_ICONSTOP);
			PostQuitMessage(0);
			return	0;
		}
		/* Setup Bitmap it self. */
		if((hSurface = CreateCompatibleBitmap(hDC, 640, 480)) == NULL)
		{
			MessageBox(hWnd, "CreateCompatibleBitmap failed!", NULL, MB_ICONSTOP);
			PostQuitMessage(0);
			return	0;
		}
		/* Connect Bitmap DC to Bitmap. */
		if(SelectObject(hSurfaceDC, hSurface) == NULL)
		{
			MessageBox(hWnd, "SelectObject failed!", NULL, MB_ICONSTOP);
			PostQuitMessage(0);
			return	0;
		}
		/* Clear Bitmap. */
		SelectObject(hSurfaceDC, GetStockObject(WHITE_BRUSH));
		FloodFill(hSurfaceDC, 0, 0, RGB(255, 255, 255));

		/* Create drawing pen. */
		if((hPen = CreatePen(PS_SOLID, 30, RGB(255, 0, 0))) == NULL)
		{
			MessageBox(NULL, "CreatePen failed!", NULL, MB_ICONSTOP);
			PostQuitMessage(0);
		}
	return	0;
	case WM_DESTROY:
		/* Clean up! */
           ReleaseDC(hWnd, hDC);
		DeleteDC(hSurfaceDC);
		DeleteObject(hSurface);
		/* Signal GetMessage to exit .. */
		PostQuitMessage(0);
	return	0;
	case WM_PAINT:
		if((hDC = BeginPaint(hWnd, &PS)) != NULL)
		{
			/* Blit Bitmap DC onto window DC. */
			if(!BitBlt(hDC, 0, 0, 640, 480, hSurfaceDC, 0, 0, SRCCOPY))
			{
				MessageBox(hWnd, "BitBlt failed!", NULL, MB_ICONSTOP);
				PostQuitMessage(0);
			}
			EndPaint(hWnd, &PS);
		}
	return	0;
	case WM_MOUSEMOVE:
		if(wParam == MK_LBUTTON)
		{
			/* Draw on Bitmap surface. */
			Pos.x = LOWORD(lParam);
			Pos.y = HIWORD(lParam);

			hPenBak = SelectObject(hSurfaceDC, hPen);
			MoveToEx(hSurfaceDC, Pos.x, Pos.y, NULL);
			LineTo(hSurfaceDC, Pos.x, Pos.y);
			SelectObject(hSurfaceDC, hPenBak);

			/* Signal window to update. */
			InvalidateRect(hWnd, NULL, FALSE);
			break;
		}
	return	0;
	case WM_LBUTTONDOWN:
       	/* Draw on mouse click instantly. */
		GetCursorPos(&POS);
		ScreenToClient(hWnd, &POS);
		SendMessage(hWnd, WM_MOUSEMOVE, MK_LBUTTON,
			MAKELPARAM(POS.x, POS.y));
		return	0;
	case WM_RBUTTONDOWN:
		/* Clear surface. */
		SetRect(&rcClient, 0, 0, 640, 480);
		FillRect(hSurfaceDC, &rcClient, GetStockObject(WHITE_BRUSH));
		/* Signal window to update. */
		InvalidateRect(hWnd, NULL, FALSE);
		return	0;
}

return	DefWindowProc(hWnd, Msg, wParam, lParam);
}

post-2948-129063053337_thumb.png

Δημοσ.

 

[/color]Ένα κομάτι απο κώδικα που χρησιμοποιώ για ζωγράφισμα εκτός wm_paint.

 

 

 

>
int mdisplay::__GetDC(){
register HDC hdc = GetDC((HWND)owner()->getHwnd());
massert(((HDC)(mword)hdc) == hdc);//check for data loss
set_hdc((mword)hdc);
return hdc ? TRUE : FALSE;
}

void mdisplay::__ReleaseDC(){
if(hdc()){
	int bReleased = ReleaseDC((HWND)owner()->getHwnd(),(HDC)hdc());
#ifdef _DEBUG
	//if(_u_winapi_getFlag("ReleaseDCLog",FALSE)){
	//	writeDebug(
	//		"ReleaseDC(owner=%x, hdc=%x, returned %s)\n",
	//			(mword)owner()->getHwnd(),
	//			(mword)hdc(),
	//			bReleased ? "RELEASES" : "NOT RELEASED"
	//	);
	//}
#endif
	set_hdc(NULL);
}
}

Αυτές είναι οι low level συναρτησεις του class που χρησιμοποιώ σε windows.

Θα βγάλεις άκρη πιστευώ, εχω κρατήσει και τα "ονόματα" των windows (hdc,hwnd...) στα εσωτερικά members

 

 

Θεος, τωρα το ειδα.

>	case WM_MOUSEMOVE:
	{
		if(wParam == MK_LBUTTON)
		{
			hdc = GetDC(hWnd);
			assert(hdc!=NULL);
			HPEN hPen = CreatePen(PS_SOLID,50,RGB(22,111,22));
		    SelectObject(hdc,hPen);
			assert(hPen != NULL);
			
			MoveToEx(hdc,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y,NULL);
			LineTo(hdc,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			ReleaseDC(hWnd,hdc);
		}
	}
	break;

:-D

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...