MFC: A subclass of a subclass of CDialog

MFC: A subclass of a subclass of CDialog

Post by Zapana » Tue, 01 Jan 2008 13:02:25



I am building an app with two MFC classes descended from CDialog.

Probably by the end of it, I am going to have 5 or 6 CDialogs (in a
tabbed window). I have spent quite some time adding custom painting
to the first of them. All of them, in the end, are going to have this
same custom painting going on.

The thing to do then would be to make an intermediate class, MyDialog,
descended from CDialog, with the custom painting in the OnPaint()
method, then derive the 5 or 6 dialogs from that, so I am not
repeating and maintaining the custom painting code in all of my
dialogs.

Theoretically this is very simple ... I create a class MyDialog, then
change the parent class of my dialogs from CDialog to MyDialog, then
transfer the custom OnPaint() method from the dialogs to MyDialog, so
the children all inherit it.

But this doesn't seem to work in a project built on MFC. I tried
creating MyDialog by hand. I've been programming in C++ for years,
this part is simple enough. The CDialog constructor stymies me a
little ... the auto-generated version calls the parent with
CDialog(AppDialog1::IDD, pParent), where IDD is an enum generated with
the resource ID of the dialog. If I'm doing it by hand, I don't have
this, so I try the alternate constructor, CDialog(). This compiles,
but I don't know if this is going to be a problem.

Then I try to change AppDialog1 to subclass from MyDialog. So the
only change is I change the superclass from CDialog to MyDialog.

Now it doesn't compile, I get "error C2143: syntax error : missing ';'
before 'constant'", the error is in the header file at this line:
"class AppDialog1.1 : public MyDialog". I renamed AppDialog1 to
AppDialog1.1 so I could work on it without messing up AppDialog1,
which works ... is an x.x naming convention a problem?

So I have no idea what that means.

So I try creating MyDialog in the visual builder. It gives me a
warning because I am not building it from a visually-created class, so
it won't have an ID. Well I can't see a way around that, so OK.

When I try to compile it, I get an error (more or less predictably)
because in the enum, IDD is defined as "UNKNOWN ID" or something, so
again I change the constructor from CDialog(MyDialog::IDD, pParent) to
CDialog().

Now it compiles OK. So I try to create a subclass, AppDialog1.1,
which descends from MyDialog

Again I get the same error:

"error C2143: syntax error : missing ';' before 'constant'"

And again I have no idea what exactly that is supposed to mean.

Is this just impossible? Can I not mix my own classes with MFC
classes this way?

I am wondering if anybody has done something similar. The errors are,
as far as I can guess, happening in macros or something that are
generated by MFC. It is basically impossible to debug these.

Maybe if I build AppDialog1.1 in the visual builder ... but then it
won't allow me to choose a base class of my own, only from the MFC
classes. Another dead end.



--
Joe Cosby
http://www.yqcomputer.com/
It is difficult to produce a television documentary that is both incisive and probing when every twelve minutes one is interrupted by twelve dancing rabbits singing about toilet paper.
- Rod Serling

:: Currently listening to Poor Poor Pitiful Me, 1978, by Warren Zevon, from "Warren Zevon"
 
 
 

MFC: A subclass of a subclass of CDialog

Post by Doug Harri » Tue, 01 Jan 2008 14:17:39

n Sun, 30 Dec 2007 20:02:25 -0800, Zapanaz
<http://joecosby.com/code/mail.pl> wrote:


You should simply chain to the CDialog(ID, parent) ctor. The intermediate
base class won't have an ID of its own; instead, the derived class will
supply it.


Yes, it's a problem. The dot is not a legal character for identifiers. The
only non-alphanumeric character you can use is the underscore. Just don't
begin identifiers with the underscore or use two of them in a row, because
such names are reserved.


Don't do that.


Of course you can!


I believe you've described the hierarchy:

CDialog <- SubDlgBase <- SubDlg1, SubDlg2, SubDlg3, ...

Like CDialog, the SubDlgBase class will not have an IDD enum member, but
the derived classes, SubDlg1, SubDlg2, etc, will, because they are
associated with dialog resources. Your SubDlgBase class should define a
ctor SubDlgBase(UINT id, CWnd* parent) that chains to the corresponding
CDialog ctor. You should be able to set this up in ClassWizard such that
SubDlgBase and the derived subdialogs are all available there. It's been a
long time since I did this, but IIRC, after creating SubDlgBase, you will
delete its IDD member and the dialog template ClassWizard created for it.
Then you will modify its ctor as I described earlier. What you are trying
to do is definitely possible, and it works with full ClassWizard support
for the created classes. At least that was the case in VC6, which is where
I did it.

P.S. The best group for this question would have been
microsoft.public.vc.mfc.

--
Doug Harrison
Visual C++ MVP

 
 
 

MFC: A subclass of a subclass of CDialog

Post by Zapana » Tue, 01 Jan 2008 16:35:00

I am creating multiple CDialog's and have custom painting that they
all do the same ... so, I am trying to create a class SubDlgBase which
has all the painting in it, then descend my SubDlg's from it.

I can't figure out how to create a visual component which is a
subclass of my own class, which is descended from CDialog.

On Sun, 30 Dec 2007 23:17:39 -0600, "Doug Harrison [MVP]"
< XXXX@XXXXX.COM > wrote:


Thanks very much for the help.

It turns out the dot in the class name was the source of most of my
problems. I guess I've just never run into that before, never tried
to use a dot in a class name before ...

***

It's still kind of a hassle, but nothing I can't work around (well,
hopefully). The visual builder only allows you to subclass from an
MFC class, or choose an existing class from among classes you have
already defined by subclassing them from MFC classes (MSVC++ 6). So
the only way I can see to do it is

1. Create SubDlgBase from CDialog in the visual builder
2. Create SubDlg1 from CDialog
3. Manually edit SubDlg1 to descend from SubDlgBase
4. Copy all the visual components (text boxes, buttons, etc) from the
already-existing visual classes into the new classes
5. Copy all the existing code likewise
6. Cross fingers

But I can't just modify my existing SubDlg1 to subclass from
SubDlgBase, because the visual class is descended from CDialog, so
even if I change SubDlg1 in my code to descend from SubDlgBase, when I
build and execute it still behaves as a subclass of CDialog, not
SubDlgBase.

Oh, crap.

Now that I actually type this out ... this isn't going to work.
Whatever I do, in the visual builder, I will have the choice to either
descend from an MFC class, or instantiate one of my own classes. And
all of those classes are likewise descended one step from MFC classes.

I mean in the Class Wizard, you have the choice of:

- Create a New Class ... which lets you subclass from an existing
class ... but which only gives you MFC classes as options
- Select an existing class ... which lets you choose from your own
classes, but only to instantiate them, not to subclass them

argh. Maybe, tomorrow, if like I say I manually edit SubDlg1 to
descend from SubDlgBase, instead of CDialog as it is now, it will be
fooled into letting me instantiate it. (Currently I do have the
choice to instantiate a SubDlg1, but it's descended from CDialog
instead of SubDlgBase). But I think I am going to still have the same
problem ... since the visual component was originally descended from
CDialog, I think it is going to do the same thing and continue
behaving as a subclass of CDialog, not SubDlgBase.

Well really in retrospect, I have spent a lot more time working around
the time-saving visual builder than I would have I had done this all
in code from the start.




--
Joe Cosby
http://joecosby.com/
The Church of the SubGenius - oh, what a jackboot in the face it is!

:: Currently listening to Tits And Ass, by Lenny Bruce
 
 
 

MFC: A subclass of a subclass of CDialog

Post by Norbert Un » Tue, 01 Jan 2008 18:00:50


Zapanaz schrieb:

No problem, I've done it multiple times.


That part is easy. Derive your dialogs from CDialog, let the wizard generate the
code, and then change the base class from CDialog to SubDlgBase. The trick is to
do this in all three(?) places, not only in the class declaration. The best is
you use search&replace on both the cpp and h file to do this. If I remember, the
base class name appears
* In the class declaration (class MySub1 : public CDialog)
* At the top of the class implementation in
IMPLEMENT_DYNAMIC(MySub1, CDialog)
* In the message map definition BEGIN_MESSAGE_MAP(MySub1, CDialog).

(tis is ftom my memory, forgive me if I got a name wrong)

See below for more comments

ok

ok

Yes, but replace all three or forut ocurences of CDialog with SubDlgBase, not
only the one in the header file.

> 5. Copy all the existing code likewise
When you already have the code in some classes, why create new classes and cop
the old code to it?


You forgot to manipulate the constructor of SubDlgBase as Doug told you.
Carefully read his reply again.


That is not true. Virtual functions work perfectly fine through many levels of
hierarchy.
However, most message handlers in MFC are not implemented with virtual
functions, but by "manual" message lookup with the help of the message mapping
macros. I guess you forgot to copy the message map entries to the correct class.
When you forget that, the code compiles but the hanlders are not called.

In addition, when you implement OnPaint in the base dialog, the derived dialogs
can not have a OnPaint as well, you can only have one OnPaint. If the derived
dialogs should do some custom painting, then you would need to add some OnDraw
virtual function in your base and override it in the deriveed. The base OnPaint
would then call the overloaded OnDraw at some time during its OnPaint handling.


No, it is easy. Just replace the base class name in all places, and update the
base constructor.



Yes, but to change this after class creation is easy, see above.


Well, it is harder to setup the message mapping right in the first try, so I
still prefer the class wizard thing. In addition, even after you changed the
base, you can still add new metthods using class wizard.

Norbert
 
 
 

MFC: A subclass of a subclass of CDialog

Post by Zapana » Wed, 02 Jan 2008 07:49:38


On Mon, 31 Dec 2007 10:00:50 +0100, Norbert Unterberg



That was the problem, I replaced CDialog with SubDlgBase in the
constructor but not in the message maps.

Thanks very much for your help, this is working now. And thanks for
your patience, by the time I get to the point where I have to ask a
question I am usually fairly frustrated and my posts get a little
wild.

For OnPaint, because all the custom painting is in the superclass, I
created a non-MFC-message function SuperPaint() and pass a pointer to
the window which received the OnPaint() message to it and get the
device context from that, which works.


--
Joe Cosby
http://www.yqcomputer.com/
If a Bob is pipeless, long-haired, non-Slack-emitting, quoteless, and
not trying to sell anything, we hardly consider that a proper "Bob."

:: Currently listening to Come On, Come over, 1976, by Jaco Pastorius, from "Jaco Pastorius"