Link to home
Start Free TrialLog in
Avatar of dpitman
dpitman

asked on

Inheritence using CDialog/CPropertyPage Based Classes

Hello everyone,
I need some fairly urgent help with an application I
am doing in VC++ (version 6.0)

The application I am building is an SDI front end
with a pure C++ calculator class behind it.

I am focusing on the Front end at the moment.

My goal is to present to the user a set of property
pages which basically contain a useful interface for
collecting the data to populate the classes inside the
calculator.

So far this has been going fairly well.

My problem is:
I am trying to use MULTI-LEVEL INHERITANCE to build the
property sheets.
Rather than define a new DIALOG for each sheet, I have
TWO basic dialogs which will be replicated (50+) times.

The Inheritance structure Looks something like this:

Class A : CPropertyPage // My Property Page Base Class

Class B : Class A // My Standard Page Class

Class C : Class A // My Non Standard Page Class

Class D : Class B // Implementation of Stanard Page

Class E : Class C // Implementation of Non Standard Page

In terms of O-O I think it is quite solid, however in
terms of MFC I keep getting REALLY Strange things happening.

First, I thought that I should be able to declare
all of my Dialog Controls and Handlers for them in
Class B for the Standard and Class C for the Non Standard
Forms.

This is fine, EXCEPT when I get into the implemented
versions of these classes, the messages for the controls
are not reaching the FORMS!!!

That is, the messages are being sent, but not being
received.

A good example is:
In my implementation of Class D, I try and catch the
OnChange Event for an edit control which is on the
Dialog associated with Class B. When the message is
sent, the control which is displayed on the
screen never receives the message.

Anyway, I am in a bit of a rush to get this done,
and I appologise for the LENGTHY question, but
I think I need to be clear about the problem as it
is not straight forward.

Any help would be greatly appreciated.

Please note, I REALLY want to avoid creating a dialog
and/or set of controls+handlers for EACH page (50+)
as this would be EXTREMELY redundant and I could make
much better use of inheritance (I think/Hope)

Many Thanks

D
Avatar of Thangs
Thangs

Try to subclass the items dynamically. THis might solve your problem.
Avatar of DanRollins
Carefully check this part of the dlg class:

BEGIN_MESSAGE_MAP(CDerivedDlg, CBaseDialog)
     //{{AFX_MSG_MAP(CDerivedDlg)
     ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
     //}}AFX_MSG_MAP
END_MESSAGE_MAP()

I know that when I have played around with manually setting things up like you describe, I have missed this.  The BEGIN_MESSAGE_MAP() macro must b e correctly set to pass messages to the correct place.

-- Dan

P.S. I find it highly unlikely that you need 50 different (but nearly identical) property pages.  When I have heard similar stories, the solution was to simply hide/show a few controls, and modify some static text --  based upon some flags passed into a *single* page.
Avatar of dpitman

ASKER

DanRollins,
I have checked and re-checked the message maps
in each of the classes.

I have tried using the direct base class aswell as the
the inherited base class.

i.e.
BEGIN_MESSAGE_MAP(ClassD, ClassB)
    //{{AFX_MSG_MAP(ClassD)
    ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

Since Class B is the one which actually has the controls
physically stored in it I too thought this would
solve the problem, yet the messages still never
reach the controls.

Hmmm ...

Subclassing ...
Does that mean in each derived form I need to tell
every control to subclass itself .... for each page???

I don't really understand the concept of subclassing as
presented by microsoft.

The concept seems to be to tell a control to create a
new instance of itself and thus give it a new "owner"
in the process. (I think ???? )

In explaination of the 50 page thing ... yes I know it
sounds like .... "AH HE'S MAD!!",
But I needed a neat way of presenting to the user
All of the available inputs for my calculator, while
giving the user some idea of the input structure
and the property pages with the tabs seem to be the only
structure that makes this clear.

I have looked at alternatives and this is by far the
clearest method.

In terms of simplifying the Pages, I have reduced them
to 2 basic types, but I need to be able to individualise
each page, hence the need to create another class for
each one.

Thanks for the suggestions though.

Regards

D



>>Subclassing ...
>>Does that mean in each derived form I need to tell
>>every control to subclass itself .... for each page???

I've found that I rarely need to do manual subclassing.  It comes up only when I need to add non-standard functionality to a control.  For instance, I have a CEdit-derived class that formats the input as $###,###.## as  you type.  I use subclassing to install my keystroke handling.

There is a lot of *implicit* subclassing that goes on.  When you use the ClassWizard to create a "Control" type variable, then that CWnd-derived object will have itself inserted into the chain of window procs; that is, it will subclass the control's window.

-==-=-=-=-=-=-
A >> I need to be able to individualise each page,
B >> hence the need to create another class for each one.

One does not necessarily follow the other.  There is usually no need to create a new class to in order individualize a page.  

If you've made up your mind, then fine.  Go to it.  But I think we can both agree that it will be a lot of work to do and h3ll to maintain.  If you want any help rethinking your strategy, I'll be glad to discuss it with you.  As a start, describe the kinds of indididualizations that you'll need.

-- Dan
Avatar of dpitman

ASKER

DanRollins,

I have been re-thinking my approach to this layout dilemma.
I think you are correct.
Due to the rushed time frame I have failed to consider
ALL the possibilities.
I have been playing with the idea of a
TREEVIEW, with an associated FORMVIEW to display the
required controls, this I think will eliminate the
need for all the pages as I can store the required
class data in the tree and pass it to the FORM to
populate the controls.

So I have to thank you for making me stop and think for
a minute.
It will be quite a change from what I have now but
for the better I think.
So thank you very much.

However, this still does not answer my initial question
about why the dialog message structure cannot be inherited
correctly?

Since I am following your advice DanRollins, would you
like me to award the points to you?
I would be quite happy to do that, my only concern is
that the question I initially asked still has yet
to be resolved. Will that impact on other people if they
would like to know the same thing?

My email is
dpitman@energy.com.au
feel free to drop me a line and let me know what you think
and thank you very much again for the help.

Kind Regards,

DPitman.
I'm glad I could help.  Now lets re-examine the original problem:

I have used a CPropertyPage-derived class (CProgPg) as the base class for set of pages that needed some shared functionality.  They needed to have a balloon-style popup tooltips.  So this base class overrides some functions such as OnActivate() and it also processes some messages, including WM_MOUSEMOVE

Note that there is no actual Dialog resource associated with this base class.

Now when I want to create a propterty page that inherits this special functionality, I proceed as follows:

1) In the Wizard, create a new dialog with the expected styles (Child, title bar, thin border).  Actually, I copy a previously-created one, giving it a new IID, say IID_PgMyNewPg.

2) when I double-click its titlebar the first time, the classwizard says "IID_PgMyNewPg is a new resource..."  I click OK to create a new class.

3) Class name is CDlgPgMyNewPg and its base class is CPropertyPage

4) Before doing *anything Esle*.  I clcik [Edit Code] to bring up the neew CPP file.

5) I replace every occurrance of "CPropertyPage" with "CPropPg" (my custom base class).

6) I then bring up the header file, DlgPgMyNewPg.h  And I again replace every occurrence of "CPropertyPage" with "CPropPg"

7) In the .h file, I also add
    #include "PropPg.h"
near the top.

=-=-=-=-=-=-=-=-=-=-
From now on, I can treat CMyNewPg as if it were derived directly from CProperyPage and the ClassWizard does not give me any sass.

=-=-=-=-=-=-=-=-=-=-
Looking back over your question, I see:
>>A good example is:
>>... I try and catch the OnChange Event for an edit
>> control which is on the Dialog associated with Class B.
>> When the message is sent, the control which is
>> displayed on the screen never receives the message.

I know there is a deal called "Message Reflection" which is supposed to solve all of the ills of the earth, but in general, one typically handles EN_CHANGE in the parent dialog, via an OnChangeMyEditBox() fn.  Did you misspeak yourself, or do you have a Control (i.e., a CEdit-derived class) that you wanted to get and handle these notifications?

=-=-=-=-=-=-=-=-=-=-
Please describe the inheretance that you wish to pass on the derived classes.

I can imagine someone wanting a scenario like this:

*  A dialog box with an edit control in the upper left corner and nothing else -- the base class

*  A derived class that adds a list box in the lower right corner.  Since it is derived from the base class, you would expect it to also show the edit box in the upper left corner.

If that is your goal, I think it will be difficult to implement.  There must be a dialog resource that matches the controls in the class.  In this sceanrio, there are two dialog resources and neither one has all of the controls.  It may be possible, but it is certainly going to fail unless you hand-craft each dialog box resource and each class.  Doing so will lose much of the value and convenience of the ClassWizard.

If your goal is a different situation, please describe it.

-- Dan
Avatar of dpitman

ASKER

DanRollins,
I think that you have almost the situation I am in
described correctly.

I will try and make it clearer my exact predicament.

I want to implement Multiple Property Pages with the same
layout and controls.
This describes the perfect need for inheritance.

i.e. If I implement 2 or 3 or however many base classes
of the layouts I need, I should be able to inherit the
dialogs, the controls, the message handlers ... everything
into another class and then customise each (if required).

So here is my goal (was my goal :) )
I have two basic layouts

Class MyPropertyPage : public CPropertyPage
{
// Custom handlers for OnSize etc..
// ONLY COMMON TO THE DERIVED CLASSES!!!
}

Class Standard : CMyPropertyPage
{
// IMPLEMENTS the DIALOG and Controls and
// Message handlers for the controls
// For DIALOG TYPE STANDARD
}

Class NonStandard : CMyPropertyPage
{
// IMPLEMENTS the DIALOG and Controls and
// Message handlers for the controls
// For the DIALOG TYPE NON-STANDARD
}

Now both of these classes should inherit the message
handlers for OnSize from the base class ... right?
Then they each customise the handling of the controls
on their respective forms.

Now, To make it clear for the user, I have implemented
a bunch of usage classes which use these base Property
Pages. NOTE: This was also to help me keep track of the
different data stored in my app. (Conceptually speaking)

Like This:
Class Use1 : public Standard
{
}

Class Use2 : public Standard
{
}

Class Use3 : public NonStandard
{
}

So now what I was hoping to have implemented was:
Three Use Classes which would display and handle their
own dialogs, controls, and messages.

The problem was : The messages were not handled in
any of the Use Classes and were not being passed to the base classes. (Where the controls live.)

So really my derived classes are not modifying the
forms in any way or adding controls even, they are
just there for structural benefit.

What my programming intention was, because I wanted to
clearly implement the structure I have been given, I was
quite happy to define the 50 or so classes required, but
rather than make each class have EVERYTHING on the form
and perform its own handling of the controls which exist
on EVERY other form, I thought ... AHA, inheritance is my
saviour.

But Alas ....
Shot down again .... :(

Hows that? Bit Clearer than my first go? :)

Look Forward to a response .... ;)

Regards

D
It reamins difficult for me to visualize what you are doing.  This is not to criticize your expository techniquies, only that these things are best discusees in a conference room with a white board...

It would help to have concrete examples.  E.g., "In Dialog A, the user needs to input the name of a car maker which later needs to be stored into a database table... and in Dialog B the user must select a type of vegetable from a drop-down list which is populated from..."

But even lacking this, I think can recommend the following technique:  

Create just the two CPropertyPage classes and two Dialog Resources.  Now create a new object that describes what is distinctive about the 50 dialogs.  Make that object a member of the base dialogs and initialize that object before displaying the propertysheet.  Then the page can do different things based upon the settings in this object.  This object is, in some ways like the MFC concept of a "Document" and the dialogs parallel the MFC "View"

You asked why your derived OnSize() is not getting called.  I think that is because CPropertyPage does special handling for sizing property pages.  It needs to set the size of all pages to be the same.   Also, propertypages are child dialogs so can't be sized manually anyway.

To experiment, look for some other messages, such as WM_MOUSEMOVE, etc.

-- Dan
hi dpitman,
Do you have any additional questions?  Do any comments need clarification?

-- Dan
hi dpitman,
Do you have any additional questions?  Do any comments need clarification?

-- Dan
Avatar of dpitman

ASKER

Sorry,

I have been away for a couple of weeks.

I am puting together a demo app for your review.
Outlining my implementation.

Have you got an email address I can post the project
files to DanRollins?

Regards,

D


I'd rather not post my email address here.  Post your own email address.  I'll reply to it and you can reply to that.

-- Dan
Avatar of dpitman

ASKER

ok
use

damo_online@hotmail.com

and that should be ok.

if that is a problem, i have two others you can try

D
hi dpitman,
Do you have any additional questions?  Do any comments need clarification?

-- Dan
ASKER CERTIFIED SOLUTION
Avatar of DanRollins
DanRollins
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial