 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Kent Guest
|
Posted: Mon Apr 03, 2006 6:03 am Post subject: TPanel derived class Paint problem |
|
|
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
|
Posted: Mon Apr 03, 2006 6:03 pm Post subject: Re: TPanel derived class Paint problem |
|
|
"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
|
Posted: Tue Apr 04, 2006 3:03 am Post subject: Re: TPanel derived class Paint problem |
|
|
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
|
Posted: Tue Apr 04, 2006 3:03 am Post subject: Re: TPanel derived class Paint problem |
|
|
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
|
Posted: Tue Apr 04, 2006 6:03 am Post subject: Re: TPanel derived class Paint problem |
|
|
"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
|
Posted: Tue Apr 04, 2006 6:03 am Post subject: Re: TPanel derived class Paint problem |
|
|
| 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
|
Posted: Tue Apr 04, 2006 9:03 am Post subject: Re: TPanel derived class Paint problem |
|
|
"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 ).
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
|
Posted: Wed Apr 05, 2006 5:03 am Post subject: Re: TPanel derived class Paint problem |
|
|
| 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
|
Posted: Wed Apr 05, 2006 10:03 am Post subject: Re: TPanel derived class Paint problem |
|
|
"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
|
Posted: Thu Apr 06, 2006 7:03 am Post subject: Re: TPanel derived class Paint problem |
|
|
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
|
Posted: Thu Apr 06, 2006 3:03 pm Post subject: Re: TPanel derived class Paint problem |
|
|
"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
|
Posted: Thu Apr 06, 2006 11:03 pm Post subject: Re: TPanel derived class Paint problem |
|
|
It's working now. Many thanks.
Kent |
|
| Back to top |
|
 |
|
|
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
|
|