Board index » cppbuilder » What can be the reason, when method CreateWnd() not being called?

What can be the reason, when method CreateWnd() not being called?


2007-07-15 02:05:15 PM
cppbuilder43
What can be the reason, when method CreateWnd() not being called?
Running through the internet, I found a TButton-extention-component,
being able to change one's TButtons color.
Each of them work fine separated...
Also I found a TButton-extention-component being able to allow a
button to have more multi-line text.
And both have included source
So I tried to combine these two into one component TMyButton, also for
an exercise...
The result was that the multi-line feature was gone. The property is
shown in the object-inspector, but not more than one line is
displayed.
Diving a little deeper I found out that the overriden methode
TMyButton::CreateWnd() is not being called. So I suspect the first
extention (colored buttons) interfers with this.
Can it be it has to do with the messages it handles by itself? The
messages it handles are: ENABLEDCHANGED, FONTCHANGED,MEASUREITEM and
DRAWITEM. I inserted in each associated methode a
inherited::Dispatch((void *)&Message);
if it was not already, but the result was the same: No call of
CreateWnd().
Might this be nevertheless the reason or what can the problem be (and
how to overcome this)? From where CreateWnd() is called directly or
indirectly (by throwing a message)?
Thanks a lot,
Michael
 
 

Re:What can be the reason, when method CreateWnd() not being called?

OOps, sorry!
Wrong newsgroup.
I repost it in borland.public.cppbuilder.vcl.components.writing
Thanks,
Michael
 

Re:What can be the reason, when method CreateWnd() not being called?

Checking the stack at a breakpoint on CreateWnd() on the correct
working multi-line-button, it is
CreateWnd
TWinControl@CreateHandle
TWinControl@UpdateShowing
TWinControl@UpdateControlState
TWinControl@CMVisibleChanged
vcl100.bpl
...
, so my original question perhaps might be reduced to
What can be the reason, when message CMVisibleChanged is not
thrown?
Thanks,
Michael
 

{smallsort}

Re:What can be the reason, when method CreateWnd() not being called?

<MR>wrote in message news: XXXX@XXXXX.COM ...
Quote
What can be the reason, when method CreateWnd() not being called?
Because you did not override it correctly. Or you are not doing anything
that requires the Handle to be allocated in the first place.
Quote
So I tried to combine these two into one component TMyButton,
also for an exercise...
Then you likely did not merge then correctly. Please show the actual code.
Gambit
 

Re:What can be the reason, when method CreateWnd() not being called?

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >schrieb:
Remy, thanks of your answers.
Quote

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

>What can be the reason, when method CreateWnd() not being called?

Because you did not override it correctly. Or you are not doing anything
that requires the Handle to be allocated in the first place.
>So I tried to combine these two into one component TMyButton,
>also for an exercise...

Then you likely did not merge then correctly. Please show the actual code.
Here is the header-file. I'm not sure if I'm allowed to publish the
.cpp-file here (copyright-reasons of the original delphi-authors, even
if the Delphi-source-code is available in the net), but I suppose it
is not really necessary, because there is no error occuring in
CreateWin, it is just not being called.
But I suppose it would be ok, to send it directly per Email, if you
want this.
// From TColorButton
// ->delphi.about.com/library/code/ncaa061104a.htm
// From TMultiLineButton
// ->
//---------------------------------------------------------------------------
#ifndef TMRButtonH
#define TMRButtonH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <SysUtils.hpp>
//---------------------------------------------------------------------------
class PACKAGE TMRButton : public TButton
{
public:
__fastcall TMRButton(TComponent* Owner);
__fastcall ~TMRButton();
void __fastcall CreateParams(TCreateParams &Params);
void __fastcall CreateWnd(void);
void __fastcall WndProc(TMessage &Message);
// MultiLineButton
private:
typedef TButton inherited;
bool FMultiLine;
public:
void __fastcall TMRButton_MultiLineButton__Constructor(TComponent*
Owner);
void __fastcall TMRButton_MultiLineButton__Destructor();
private:
void __fastcall SetMultiLine(bool _is_multi_line) {
FMultiLine=_is_multi_line;
}
protected:
void __fastcall TMRButton_MultiLineButton__CreateWnd(void);
__published:
__property bool MultiLine={read=FMultiLine, write=SetMultiLine};
// ColorButton
private:
TColor FBackBeforeHoverColor;
TCanvas *FCanvas;
bool IsFocused;
TColor FBackColor;
TColor FForeColor;
TColor FHoverColor;
public:
void __fastcall TMRButton_ColorButton__Constructor(TComponent*
Owner);
void __fastcall TMRButton_ColorButton__Destructor();
private:
void __fastcall SetBackColor(const TColor Value);
void __fastcall SetForeColor(const TColor Value);
void __fastcall SetHoverColor(const TColor Value);
__property TColor BackBeforeHoverColor={read=FBackBeforeHoverColor,
write=FBackBeforeHoverColor};
protected:
void __fastcall TMRButton_ColorButton__CreateParams(TCreateParams
&Params);
void __fastcall TMRButton_ColorButton__WndProc(TMessage &Message);
void __fastcall SetButtonStyle(bool Value);
void __fastcall DrawButton(TRect Rect, unsigned State);
// procedure CMEnabledChanged(var Message: TMessage); message
CM_ENABLEDCHANGED;
MESSAGE void __fastcall CMEnabledChanged(TMessage &Msg);
// procedure CMFontChanged(var Message: TMessage); message
CM_FONTCHANGED;
MESSAGE void __fastcall CMFontChanged(TMessage &Msg);
// procedure CNMeasureItem(var Message: TWMMeasureItem); message
CN_MEASUREITEM;
MESSAGE void __fastcall CNMeasureItem(TWMMeasureItem &Msg);
// procedure CNDrawItem(var Message: TWMDrawItem); message
CN_DRAWITEM;
MESSAGE void __fastcall CNDrawItem(TWMDrawItem &Msg);
//
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_ENABLEDCHANGED, TMessage, CMEnabledChanged)
MESSAGE_HANDLER(CM_FONTCHANGED, TMessage, CMFontChanged)
MESSAGE_HANDLER(CN_MEASUREITEM, TWMMeasureItem, CNMeasureItem)
MESSAGE_HANDLER(CN_DRAWITEM, TWMDrawItem, CNDrawItem)
// END_MESSAGE_MAP(TMRButton) // =>Stack overflow...
END_MESSAGE_MAP(inherited)
__published:
__property TColor BackColor={read=FBackColor, write=SetBackColor,
default=clBtnFace};
__property TColor ForeColor={read=FForeColor, write=SetForeColor,
default=clBtnText};
__property TColor HoverColor={read=FHoverColor, write=SetHoverColor,
default=clBtnFace};
};
//---------------------------------------------------------------------------
#endif
Thank you,
Michael
 

Re:What can be the reason, when method CreateWnd() not being called?

<MR>wrote in message news: XXXX@XXXXX.COM ...
Quote
I'm not sure if I'm allowed to publish the .cpp-file here
(copyright-reasons of the original delphi-authors, even
if the Delphi-source-code is available in the net), but I
suppose it is not really necessary, because there is no
error occuring in CreateWin, it is just not being called.
Not having your actual source code handy makes it very difficult to diagnose
your problem.
Quote
void __fastcall CreateParams(TCreateParams &Params);
void __fastcall CreateWnd(void);
void __fastcall WndProc(TMessage &Message);
Those methods are originally declared to be "protected". They should not be
declared in the "public" section.
Also, TButton already overrides those methods, so make sure that your
overriden methods call TButton's methods when needed.
Quote
void __fastcall TMRButton_MultiLineButton__Constructor(TComponent*
Owner);
void __fastcall TMRButton_MultiLineButton__Destructor();
Get rid of those. They don't belong in your component. You are already
overriding the actual constructor and destructor. Do the work in there.
Quote
void __fastcall SetMultiLine(bool _is_multi_line)
That setter method should be refreshing the button display.
Quote
void __fastcall TMRButton_MultiLineButton__CreateWnd(void);
Use the CreateWnd() that you have already overriden.
Quote
void __fastcall TMRButton_ColorButton__Constructor(TComponent*
Owner);
void __fastcall TMRButton_ColorButton__Destructor();
Again, get rid of those and do the work in the main constructor/destructor
directly.
Quote
void __fastcall TMRButton_ColorButton__CreateParams(TCreateParams
&Params);
void __fastcall TMRButton_ColorButton__WndProc(TMessage &Message);
And those.
Quote
void __fastcall DrawButton(TRect Rect, unsigned State);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_ENABLEDCHANGED, TMessage, CMEnabledChanged)
MESSAGE_HANDLER(CM_FONTCHANGED, TMessage, CMFontChanged)
MESSAGE_HANDLER(CN_MEASUREITEM, TWMMeasureItem, CNMeasureItem)
MESSAGE_HANDLER(CN_DRAWITEM, TWMDrawItem, CNDrawItem)
// END_MESSAGE_MAP(TMRButton) // =>Stack overflow...
END_MESSAGE_MAP(inherited)
Make sure all of those messages handlers are calling the ones inherited from
TButton.
Gambit
 

Re:What can be the reason, when method CreateWnd() not being called?

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

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

>void __fastcall CreateParams(TCreateParams &Params);
>void __fastcall CreateWnd(void);
>void __fastcall WndProc(TMessage &Message);

Those methods are originally declared to be "protected". They should not be
declared in the "public" section.
Ok, done.
Quote
>void __fastcall SetMultiLine(bool _is_multi_line)

That setter method should be refreshing the button display.
Ok. For testing I inserted the code being in CreateWnd() into the
setter method:
if(FMultiLine)
SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle,
GWL_STYLE)|BS_MULTILINE);
else
SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle,
GWL_STYLE)&~BS_MULTILINE);
But it did not change anything: when the button-text exceeds the
button's Width, there appears no second line.
Quote
Also, TButton already overrides those methods, so make sure that your
overriden methods call TButton's methods when needed.
>void __fastcall TMRButton_MultiLineButton__Constructor(TComponent*
>Owner);
>void __fastcall TMRButton_MultiLineButton__Destructor();

Get rid of those. They don't belong in your component. You are already
overriding the actual constructor and destructor. Do the work in there.


>void __fastcall TMRButton_MultiLineButton__CreateWnd(void);

Use the CreateWnd() that you have already overriden.

>void __fastcall TMRButton_ColorButton__Constructor(TComponent*
>Owner);
>void __fastcall TMRButton_ColorButton__Destructor();

Again, get rid of those and do the work in the main constructor/destructor
directly.

>void __fastcall TMRButton_ColorButton__CreateParams(TCreateParams
>&Params);
>void __fastcall TMRButton_ColorButton__WndProc(TMessage &Message);

And those.
Originally I mixed all these code up - like you propse - into one
function. but than I thought it would be better to have separate
functions, so it's easier to see which function is associated with
which feature. Ok, in this very moment there are only two features
(multiline and color), but perhaps later there might be more...
Might a mixing it together (like you propose) makes it more probable
that CreateWnd is being called? I don't think so.
Quote
>void __fastcall DrawButton(TRect Rect, unsigned State);

>BEGIN_MESSAGE_MAP
>MESSAGE_HANDLER(CM_ENABLEDCHANGED, TMessage, CMEnabledChanged)
>MESSAGE_HANDLER(CM_FONTCHANGED, TMessage, CMFontChanged)
>MESSAGE_HANDLER(CN_MEASUREITEM, TWMMeasureItem, CNMeasureItem)
>MESSAGE_HANDLER(CN_DRAWITEM, TWMDrawItem, CNDrawItem)
>// END_MESSAGE_MAP(TMRButton) // =>Stack overflow...
>END_MESSAGE_MAP(inherited)

Make sure all of those messages handlers are calling the ones inherited from
TButton.
I did: I called inherited::Dispatch() from all these event-functions,
e.g.
MESSAGE void __fastcall TMRButton::CNMeasureItem(TWMMeasureItem
&Message)
{
Message.MeasureItemStruct->itemWidth=Width;
Message.MeasureItemStruct->itemHeight=Height;
inherited::Dispatch((void *)&Message);
}
Quote
>I'm not sure if I'm allowed to publish the .cpp-file here
>(copyright-reasons of the original delphi-authors, even
>if the Delphi-source-code is available in the net), but I
>suppose it is not really necessary, because there is no
>error occuring in CreateWin, it is just not being called.

Not having your actual source code handy makes it very difficult to diagnose
your problem.
Can I mail it to you directly?
Thanks,
Michael
 

Re:What can be the reason, when method CreateWnd() not being called?

<MR>wrote:
Quote

>Not having your actual source code handy makes it very
>difficult to diagnose your problem.

Can I mail it to you directly?
Zip it up and post it in the Attachments group.
~ JD
 

Re:What can be the reason, when method CreateWnd() not being called?

<MR>wrote in message news: XXXX@XXXXX.COM ...
Quote
Ok. For testing I inserted the code being in CreateWnd()
into the setter method:
That is not the correct thing to do. Call the RecreateWnd() method instead,
ie:
void __fastcall SetMultiLine(bool _is_multi_line)
{
if( FMultiLine != _is_multi_line )
{
FMultiLine = _is_multi_line;
RecreateWnd();
}
}
Gambit
 

Re:What can be the reason, when method CreateWnd() not being called?

Ok,
I just did...
Michael
 

Re:What can be the reason, when method CreateWnd() not being called?

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

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

>Ok. For testing I inserted the code being in CreateWnd()
>into the setter method:

That is not the correct thing to do. Call the RecreateWnd() method instead,
ie:

void __fastcall SetMultiLine(bool _is_multi_line)
{
if( FMultiLine != _is_multi_line )
{
FMultiLine = _is_multi_line;
RecreateWnd();
}
}


Gambit
I tried it, but it did not change the multi-line behaviour...
I just published the complete source-code into the
'Attachments'-group.
Thank you,
Michael
 

Re:What can be the reason, when method CreateWnd() not being called?

<MR>wrote:
Quote

The logic of the two buttons are imcompatable with each other.
The color button relies on a Style that includes BS_OWNERDRAW
which requires you to paint the button and the multi-line
Button relies on a Style that includes BS_MULTILINE which
utilizes default drawing.
To get both effects, use just the color button sample and add
some code to it's DrawButton method. Locate the call to the
win32 API DrawText. You need to wrap that call in an if-block:
else
{
TRect R = Rect;
::DrawText( FCanvas->Handle, Caption.c_str(), -1, &R, DT_CALCRECT | DT_WORDBREAK | DT_CENTER );
// now you need code here to adjust R so that it's
// centered on the button face
::DrawText( FCanvas->Handle, Caption.c_str(), -1, &R, DT_WORDBREAK | DT_CENTER | DT_VCENTER ); // <-- note that I changed the flags
}
In addition, prior to BDS, CM_MOUSELEAVE is unreliable
so the WndProc needs to be changed as well. Look here
for more:
newsgroups.borland.com/cgi-bin/dnewsweb&utag=
~ JD