C/C++ Windows API

Moderators: Lundin
Number of threads: 443
Number of posts: 1215

This Forum Only
Post New Thread
Single Post View       Linear View       Threaded View      f

Report
Drawing two or more rectangles on single client window Posted by Sonx_hvn7 on 6 May 2008 at 5:15 AM
Here's my attempt on trying to draw two rectangles on the same window!

#include "stdafx.h"
#include <windows.h>  //include all the basics
#include <tchar.h>    //string and other mapping macros
#include <string>
   
// Define structure for colors
typedef struct rgbColors {
	int R,G,B;
} RGBColor;

#define MAXCOLOR 10

//define an unicode string type alias
typedef std::basic_string<TCHAR> ustring;

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

void DrawARectangle(HWND hwnd, HPEN hpen, HDC hdc,HBRUSH hbrush,
PAINTSTRUCT pntS, const RECT& rc);

void PaintObject(HWND hwnd, const RECT& rc, RGBColor *c, int p);
RECT initRecArea(int l,int r,int t,int b);

inline int ErrMsg(const ustring&);

//setup some edit control id's
enum {
	IDCE_SINGLELINE=200,
	IDCE_MULTILINE,
};

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR pStr,int nCmd)
{
	ustring classname=_T("RFS Range");
	WNDCLASSEX wcx={0}; 
	wcx.cbSize = sizeof(WNDCLASSEX);           
	wcx.lpfnWndProc = WndProc;
	wcx.hInstance = hInst;
	wcx.hIcon = LoadImage(0,IDI_APPLICATION,IMAGE_ICON,0,0,LR_SHARED);
	wcx.hCursor = LoadImage(0,IDC_ARROW,IMAGE_CURSOR,0,0,LR_SHARED);
	wcx.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BTNFACE+1);   
	wcx.lpszClassName = classname.c_str(); 

	if (!RegisterClassEx(&wcx))
	{
		ErrMsg(_T("Failed to register wnd class"));
		return -1;
	}

	int desktopwidth=GetSystemMetrics(SM_CXSCREEN);
	int desktopheight=GetSystemMetrics(SM_CYSCREEN);

	HWND hwnd=CreateWindowEx(0,                     //extended styles
		classname.c_str(),     //name: wnd 'class'
		_T("RFS Range"),	   //wnd title
		WS_OVERLAPPEDWINDOW,   //wnd style
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		/*desktopwidth/4,        //position:left
		desktopheight/4,       //position: top
		desktopwidth/2,        //width
		desktopheight/2,       //height*/
		0,                     //parent wnd handle
		0,                     //menu handle/wnd id
		hInst,                 //app instance
		0);                    //user defined info
	if (!hwnd)
	{
		ErrMsg(_T("Failed to create wnd"));
		return -1;
	}

	ShowWindow(hwnd,nCmd); 
	UpdateWindow(hwnd);
	MSG msg;

	while (GetMessage(&msg,0,0,0)>0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return static_cast<int>(msg.wParam);
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	int pos=0;
	RGBColor colors[MAXCOLOR] = {{0x80,0x80,0x80},{0x00,0xFF,0x00},
	{0xFF,0xFF,0xFF},{0x00,0x00,0x00}};

	switch (uMsg)
	{
	case WM_CREATE:
          return 0;

	case WM_PAINT:

	   // Draw rectangle area 1
	   PaintObject(hwnd,initRecArea(5,5,300,350),colors,pos);

	   // Draw rectangle area 2
	   PaintObject(hwnd,initRecArea(400,5,800,250),colors,pos);

	   return 0;

	case WM_TIMER: 
	   /* Force the WM_PAINT */
	   InvalidateRect (hwnd, NULL, TRUE);
	   UpdateWindow(hwnd);
	break;

	case WM_DESTROY:
	   PostQuitMessage(0);
	   return 0;

	default:

    return DefWindowProc(hwnd,uMsg,wParam,lParam);  
    }
}

inline int ErrMsg(const ustring& s)
{
return MessageBox(0,s.c_str(),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
}

// Purpose: Draws a rectangle which will have text boxes for input data
void DrawARectangle(HWND hwnd, HPEN hpen, HDC hdc, 
					HBRUSH hbrush, PAINTSTRUCT pntS, const RECT& rc) 
{
	HPEN hpenOld;
	HBRUSH hbrushOld;

	// Select the new pen and brush, and then draw.
	hpenOld = (HPEN)SelectObject(hdc, hpen);
	hbrushOld = (HBRUSH)SelectObject(hdc, hbrush);
	Rectangle(hdc,rc.left,rc.top,rc.right,rc.bottom);

	// Do not forget to clean up.
	SelectObject(hdc, hpenOld);
	DeleteObject(hpen);
	SelectObject(hdc, hbrushOld);
	DeleteObject(hbrush);
}

// Purpose: Draws an object on the window
void PaintObject(HWND hwnd, const RECT& rc, RGBColor *color, int index)
{
	HDC hdc;
	HPEN hpen;
	HBRUSH hbrush;
	PAINTSTRUCT pntS;

	hdc = BeginPaint(hwnd, &pntS);									
	hpen = CreatePen(PS_SOLID, 2, RGB(color[index+3].R, color[index+3].G, color[index+3].B));
	hbrush = CreateSolidBrush(RGB(color[index].R, color[index].G, color[index].B));
	DrawARectangle(hwnd, hpen, hdc, hbrush, pntS, rc);
	EndPaint(hwnd, &pntS);
}

// Initialize rectangle area
RECT initRecArea(int left, int top, int width, int height)
{
	RECT rec = {left, top, width, height};
	return rec;
}


rectangles draws if one of PaintObject() function is called, calling both only draws the fisrt call... Any ideas on how to draw morethan one rectangle on same window????
Report
Re: Drawing two or more rectangles on single client window Posted by Lundin on 6 May 2008 at 5:48 AM
Did you try to call the Rectangle function twice, but with different parameters?
Report
Re: Drawing two or more rectangles on single client window Posted by Sonx_hvn7 on 6 May 2008 at 11:02 PM
: Did you try to call the Rectangle function twice, but with different
: parameters?

Inside WM_PAINT, the function PaintObject() attempts to do that... Check it's parameters, initRecArea() has different coordinates...
Report
Re: Drawing two or more rectangles on single client window Posted by AsmGuru62 on 7 May 2008 at 2:39 AM
WM_PAINT message gives you only one shot at drawing. Meaning: you must only have ONE PAIR of BeginPaint/EndPaint calls. So, this is what you should always do:

1. You enter your WM_PAINT case
2. You call BeginPaint() and get back an HDC

3. You paint ALL contents of a window

4. You call EndPaint() and let Windows know that your drawing is done. This is what is happening: once Windows knows that drawing is done (you call EndPaint() twice) - it will not do any action on the second call to BeginPaint() in the same response to WM_PAINT. You need next WM_PAINT for the next drawing.
5. You exit your WM_PAINT case

So, to resolve this simply move BeginPaint/EndPaint out of your drawing functions and into the WM_PAINT case.

Hint: it is less code to draw rectangles using FillRect()/FrameRect() API - you do not need to select any brushes or pens into DC:
void DrawFilledRect (HDC hDC, RECT& r, COLORREF rgbFrame, COLORREF rgbInterior)
{
	HBRUSH hBrush;

	hBrush = CreateSolidBrush (rgbInterior);
	FillRect (hDC, &r, hBrush);
	DeleteObject (hBrush);

	hBrush = CreateSolidBrush (rgbFrame);
	FrameRect (hDC, &r, hBrush);
	DeleteObject (hBrush);
}

This will work nicely for solid colors, but if you need some fancy border, like PS_DOT_DASH_DOT or something of the sort - you still need to create pens and select them.

How to cause WM_PAINT? Do not send WM_PAINT by your code. To update a portion of the window call two functions in sequence:
void RefreshWnd (HWND hWnd, RECT* pArea)
{
	InvalidateRect (hWnd, pArea, TRUE);
	UpdateWindow (hWnd);
}

To redraw only portion - pass the address of a portion in 2-nd parameter, to refresh whole client surface - pass NULL instead of this address.
Report
Re: Drawing two or more rectangles on single client window Posted by Sonx_hvn7 on 12 May 2008 at 6:13 AM
: WM_PAINT message gives you only one shot at drawing.
: Meaning: you must only have ONE PAIR of BeginPaint/EndPaint calls.
: So, this is what you should always do:
:
: 1. You enter your WM_PAINT case
: 2. You call BeginPaint() and get back an HDC
:
: 3. You paint ALL contents of a window
:
: 4. You call EndPaint() and let Windows know that your drawing is
: done. This is what is happening: once Windows knows that drawing is
: done (you call EndPaint() twice) - it will not do any action on the
: second call to BeginPaint() in the same response to WM_PAINT. You
: need next WM_PAINT for the next drawing.
: 5. You exit your WM_PAINT case
:
: So, to resolve this simply move BeginPaint/EndPaint out of your
: drawing functions and into the WM_PAINT case.
:
: Hint: it is less code to draw rectangles using
: FillRect()/FrameRect() API - you do not need to select any brushes
: or pens into DC:
:
: 
: void DrawFilledRect (HDC hDC, RECT& r, COLORREF rgbFrame, COLORREF rgbInterior)
: {
: 	HBRUSH hBrush;
: 
: 	hBrush = CreateSolidBrush (rgbInterior);
: 	FillRect (hDC, &r, hBrush);
: 	DeleteObject (hBrush);
: 
: 	hBrush = CreateSolidBrush (rgbFrame);
: 	FrameRect (hDC, &r, hBrush);
: 	DeleteObject (hBrush);
: }
: 
:
: This will work nicely for solid colors, but if you need some fancy
: border, like PS_DOT_DASH_DOT or something of the sort - you still
: need to create pens and select them.
:
: How to cause WM_PAINT? Do not send WM_PAINT by your code. To update
: a portion of the window call two functions in sequence:
:
: 
: void RefreshWnd (HWND hWnd, RECT* pArea)
: {
: 	InvalidateRect (hWnd, pArea, TRUE);
: 	UpdateWindow (hWnd);
: }
: 
:
: To redraw only portion - pass the address of a portion in 2-nd
: parameter, to refresh whole client surface - pass NULL instead of
: this address.
:


Thanks a lot asmguru, u really are a guru! lol



 

Recent Jobs

Official Programmer's Heaven Blogs
Web Hosting | Browser and Social Games | Gadgets

Popular resources on Programmersheaven.com
Assembly | Basic | C | C# | C++ | Delphi | Flash | Java | JavaScript | Pascal | Perl | PHP | Python | Ruby | Visual Basic
© Copyright 2011 Programmersheaven.com - All rights reserved.
Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
Operated by CommunityHeaven, a BootstrapLabs company.