Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Drawing two or more rectangles on single client window

Sonx_hvn7Sonx_hvn7 Member Posts: 54
Here's my attempt on trying to draw two rectangles on the same window!

[code]
#include "stdafx.h"
#include //include all the basics
#include //string and other mapping macros
#include

// 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 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(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(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;
}
[/code]

[color=Blue]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????[/color]

Comments

  • LundinLundin Member Posts: 3,711
    Did you try to call the Rectangle function twice, but with different parameters?
  • Sonx_hvn7Sonx_hvn7 Member Posts: 54
    : 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...
  • AsmGuru62AsmGuru62 Member Posts: 6,519
    [color=Blue]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

    [color=Red]3. You paint ALL contents of a window[/color]

    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:
    [code]
    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);
    }
    [/code]
    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:
    [code]
    void RefreshWnd (HWND hWnd, RECT* pArea)
    {
    InvalidateRect (hWnd, pArea, TRUE);
    UpdateWindow (hWnd);
    }
    [/code]
    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.
    [/color]
  • Sonx_hvn7Sonx_hvn7 Member Posts: 54
    : [color=Blue]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
    :
    : [color=Red]3. You paint ALL contents of a window[/color]
    :
    : 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:
    : [code]:
    : 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);
    : }
    : [/code]:
    : 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:
    : [code]:
    : void RefreshWnd (HWND hWnd, RECT* pArea)
    : {
    : InvalidateRect (hWnd, pArea, TRUE);
    : UpdateWindow (hWnd);
    : }
    : [/code]:
    : 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.
    : [/color]

    Thanks a lot asmguru, u really are a guru! lol
Sign In or Register to comment.