BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

TPanel derived class Paint problem

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (VCL Components Usage)
View previous topic :: View next topic  
Author Message
Kent
Guest





PostPosted: Mon Apr 03, 2006 6:03 am    Post subject: TPanel derived class Paint problem Reply with quote



I have derived a class from TPanel to custom draw the panel's borders,
based on one of JD's past
posts. The TPanels contain one TImage and a variable number of
TSpeedButtons, with the speedbuttons added at runtime.

void __fastcall TMyPanel::Paint()
{
Canvas->Brush->Color = clBtnFace;
Canvas->FillRect( Canvas->ClipRect );
Frame3D(Canvas, Canvas->ClipRect, clBtnShadow, clBtnShadow, 1);

}

I have also tried the following:

void __fastcall TMyPanel::PaintWindow(HDC DC)
{
Canvas->Handle = DC;
Canvas->Brush->Color = clBtnFace;
Canvas->FillRect( Canvas->ClipRect );
Frame3D(Canvas, Canvas->ClipRect, clBtnShadow, clBtnShadow, 1);
}


Both ways seem to work equally well. The only problem I have occurs
using both methods: when the speedbutton's flat property is set to
true, moving the mouse over and exiting the button leaves the
bottom/right clBtnShadow raised edges behind.

What can I do to stop this from happening?

I'm using BCB3 Pro on XP Pro.

Kent
Back to top
JD
Guest





PostPosted: Mon Apr 03, 2006 6:03 pm    Post subject: Re: TPanel derived class Paint problem Reply with quote



"Kent" <kentav (AT) accessus (DOT) net> wrote:
Quote:

[...]
void __fastcall TMyPanel::PaintWindow(HDC DC)
{
Canvas->Handle = DC;
Canvas->Brush->Color = clBtnFace;
Canvas->FillRect( Canvas->ClipRect );
Frame3D(Canvas, Canvas->ClipRect, clBtnShadow, clBtnShadow, 1);
}

That must be really old because I would never code that that
way today.

Quote:
[...] when the speedbutton's flat property is set to true,
moving the mouse over and exiting the button leaves the
bottom/right clBtnShadow raised edges behind.

You're going to have to post the whole class.

~ JD
Back to top
Kent
Guest





PostPosted: Tue Apr 04, 2006 3:03 am    Post subject: Re: TPanel derived class Paint problem Reply with quote



JD,

Thanks for replying.

Here is the link for the post to which I was referring:

http://216.101.185.148/scripts/isapi.dll/article?id=36FD8391&article=6
033574

The class is exactly the same, just copied and pasted.

The only difference in my code is the "custom drawing" in the
PaintWindow method. When I noticed the problem, I tried the Paint
method and the problem persisted.

In the main form's constructor I have the following:

Panel2 = new TMyPanel(this);
Panel2->Parent = this;
Panel2->Width=27;
Panel2->Align=alRight;

Then I add TSpeedButtons to the panel and set some of their
properties.

Can you replicate the problem on your system?

Thanks for any help you can provide.

Kent
Back to top
Kent
Guest





PostPosted: Tue Apr 04, 2006 3:03 am    Post subject: Re: TPanel derived class Paint problem Reply with quote

JD,

Thanks for replying.

Here is the link for the post to which I was referring:

http://216.101.185.148/scripts/isapi.dll/article?id=36FD8391&article=6
033574

The class is exactly the same, just copied and pasted.

The only difference in my code is the "custom drawing" in the
PaintWindow method. When I noticed the problem, I tried the Paint
method and the problem persisted.

In the main form's constructor I have the following:

Panel2 = new TMyPanel(this);
Panel2->Parent = this;
Panel2->Width=27;
Panel2->Align=alRight;

Then I add TSpeedButtons to the panel and set some of their
properties.

Can you replicate the problem on your system?

Thanks for any help you can provide.

Kent
Back to top
JD
Guest





PostPosted: Tue Apr 04, 2006 6:03 am    Post subject: Re: TPanel derived class Paint problem Reply with quote

"Kent" <kentav (AT) accessus (DOT) net> wrote:
Quote:

Here is the link for the post to which I was referring:

Tamarack is by session only so as soon as you closed that
page, the link expired. I tried several different searches
but didn't find what I thought was the right class.

~ JD
Back to top
Kent
Guest





PostPosted: Tue Apr 04, 2006 6:03 am    Post subject: Re: TPanel derived class Paint problem Reply with quote

Quote:
Tamarack is by session only so as soon as you closed that
page, the link expired. I tried several different searches
but didn't find what I thought was the right class.


Sorry about that.

Here is the post:

From:"JD" <nospam (AT) nospam (DOT) com>

Subject:Re: TCanvas and repainting

Date:17 Oct 2005 16:27:47 -0700

Groups:borland.public.cppbuilder.vcl.components.using

Quote:
[...] What is the correct/proper way to set up a TCanvas on

a TPanel and have it handle its drawing in a way that will

not interfere with the other components' regular drawing

Subclass the TPanel so that you can override it's PaintWindow

method. For example:

//-------------------------------------------------------------

#ifndef MyPanelH

#define MyPanelH

//-------------------------------------------------------------

#include <Classes.hpp>

#include <ExtCtrls.hpp>

//-------------------------------------------------------------

class TMyPanel : public TPanel

{

protected:

virtual void __fastcall PaintWindow(HDC DC);

public:

__fastcall TMyPanel( TComponent *Owner );

};

//-------------------------------------------------------------

#endif



//-------------------------------------------------------------

#pragma hdrstop

#include "MyPanel.h"

#pragma package(smart_init)

//-------------------------------------------------------------

__fastcall TMyPanel::TMyPanel( TComponent *Owner ) : TPanel( Owner )

{

}

//-------------------------------------------------------------

void __fastcall TMyPanel::PaintWindow(HDC DC)

{

// do your custom drawing here

}

//-------------------------------------------------------------

Click File | New | Unit and save it as MyPanel. Then make it

look exactly as the above and save it again. Then add the

MyPanel header to the form's unit's includes and add this to

the form's unit:

TMyPanel *pPanel;

//-------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

pPanel = new TMyPanel( this );

pPanel->Parent = this;

pPanel->Left = 10;

pPanel->Top = 10;

// set any other properties as needed

for( int x = 0; x > Panel1->Component->Count; ++x )

{

TControl *pControl = dynamic_cast<TControl*>(

Panel1->Component[x] );

if( pControl ) pControl->Parent = pPanel;

}

delete Panel1;

}

//-------------------------------------------------------------

The above allows you to use the IDE as usual and it allows you

to *not* have to wrap the TMyPanel class into a component that

you would then have to install into the IDE so that you could

drop it on the form at design time.

Quote:
and at the same time have the least overhead?

That would depend on exactly how and what you are drawing and

what you define as overhead. What exactly are you trying to

accomplish and how are you trying to do it?

Quote:
Is there a set of best practices or a sort of guide with

regards to this?

First and foremost, you have to stick with what works for

you. When it comes to custom drawing, it's usually a matter

of trade-offs. How fast is fast enough? Is it worth it to

code 100 lines or more, or revert to assembler for only a

slight reduction in performance? Each case is unique and

needs to be approached as such.

~ JD
Back to top
JD
Guest





PostPosted: Tue Apr 04, 2006 9:03 am    Post subject: Re: TPanel derived class Paint problem Reply with quote

"Kent" <kentav (AT) accessus (DOT) net> wrote:
Quote:

Here is the post: [...]

I don't see any benifit from using that class. Everything that
you're doing in the paint methods is already handled natively
by the TPanel. For example:

Quote:
void __fastcall TMyPanel::PaintWindow(HDC DC)
{
Canvas->Handle = DC;

Don't do that!

Quote:
Canvas->Brush->Color = clBtnFace;

Set the Color property instead.

Quote:
Canvas->FillRect( Canvas->ClipRect );

If you don't override PaintWindow, this will happen
automatically.

Quote:
Frame3D(Canvas, Canvas->ClipRect, clBtnShadow, clBtnShadow, 1);

Set it's BevelInner to bvNone and BevelOuter to bvRaised. BTW:
ClipRect is not always the same as Rect( 0, 0, Width, Height ).

Quote:
}

From you original post, I'm uncertain if the problem is with
the TPanel's borders or the TSpeedButton's. In either case,
You can always Invalidate the TPanel when you detect CM_MOUSELEAVE.
For example:

protected: // User declarations
virtual void __fastcall WndProc( TMessage &Message );

//-------------------------------------------------------------
void __fastcall TMyPanel::WndProc( TMessage &Message )
{
if( Message.Msg == CM_MOUSELEAVE )
{
Invalidate();
}
TPanel::WndProc( Message );
}
//-------------------------------------------------------------

~ JD
Back to top
Kent
Guest





PostPosted: Wed Apr 05, 2006 5:03 am    Post subject: Re: TPanel derived class Paint problem Reply with quote

Quote:
I don't see any benifit from using that class. Everything that
you're doing in the paint methods is already handled natively
by the TPanel. For example:

I plan to do more drawing than the example code shows and use
different colors than the bevel properties allow.

Quote:

void __fastcall TMyPanel::PaintWindow(HDC DC)
{
Canvas->Handle = DC;

I pasted in this line from another "PaintWindow" post. I'm curious,
though, as to what circumstances would require using this parameter.


BTW:
Quote:
ClipRect is not always the same as Rect( 0, 0, Width, Height ).

Thanks for pointing this out.


Quote:
From you original post, I'm uncertain if the problem is with
the TPanel's borders or the TSpeedButton's. In either case,
You can always Invalidate the TPanel when you detect CM_MOUSELEAVE.

I tried that and it works, but it flickers the whole panel of
speedbuttons when moving from one speedbutton to the next.

In case I wasn't clear in my first post, the flat-style speedbuttons
stay "raised" on the right and bottom edges only when moving from one
speedbutton to the previous speedbutton (to the left) but do not stay
raised when moving to the right.

It seems strange that a simple class derivation introduces this
behavior.

Thanks for your interest. I appreciate it.

Kent
Back to top
JD
Guest





PostPosted: Wed Apr 05, 2006 10:03 am    Post subject: Re: TPanel derived class Paint problem Reply with quote

"Kent" <kentav (AT) accessus (DOT) net> wrote:
Quote:

I don't see any benifit from using that class. [...]

I plan to do more drawing [...]

Then I would suggest that you use a TBitmap for that, sizing
it to the same dimensions as the panel and doing all of your
drawing on it instead of the Panel's Canvas. Then, in the
PaintWindow method, use the TCanvas::CopyRect method to paint
the bitmap. It's the fastest that you can get using a pure VCL
solution and insignificantly slower than using the win32 API
BitBlt.

I recall that you also have a TImage in there as well. Since
you're already subclassing TPanel, you could add that image to
the resource and use another TBitmap instead.

Other considerations are if you configure the panel to be
resizable by setting it's Align property or by using some
other OnResize event and manually changing the panel's size.
If you going this way, intercept WM_WINDOWPOSCHANGED and change the bitmaps size and redraw it.

Quote:
and use different colors than the bevel properties allow.

Draw that once onto the bitmap unless it's going to be a
number of different colors.

Quote:
Canvas->Handle = DC;

[...] I'm curious, though, as to what circumstances would
require using this parameter.

In this class, TPanel's PaintWindow method has been overridden
by your PaintWindow method and your method does not use it and does not call it's inherited method which would use it.

Quote:
[...] Invalidate the TPanel when you detect CM_MOUSELEAVE.

I tried that and it works, but it flickers the whole panel of
speedbuttons when moving from one speedbutton to the next.

I overlooked that that message would be sent even if the mouse
was still within the panel's bounding rect but that's easy to
fix.

Quote:
[...] speedbuttons stay "raised" [...] It seems strange that
a simple class derivation introduces this behavior.

It's because the code that I posted isn't correct. The VCL
sends CM_MOUSELEAVE down it's Parent chain and I didn't check
to see if the message was intended for the TPanel or one of
the other controls that it's parenting. The following sample
also includes checking to see if the mouse is really outside
the panel's bounding rect before it Invalidates the entire
panel (even though I don't think you'll need it for the panel):

//-------------------------------------------------------------
void __fastcall TMyPanel::WndProc( TMessage &Message )
{
if( Message.Msg == CM_MOUSELEAVE )
{
TControl *pControl = reinterpret_cast<TControl*>( Message.LParam );
TSpeedButton *pButton = dynamic_cast<TSpeedButton*>( pControl );
if( pButton ) // it's for a speedbutton
{
// repaint the button
pButton->Invalidate();
}
else // it's for the panel
{
TRect R;
TPoint P;
::GetWindowRect( Handle, &R );
::GetCursorPos( &P );
if( !::PtInRect(R,P) ) Invalidate();
}
}
TPanel::WndProc( Message );
}
//-------------------------------------------------------------

~ JD
Back to top
Kent
Guest





PostPosted: Thu Apr 06, 2006 7:03 am    Post subject: Re: TPanel derived class Paint problem Reply with quote

The speedbuttons' stay raised when moving the mouse within the panel
from button to button. They invalidate correctly when moving off of
the panel.

Recall that only the bottom and right edges stay raised, the top and
left edges lower as they should, and this only occurs when moving the
mouse leftward.

One thing I have noticed: if I don't override the PaintWindow method,
the buttons behave correctly, minus my custom drawing of course,
regardless of whether I override WndProc. If I override PaintWindow
but include a PaintWindow call after my custom drawing, the buttons
behave correctly but of course my drawing is negated.

For some reason, custom drawing appears to cause a problem for the
speedbuttons.

Kent
Back to top
JD
Guest





PostPosted: Thu Apr 06, 2006 3:03 pm    Post subject: Re: TPanel derived class Paint problem Reply with quote

"Kent" <kentav (AT) accessus (DOT) net> wrote:
Quote:

[...] For some reason, custom drawing appears to cause a
problem for the speedbuttons.

I do not see that behavior with the following. If you don't
find a solution in the sample, then you need to post your
entire class.

//-------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
new TMyPanel( this );
}
//-------------------------------------------------------------


//-------------------------------------------------------------
#ifndef Unit2H
#define Unit2H
//-------------------------------------------------------------
#include <Classes.hpp>
#include <Buttons.hpp>
//-------------------------------------------------------------
class TMyPanel : public TPanel
{
protected:
virtual void __fastcall PaintWindow(HDC DC);
virtual void __fastcall WndProc( TMessage &Message );
private:
typedef TPanel inherited;
public:
__fastcall TMyPanel( TComponent* Owner );
__fastcall ~TMyPanel();
__published:
};
//-------------------------------------------------------------
#endif

//-------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
#pragma package(smart_init)
//-------------------------------------------------------------
__fastcall TMyPanel::TMyPanel(TComponent* Owner) : TPanel( Owner )
{
Parent = dynamic_cast<TWinControl*>( Owner );
Left = 10;
Top = 10;
Width = 200;
Height = 200;
Color = clWhite;
for( int x = 0; x < 5; ++x )
{
TSpeedButton *pButton = new TSpeedButton( this );
pButton->Parent = this;
pButton->Left = 10 + (pButton->Width + 10) * x;
pButton->Top = 10;
pButton->Flat = true;
}
}
//-------------------------------------------------------------
__fastcall TMyPanel::~TMyPanel()
{
}
//-------------------------------------------------------------
void __fastcall TMyPanel::PaintWindow(HDC DC)
{
Canvas->FillRect( Rect(0,0,Width,Height) );
}
//-------------------------------------------------------------
void __fastcall TMyPanel::WndProc( TMessage &Message )
{
inherited::WndProc( Message );
}
//-------------------------------------------------------------

~ JD
Back to top
Kent
Guest





PostPosted: Thu Apr 06, 2006 11:03 pm    Post subject: Re: TPanel derived class Paint problem Reply with quote

It's working now. Many thanks.

Kent
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (VCL Components Usage) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.