Board index » cppbuilder » custom groupbox

custom groupbox


2007-11-30 05:05:09 AM
cppbuilder80
I am making a custom groupbox component derived from TCustomComponent. I am using regions to make part of it transparent. It should be a box with another smaller box with the caption in it slightly sticking up off the top. This all works fine. My problem with it is that when I put components on it at design-time some can't be seen (ie. labels show up fine but radio buttons don't, and the little blue handles for resizing don't show up on anything). It seems to work as intended at run-time, but can make it difficult to work with when designing the form.
I can somewhat fix this problem by looping through the child controls and calling Repaint() on them but that causes it to be constanly refreshed and hammers the system.
Any advice on what might be causing this and how I might go about fixing it?
Thanks,
Kent
 
 

Re:custom groupbox

Hi Kent
Kent says:
Quote

I am making a custom groupbox component derived from TCustomComponent. I am using regions to make part of it transparent. It should be a box with another smaller box with the caption in it slightly sticking up off the top. This all works fine. My problem with it is that when I put components on it at design-time some can't be seen (ie. labels show up
fine but radio buttons don't, and the little blue handles for resizing don't show up on anything). It seems to work as intended at run-time, but can make it difficult to work with when designing the form.

I can somewhat fix this problem by looping through the child controls and calling Repaint() on them but that causes it to be constanly refreshed and hammers the system.

Any advice on what might be causing this and how I might go about fixing it?

Thanks,
Kent
I dont have a TCustomComponent in my BCB5,but from the
name I gues that it is the ancestor to TComponent an if
that is the case and You want Your component to be able
to have children dropped on it like a panel You have to
derive Your component from one of the Windowed classes.
TCustomControl, TCustomPanel, TWindowControl etc.
P.s. Please hard break Your lines.
Kind regards
Asger
 

Re:custom groupbox

Quote

I dont have a TCustomComponent in my BCB5,but from the
name I gues that it is the ancestor to TComponent an if
that is the case and You want Your component to be able
to have children dropped on it like a panel You have to
derive Your component from one of the Windowed classes.
TCustomControl, TCustomPanel, TWindowControl etc.

P.s. Please hard break Your lines.

Kind regards
Asger
Right, sorry about the line break thing. My component is
derived from TCustomControl, it was a typo. I also have it's
ControlStyle set to include csAcceptsControls.
Thanks again.
 

{smallsort}

Re:custom groupbox

Sorry, you snuck in your reply while I got distracted trying to reply to the other reply.
Quote
There is no such class. Are you referring to TCustomControl? Why not just
derive from TCustomGroupBox instead?

Yes, I meant to type TCustomControl. I did try deriving from
TCustomGroupBox, but it didn't solve the problem.
Quote

Do you have the csAcceptsControls flag enabled in the ControlStyle property?

Yes, I do have csAcceptsControls enabled.
To elaborate a bit more... the radio buttons seem to draw just
their plain colored background (my component has a gradient)
but not the text or the button. StringGrids will draw the blank
white box and bevels with scrollbars, but not the actual cells.
When I select the form everything is on the components all seem
to draw fine. But if I select the groupbox almost everything
goes blank and if I select a component on the groupbox
everything else will draw OK, but the selected component will
be blank. If the handles for components get drawn at all their location will be way off the almost like the where they would
be if the component was on the parent of the groupbox instead
(I don't know if that makes sense but it's hard to explain).
Thanks again,
Kent
 

Re:custom groupbox

"Kent" < XXXX@XXXXX.COM >wrote in message
Quote
I am making a custom groupbox component derived from
TCustomComponent.
There is no such class. Are you referring to TCustomControl? Why not just
derive from TCustomGroupBox instead?
Quote
My problem with it is that when I put components on it at design-time
some can't be seen (ie. labels show up fine but radio buttons don't,
and the little blue handles for resizing don't show up on anything).
Do you have the csAcceptsControls flag enabled in the ControlStyle property?
Gambit
 

Re:custom groupbox

Hi Kent
Just a thought, do You handle the WM_PAINT or are You
overriding the paint procedure.
I have seen strange thigs happen when I handled the
WM_PAINT message and forgot to dispatch it.
Otherwise I have no Idea what is going on
Good luck
Kind regards
Asger
 

Re:custom groupbox

"Kent" < XXXX@XXXXX.COM >wrote in message
Quote
Yes, I meant to type TCustomControl. I did try deriving
from TCustomGroupBox, but it didn't solve the problem.
Please show your actual code. It has to be doing something to interfer with
the default behaviors of the components. Are you overriding any methods, or
handling any messages?
Gambit
 

Re:custom groupbox

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >wrote:
Quote

Please show your actual code. It has to be doing something to interfer with
the default behaviors of the components. Are you overriding any methods, or
handling any messages?


Gambit

Here is some of my code. Obviously it's not all my code, but
I'm hoping it's enought for you to get an idea of what's going
on. I left out my setter functions and the actual code that's
drawing the gradient backgrounds and stuff, but I'm hopping
you can tell what's going on from this sample.
class PACKAGE TDJGradGroupBox : public TCustomGroupBox
{
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_ERASEBKGND, TMessage, WMErasebkgnd)
END_MESSAGE_MAP(TCustomControl)
public:
__fastcall TDJGradGroupBox(TComponent* Owner);
__fastcall ~TDJGradGroupBox();
protected:
virtual void __fastcall Paint();
void __fastcall BuildBmpBackground(Graphics::TBitmap *lBmp);
void __fastcall BuildBmpCaption(Graphics::TBitmap *lBmp);
HRGN __fastcall BuildRgn();
void __fastcall WMErasebkgnd(TMessage &Msg);
virtual void __fastcall AlignControls(TControl* AControl, TRect &Rect);
private:
Graphics::TBitmap *BGBmp;
Graphics::TBitmap *CapBmp;
TColor FColorBackgroundFace, FColorBackgroundGrad;
TColor FBoarderColor;
TColor FColorCaptionFace, FColorCaptionGrad;
TColor FCaptionBoarderColor;
void __fastcall SetColorBackgroundFace(TColor NewColor);
void __fastcall SetColorBackgroundGrad(TColor NewColor);
void __fastcall SetBoarderColor(TColor NewColor);
void __fastcall SetColorCaptionFace(TColor NewColor);
void __fastcall SetColorCaptionGrad(TColor NewColor);
void __fastcall SetCaptionBoarderColor(TColor NewColor);
__published:
__property TColor BackgroundColorFace = {read = FColorBackgroundFace, write = SetColorBackgroundFace, default = clBtnShadow};
__property TColor BackgroundColorGrad = {read = FColorBackgroundGrad, write = SetColorBackgroundGrad, default = clBackground};
__property TColor BackgroundBoarderColor = {read = FBoarderColor, write = SetBoarderColor, default = clWhite};
__property TColor CaptionColorFace = {read = FColorCaptionFace, write = SetColorCaptionFace, default = clBtnShadow};
__property TColor CaptionColorGrad = {read = FColorCaptionGrad, write = SetColorCaptionGrad, default = clBackground};
__property TColor CaptionBoarderColor = {read = FCaptionBoarderColor, write = SetCaptionBoarderColor, default = clWhite};
};
static inline void ValidCtrCheck(TDJGradGroupBox *)
{
new TDJGradGroupBox(NULL);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
__fastcall TDJGradGroupBox::TDJGradGroupBox(TComponent* Owner) : TCustomGroupBox(Owner)
{
BGBmp = new Graphics::TBitmap();
CapBmp = new Graphics::TBitmap();
ControlStyle = ControlStyle << csAcceptsControls;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
__fastcall TDJGradGroupBox::~TDJGradGroupBox()
{
delete BGBmp;
delete CapBmp;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TDJGradGroupBox::Paint()
{
int clientWidth = ClientRect.Width();
if(clientWidth>0)
{
BuildBmpBackground(BGBmp);
BuildBmpCaption(CapBmp);
HRGN rgn = BuildRgn();
if(!SetWindowRgn(Handle, rgn, true))
RaiseLastWin32Error();
DeleteObject(rgn);
Canvas->Draw(0,5,BGBmp);
Canvas->Draw(5,0,CapBmp);
}
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
HRGN __fastcall TDJGradGroupBox::BuildRgn()
{
HRGN bgRgn = CreateRectRgn(0, 5, BGBmp->Width, BGBmp->Height+5);
HRGN capRgn = CreateRectRgn(5, 0, CapBmp->Width+5, CapBmp->Height);
CombineRgn(bgRgn, bgRgn, capRgn, RGN_OR);
DeleteObject(capRgn);
return bgRgn;
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
void __fastcall TDJGradGroupBox::WMErasebkgnd(TMessage &Msg)
{
Msg.Result = 1;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TDJGradGroupBox::BuildBmpBackground(Graphics::TBitmap *lBmp)
{
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TDJGradGroupBox::BuildBmpCaption(Graphics::TBitmap *lBmp)
{
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TDJGradGroupBox::AlignControls(TControl* AControl, TRect &Rect)
{
// modify Rect as needed
Rect.Top += 10;
Rect.Left += 5;
Rect.Bottom -= 5;
Rect.Right -= 5;
for(int t = 0; t < ControlCount; t++)
{
if(Controls[t]->Top < Rect.Top)
Controls[t]->Top = Rect.Top;
if(Controls[t]->Height>Rect.Height())
Controls[t]->Height = Rect.Height();
}
TCustomGroupBox::AlignControls(AControl, Rect);
}
Thanks for taking the time to look at it. Please don't be too
brutal in your critique of my code. I'm no expert component
writer.
-Kent
 

Re:custom groupbox

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >wrote:
Quote

You are re-building your bitmaps and region on every paint request. That is
a very bad place to perform those kinds of operations (especially the region
assignment in particular). Controls can receive hundreds of paint requests
very quickly. A window region only needs to be set once after the window is
created, and then left alone until the window is either resized or
recreated. Paint() should be used for drawing only and nothing else. Don't
touch the region at all, and draw whatever the bitmaps currently hold at
that moment. The Resize() method would be a better place to change the
bitmaps and region. Or intercept the WM_WINDOWPOSChanging message instead.


DO NOT ever delete the region if SetWindowRgn() succeeds. SetWindowRgn()
passes ownership of the region to the window. The window will clean it up
automatically when needed. This is clearly stated in SetWindowRgn()'s
documentation:


Gambit


I made those changes and it all works great now.
Thanks a bunch!
-Kent
 

Re:custom groupbox

"Kent" < XXXX@XXXXX.COM >wrote in message
Quote
Here is some of my code. Obviously it's not all my code, but
I'm hoping it's enought for you to get an idea of what's going
on. I left out my setter functions and the actual code that's
drawing the gradient backgrounds and stuff, but I'm hopping
you can tell what's going on from this sample.
You are re-building your bitmaps and region on every paint request. That is
a very bad place to perform those kinds of operations (especially the region
assignment in particular). Controls can receive hundreds of paint requests
very quickly. A window region only needs to be set once after the window is
created, and then left alone until the window is either resized or
recreated. Paint() should be used for drawing only and nothing else. Don't
touch the region at all, and draw whatever the bitmaps currently hold at
that moment. The Resize() method would be a better place to change the
bitmaps and region. Or intercept the WM_WINDOWPOSChanging message instead.
Quote
HRGN rgn = BuildRgn();
if(!SetWindowRgn(Handle, rgn, true))
RaiseLastWin32Error();
You are leaking the region if SetWindowRgn() fails.
Quote
DeleteObject(rgn);
DO NOT ever delete the region if SetWindowRgn() succeeds. SetWindowRgn()
passes ownership of the region to the window. The window will clean it up
automatically when needed. This is clearly stated in SetWindowRgn()'s
documentation:
"After a successful call to SetWindowRgn, the operating system owns the
region specified by the region handle hRgn. The operating system does not
make a copy of the region. Thus, you should not make any further function
calls with this region handle. In particular, do not close this region
handle."
Gambit