Click here to Skip to main content
15,884,473 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hello,

The issue is related to Windows GDI, actually about repainting "framed" regions (HRGN framed with "FrameRgn" function)

Looking for help or an advice on how to handle regions repainting correctly.

I have created following class:

//*****************************************************


#ifndef OwnerDrawnButtonH
#define OwnerDrawnButtonH

#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <jpeg.hpp>
#include <Graphics.hpp>

#include <windows.h>
//--------------------------------------------------------------------------
class

TOwnerDrawnButton {

 HRGN rgn;
 HWND hWnd;
 TImage *img; 
 TForm *form; 
 COLORREF rgb; 

public:

 TOwnerDrawnButton (TForm *, TImage *, HWND);
 TOwnerDrawnButton () {};

 void __fastcall drawPressed(); 
 void __fastcall drawFocused(); 
 void __fastcall clearFrame(); 
};

#endif

//*****************************************************


Implementation of some methods:

//*****************************************************
// constructor initializes "img" property with submited image parameter

// handle is HWND handle to forms window


TOwnerDrawnButton::TOwnerDrawnButton (TForm *frm, TImage *image, HWND handle)

{
 rgb = 0x00ffeeff; // light gray RGB color code
 hWnd = handle;
 form = frm;
 img = image;
}

//---------------------------------------------------------------
// "clearFrame" method draws two frames(outer, blue, 1 pixel width, and inner, gray, 4 pixels width) around region 
// that corresponds to area under the "img" property of object

void __fastcall TOwnerDrawnButton::clearFrame()
{
// drawing outer frame, width 1 pixel

 rgb = 0x00ff0000; // blue color RGB code

 rgn = CreateRoundRectRgn(form->Left + img->Left + 1,
  form->Top + 26 + img->Top + 1,
  form->Left + img->Left + img->Width + 12,
  form->Top + 26 + img->Top + img->Height + 12,
  4 , 4);

 HDC hdc = GetDC(hWnd);
 HBRUSH brush = CreateSolidBrush(rgb);
 FrameRgn(hdc, rgn, brush, 1, 1);
 ReleaseDC(hWnd,hdc);
 DeleteObject(rgn);

// drawing inner frame, width 4 pixels

 rgb = 0x00ffeeff; // light gray RGB color code
 rgn = CreateRoundRectRgn(form->Left + img->Left + 2,
  form->Top + 26 + img->Top + 2,
  form->Left + img->Left + img->Width + 11,
  form->Top + 26 + img->Top + img->Height + 11,
  4 , 4);

 hdc = GetDC(hWnd);
 brush = CreateSolidBrush(rgb);
 FrameRgn(hdc, rgn, brush, 4, 4);
 ReleaseDC(hWnd,hdc);
 DeleteObject(rgn);

}

//*****************************************************

I put two bitmap images on the form (by dragging Image icon from toolbar - TImage *img1, TImage *img2). Then i load bitmap images on to their Picture properties (TBitmap * - type). In the private section of the form i have declared two attributes type TOwnerDrawnButton*:

TOwnerDrawnButton *odButton1;

TOwnerDrawnButton *odButton2;

Now, in the forms constructor I have initialized these two TOwnerDrawnButton objects next way :

odButton1 = new TOwnerDrawnButton(this, img1, hwnd);

odButton2 = new TOwnerDrawnButton(this, img2, hwnd);<br />

To always have painted frames around images on the form, i put following code in an OnPaint event of the form:

odButton1->clearFrame();

odButton2->clearFrame();

When i run application, problem is that when my forms window is not top most (i drag some other opened window above it), those region frames are being redrawed on top of the foreground window. I understand that it is normal because of the code in an OnPaint event, but don't know the way to solve this situation.

Some more information:
i am coding in C++ using Borland C++ Builder, including VCL library (creating forms with 'drag and drop' technique). Actually, I created form (for now it's just that first form initially created when you start new project) and put two image components on it (VCL library, Additional Tab, dragged and dropped Image component on form).

This way i added two IDE Managed Components of 'TImage *' type (named img1 and img2):

TImage* img1;

TImage* img2;

Each 'TImage*' object/component has its own Picture property, which is of TBitmap type. So, in Object Inspector i have assigned proper bitmap images to Picture properties.

Appreciate any help or advice.
Posted
Comments
mbue 5-Mar-11 9:20am    
On which circumstances you draw the frames (on OnPaint)? OnPaint you should get a DC you can paint in (thats the client dc).
btw: you should delete your brushes (after about 10k not deleted gdi-objects you cant create any gdi object anymore).
Regards.
vvozar 5-Mar-11 14:00pm    
Code in FormPaint method looks like this for now:
<pre> void __fastcall TfrmMainForm::FormPaint(TObject *Sender)
{
odButton1->clearFrame();
odButton2->clearFrame();
}
</pre>
This my first time working with Device Context, Brushes, Regions, Rectangles... I'm not quite sure am i using Device context correctly.

"OnPaint you should get a DC you can paint in (thats the client dc)" - what do you mean exactly? Do you mean that i should get DC in FormPaint method, modify clearFrame(...) method and pass that DC as a parameter?
(thanks for info about brushes, i'll add DeleteObject(brush); at the end of the method)
vvozar 5-Mar-11 16:27pm    
What do you mean by 'client DC'?
vvozar 7-Mar-11 13:02pm    
Just read about DC's. I am trying to find out how to get my forms window handle, so I could get device context for that window(client DC). As 'mbue' said, i should get client DC to paint on it, because up in the code i am using device context of entire screen. Maybe that's the cause of repainting issue. Does anyone know how to get device context for painting on client area of the window? Or how to get my windows handle (HWND)?

1 solution

Instead of using regions, device contexts and brushes, i will draw directly on the form.
I've changed code in clearFrame() method to:
void __fastcall TOwnerDrawnButton::clearFrame()
{
        form->Canvas->Pen->Style = psSolid;
        form->Canvas->Pen->Width = 4;
        form->Canvas->Pen->Color = clLtGray;
        form->Canvas->Brush->Style = bsClear;
        form->Canvas->Rectangle(
          img->Left - 2,
          img->Top  - 2,
          img->Left + img->Width + 2,
          img->Top  + img->Height + 2
          );
}

This way it draws directly on forms canvas, and requires less memory management (allocating and freeing) comparing to using regions and brushes.
To be able to draw directly on a form, FormStyle must be set either to fsNormal or fsStayOnTop.
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900