Board index » cppbuilder » Derived component created using "new" get no attention

Derived component created using "new" get no attention


2005-06-17 10:21:23 AM
cppbuilder48
Hi,
I have created a sprite component for DirecDraw, which is derived from
TGraphicControl. In this control I added 2 messages which will correspond
with CM_MOUSEENTER and CM_MOUSELEAVE. ant it has 2 constructer:
//Constructor 1
//--------------------------------------
__fastcall TSprite(TComponent *Owner) //the default constructor created by
CBuilder
{
//added these to initialize for dropped component
lpddssrc = NULL; //LPDIRECTDRAWSURFACE, the source of image
lpddsdst = NULL; //same, but the pointer of the surface to draw it's
image
x = 0;
y = 0;
width = 0;
height = 0;
index = 0; //index of the image in the source image
frames = 0; //number of frames in the source image
}
//Constructor 2, the one I used to new the Component
//Basically what different is just I supply all the neccessory info at
//call of constructor
//------------------------------------
__fastcall TSprite(LPDDS source, LPDDS dest, int w, int h, TComponent
*Owner) //LPDDS = LPDIRECTDRAWSURFACE, redefined
{
x = 0;
y = 0; //the sprite will always start at these location
src = source;
dst = dest;
width = w;
height = h;
index = 0;
frames = 2; /*actually some calcualtion, lets say I have a source with 2
frames*/
}
so basically not much difference. Now the problem is, when I do:
TSprite *sprite = new TSprite(this); //with constructor 1
or
TSprite *sprite = new TSprite(source, dest, 32, 32, this);
these components will not detect the mouse entering r leaving themselves,
nor will they draw themselves. I have to explicitly call to Sprite->Paint()
to have them paint on screen. Half of the problem may be solved, but still
they will not detact mouse event. I have almost the same component, doing
all the same thing (mouse, and other event), except for the Paint() - they
paint to Canvas instead of a DirectDraw surface. Those TCanvas versions are
all working perfectly - for both Paint() and Mouse events.
To further investigate, I decide to drop this TSprite on the form directly
and supply the parameters manually (as in the way I use the Constructor 1
version) and this time, it works as planned! Well, at least half working -
this time, it will detact the Mouse event (entering and leaving) though I
still have to call to Sprite->Paint() explicitly. I'm okay with the calling
of Paint(), but why for the new'ed version is not detecting the mouse while
the dropped version will see the mouse??? I did set the Parent parameter of
the new'ed version to "this". Is there anything more that I need to do to
make a self-made component to recieve mouse messages?
Thanks in advance.
Regards.
 
 

Re:Derived component created using "new" get no attention

"Choykw" < XXXX@XXXXX.COM >wrote in message
Quote
it has 2 constructer:
Neither constructor is calling the base class TGraphicControl constructor.
You should be doing so, ie:
__fastcall TSprite::TSprite(TComponent *Owner)
: TGraphicControl(Owner) // <-- HERE
{
//...
}
__fastcall TSprite::TSprite(LPDDS source, LPDDS dest, int w, int h,
TComponent *Owner)
: TGraphicControl(Owner) // <-- HERE
{
//...
}
Quote
these components will not detect the mouse entering r leaving
themselves, nor will they draw themselves.
TGraphicControl is a visual component. Are you ever assigning the Parent
property anywhere? Without that, the component cannot be shown visually
onscreen, or react to any visual actions, such a mouse movements.
Quote
these components will not detect the mouse entering r leaving themselves,
nor will they draw themselves. I have to explicitly call to
Sprite->Paint()
to have them paint on screen.
<snip>
To further investigate, I decide to drop this TSprite on the form directly
and supply the parameters manually (as in the way I use the Constructor
1 version) and this time, it works as planned! Well, at least half
working -
this time, it will detact the Mouse event (entering and leaving) though I
still have to call to Sprite->Paint() explicitly.
You never have to, nor should you, ever call Paint() directly. Doing so
suggests that your component is fundamentaly flawed at its core. Please
show more of your code.
Quote
I'm okay with the calling of Paint()
You should not be ok with it, because you should not be having to do it in
the first place.
Quote
I did set the Parent parameter of the new'ed version to "this".
Where exactly?
Gambit
 

Re:Derived component created using "new" get no attention

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote

"Choykw" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

Neither constructor is calling the base class TGraphicControl constructor.
You should be doing so, ie:


__fastcall TSprite::TSprite(TComponent *Owner)
: TGraphicControl(Owner) // <-- HERE
{
//...
}

__fastcall TSprite::TSprite(LPDDS source, LPDDS dest, int w, int h,
TComponent *Owner)
: TGraphicControl(Owner) // <-- HERE
{
//...
}

oops! forgot to type those in. Yes, I did call the default constructor, else
the code will not compile.
Quote

TGraphicControl is a visual component. Are you ever assigning the Parent
property anywhere? Without that, the component cannot be shown visually
onscreen, or react to any visual actions, such a mouse movements.

I did. After I called the "new" to create the object.
Quote

You never have to, nor should you, ever call Paint() directly. Doing so
suggests that your component is fundamentaly flawed at its core. Please
show more of your code.
Okay, here they are :
the Sprite.cpp, as in dcluser.bpk:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Sprite.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TSprite *)
{
new TSprite(NULL);
}
//---------------------------------------------------------------------------
__fastcall TSprite::TSprite(TComponent* Owner)
: TGraphicControl(Owner)
{
src = NULL;
dst = NULL;
fwidth = 0;
fheight = 0;
fframes = 0;
findex = 0;
fswidth = 0;
fsheight = 0;
FMouseInControl = false;
}
//---------------------------------------------------------------------------
__fastcall TSprite::TSprite(lpDDs source, lpDDs dest, int w, int h,
TComponent *Owner)
: TGraphicControl(Owner)
{
src = source;
dst = dest;
fwidth = w;
fheight = h;
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
src->GetSurfaceDesc(&ddsd);
fswidth = ddsd.dwWidth;
fsheight = ddsd.dwHeight;
fframes = fswidth / fwidth;
findex = 0;
FMouseInControl = false;
}
//---------------------------------------------------------------------------
namespace Sprite
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TSprite)};
RegisterComponents("Standard", classes, 0);
}
}
//---------------------------------------------------------------------------
void __fastcall TSprite::CMMouseEnter(TMessage &Msg)
{
findex = 1;
FMouseInControl = true;
}
//---------------------------------------------------------------------------
void __fastcall TSprite::CMMouseLeave(TMessage &Msg)
{
findex = 0;
FMouseInControl = false;
}
//---------------------------------------------------------------------------
void __fastcall TSprite::Paint(void)
{
if(src != NULL && dst != NULL)
{
TRect r = Rect(findex * fwidth, 0, (findex + 1) * fwidth, fheight);
//Here I assume all the source images are in a 1xN image strip (N is
the number
//of frames), I might add support for multiple rows, but not now.
dst->BltFast(fx, fy, src, &r, DDBLTFAST_WAIT |
DDBLTFAST_SRCCOLORKEY);
}
}
//---------------------------------------------------------------------------
the Sprite.h for the cpp above:
//---------------------------------------------------------------------------
#ifndef SpriteH
#define SpriteH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <Controls.hpp>
#include <ddraw.h>
#include <ddutil.h>
#define lpDDs LPDIRECTDRAWSURFACE
//---------------------------------------------------------------------------
class PACKAGE TSprite : public TGraphicControl
{
private:
MESSAGE void __fastcall CMMouseEnter(TMessage &Msg);
MESSAGE void __fastcall CMMouseLeave(TMessage &Msg);
protected:
public:
__fastcall TSprite(TComponent* Owner);
__fastcall TSprite(lpDDs source, lpDDs dest, int w, int h, TComponent
*Owner);
bool FMouseInControl;
lpDDs src, dst;
int fx, fy, fwidth, fheight, fframes, findex, fswidth, fsheight;
void __fastcall Paint(void);
__published:
__property int x={read=fx, write=fx};
__property int y={read=fy, write=fy};
__property int spwidth={read=fwidth, write=fwidth};
__property int spheight={read=fheight, write=fheight};
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGraphicControl)
};
//---------------------------------------------------------------------------
#endif
note that the above component is not finished. I only added the Mouse Enter
and Mouse Leave detection and the Paint(), just enough for testing to see if
it is working.
Quote
You should not be ok with it, because you should not be having to do it in
the first place.

>I did set the Parent parameter of the new'ed version to "this".

Where exactly?
in my test app code, after I "new" the TSprite.
void __fastcall TForm1::Button1Click(TObject *Sender)//start the app in
DirectDraw mode
{
initDD(); //init the DirectDraw to 640x480x16,
//double buffered
//sprite1 is the "dropped" version of the component,
//i.e. design time version dropped as a visual
//component on the form
sprite1->src = lpddspot;
sprite1->dst = lpddsback;
//sprite is the runtime version, using "new"
sprite = new TSprite(this);
sprite->Parent = this;
sprite->src = lpddspot;
sprite->dst = lpddsback;
sprite->fwidth = 32;
sprite->fheight = 32;
sprite->fx = 320;
sprite->fy = 240;
Timer1->Enabled = true; //to update and flip the screen buffer
Button1->Visible = false;
Form1->SetFocus();
ready = true; //tells the updater that it weather it should update,
//to prevent AV due to lpDDs are NULL
}
Quote


Gambit


and after careful thoughts, I might not want to have a component that paint
itself, I'd rather want a component that only paints itself when I want it
to, when I'm updating the application in the loop (think a game loop: Read
input->process/update->render screen->flip->repeat loop). I'm not sure how
is the default behavior of Paint(), but I do not want it to paint itself
when the destination surface is locked or is updating by other screen
elements, nor would I want to have a screen element that will not paint
itself (it think it is not neccessory to paint) when I want it to paint. Is
there a way to achieve this? (rather than relying on the Paint() which I
could not decide when it will activate)
Thanks.
Regards.
 

{smallsort}

Re:Derived component created using "new" get no attention

Any help?
"Choykw" < XXXX@XXXXX.COM >wrote in message
Quote

<snipped>
 

Re:Derived component created using "new" get no attention

please?
"Choykw" < XXXX@XXXXX.COM >wrote in message
Quote
Any help?


"Choykw" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...
>
<snipped>

 

Re:Derived component created using "new" get no attention

"Choykw" < XXXX@XXXXX.COM >wrote in message
Quote
void __fastcall TSprite::CMMouseEnter(TMessage &Msg)
<snip>
void __fastcall TSprite::CMMouseLeave(TMessage &Msg)
<snip>
Neither of those are calling the base class Dispatch() method to pass on the
messages for default handling.
Quote
void __fastcall Paint(void);
Paint() should be declared as 'protected', not 'public'.
Quote
BEGIN_MESSAGE_MAP
A MESSAGE_MAP should be declared as 'public', not '__published'.
Quote
//sprite is the runtime version, using "new"
sprite = new TSprite(this);
sprite->Parent = this;
sprite->src = lpddspot;
<snip>
Why declare a second contructor if you don't actually use it?
Quote
and after careful thoughts, I might not want to have a component
that paint itself, I'd rather want a component that only paints itself
when I want it to
Then you should be drawing to an in-memory bitmap instead and display the
bitmap when needed. That is how typical double-buffered systems work,
especially when animation and such is involved.
Gambit
 

Re:Derived component created using "new" get no attention

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote

"Choykw" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

>void __fastcall TSprite::CMMouseEnter(TMessage &Msg)
<snip>
>void __fastcall TSprite::CMMouseLeave(TMessage &Msg)
<snip>

Neither of those are calling the base class Dispatch() method to pass on
the
messages for default handling.

I was following the example in the book "C++ Builder 6 Developer Guide" from
SAMS publishing...Seems like I've yet again wasted my money on poorly
written books. The examples there never mentioned about Dispatch() method.
Strange is I've used almost identical codes to make another "Icon" type of
component (it has a graphic and a text label), the only difference is this
TSprite is drwing on a DirectDraw Surface while the TMultiIcon (thats what I
called the other one) is drawing to a TCanvas. The TMultiIcon is working
fine, it draws correctly, react to Mouse event correctly.
Quote
>void __fastcall Paint(void);

Paint() should be declared as 'protected', not 'public'.
It was originally protected, but since it is not drawing correctly, I moved
it to public so that I can call it in my test application.
Quote

>BEGIN_MESSAGE_MAP

A MESSAGE_MAP should be declared as 'public', not '__published'.
okay, this one got me there. The book DID put it in the __published area.
Sigh...guessed I should only buy books from Borland from now on.
Quote

>//sprite is the runtime version, using "new"
>sprite = new TSprite(this);
>sprite->Parent = this;
>sprite->src = lpddspot;
<snip>

Why declare a second contructor if you don't actually use it?
I used both constructors in different cases. The one with only an Owner as
parameter is used when the component is dropped on the form, to avoid Access
Violation, since I haven't created the LPDIRECTDRAWSURFACEs at design time.
The second constructor is for design time creation of the component via
"new" operator. I couldn't rely on the design time constructor since I
couldn't predict any of my apps will need how many of these TSprites and
drop them at design time (well, actually I could, but that will impose
limitations on how many TSprites I could have in an app, and also waste
resource if i actually need less of them - my target machines are P200 with
32 MB RAM)
Quote

>and after careful thoughts, I might not want to have a component
>that paint itself, I'd rather want a component that only paints itself
>when I want it to

Then you should be drawing to an in-memory bitmap instead and display the
bitmap when needed. That is how typical double-buffered systems work,
especially when animation and such is involved.
Yes. I'm doing that, I paint to the offscreen buffer.
Thanks for your reply, I'll try to find out how the Dispatch() method works.
Quote


Gambit


 

Re:Derived component created using "new" get no attention

"Choykw" < XXXX@XXXXX.COM >wrote in message
Quote

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
news:42b70814$ XXXX@XXXXX.COM ...
>
>"Choykw" < XXXX@XXXXX.COM >wrote in message
>news: XXXX@XXXXX.COM ...
>
>>void __fastcall TSprite::CMMouseEnter(TMessage &Msg)
><snip>
>>void __fastcall TSprite::CMMouseLeave(TMessage &Msg)
><snip>
>
>Neither of those are calling the base class Dispatch() method to pass on
>the
>messages for default handling.
>

I was following the example in the book "C++ Builder 6 Developer Guide"
from SAMS publishing...Seems like I've yet again wasted my money on poorly
written books. The examples there never mentioned about Dispatch() method.
Strange is I've used almost identical codes to make another "Icon" type of
component (it has a graphic and a text label), the only difference is this
TSprite is drwing on a DirectDraw Surface while the TMultiIcon (thats what
I called the other one) is drawing to a TCanvas. The TMultiIcon is working
fine, it draws correctly, react to Mouse event correctly.



Okay, I made another mistake here, I missed out the Invalidate() in both
CMMouseEnter() and CMMouseLeave(). Now I solved the Paint() problem, though
as I expected, the way of letting the control painting itself is not what I
want. It paints before my test app draw to the back buffer, and when the app
is updating the back buffer, the first thing it does is blank the whole
buffer - so erasing the image of the component.
So, now what I need is a non-visual component that have mouse event...any
suggestion what should I base my component on? TControl?
Thanks in advance.
 

Re:Derived component created using "new" get no attention

"Choykw" < XXXX@XXXXX.COM >wrote in message
Quote
I was following the example in the book "C++ Builder 6 Developer Guide"
from SAMS publishing...Seems like I've yet again wasted my money on
poorly written books. The examples there never mentioned about Dispatch()
method.
A MESSAGE_MAP is a series of precompiler macros that override the virtual
Dispatch() method. Unless you are going to swallow the messages, you should
pass them on to the base class's Dispatch() for default handling.
Quote
Strange is I've used almost identical codes to make another "Icon" type
of component (it has a graphic and a text label), the only difference is
this
TSprite is drwing on a DirectDraw Surface while the TMultiIcon (thats
what I called the other one) is drawing to a TCanvas. The TMultiIcon is
working fine, it draws correctly, react to Mouse event correctly.
If all you are doing is changing where the drawing is directed to, and
nothing else has changed, then there should be no reason why the TSprite
would not work as well. If you give TMultiIcon a DD surface, and make no
other changes, does it still work?
Quote
>Paint() should be declared as 'protected', not 'public'.

It was originally protected, but since it is not drawing correctly,
I moved it to public so that I can call it in my test application.
Move it back to 'protected'. You are not supposed to be calling it directly
at all.
Gabit
 

Re:Derived component created using "new" get no attention

"Choykw" < XXXX@XXXXX.COM >wrote in message
Quote
as I expected, the way of letting the control painting itself is not
what I want.
What EXACTLY do you want? Please be more specific.
Quote
It paints before my test app draw to the back buffer, and when
the app is updating the back buffer, the first thing it does is blank
the whole buffer - so erasing the image of the component.
Do all of your main drawing to a bitmap, and have Paint() draw whatever is
currently in the bitmap. What are you having troubles with?
Quote
So, now what I need is a non-visual component that have mouse event...
There is no such thing. The mouse is a visual device. It only works with
visual controls.
Gambit