Howdy, Stranger!

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

Categories

Welcome to the new platform of Programmer's Heaven! We apologize for the inconvenience caused, if you visited us from a broken link of the previous version. The main reason to move to a new platform is to provide more effective and collaborative experience to you all. Please feel free to experience the new platform and use its exciting features. Contact us for any issue that you need to get clarified. We are more than happy to help you.

Drawing two or more rectangles on single client window

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