How do you Switch between several views within the same ChildFrame object?

How do you Switch Views within the same Child Frame?  C++ VS2018 15.5.6  I am using the MFC Doc/View Architecture.  I can create new 7 document, as programed.  I have seen several different code examples for do it within the Main Frame, however not within the Child Frame class.  I have created several different CView based classes.  I have added the #include(s) for them in the App.h file header, and this header is included in the ChildFm.cpp file.  It shows up OK as far as Intellisense is concerned.  
// ChildFrm.cpp : implementation of the CChildFrame class
//
#include "stdafx.h"
#include "TCPG.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CChildFrame
IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWndEx)
BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWndEx)
      ON_COMMAND(ID_VIEW_PLAYERVIEW, &CChildFrame::OnViewPlayerview)
      ON_COMMAND(ID_VIEW_QUESTIONVIEW, &CChildFrame::OnViewQuestionview)
      ON_COMMAND(ID_VIEW_LAYOUTVIEW, &CChildFrame::OnViewLayoutview)
      ON_COMMAND(ID_VIEW_YOURREADING, &CChildFrame::OnViewYourreading)
END_MESSAGE_MAP()
These are the function declarations for switching the views.  The empty bodies are in the .cpp file.
And all of it compiles OK at this point.  Each view class is filled with all of the necessaries for that class, and works with the CDocument class.
Yet ...  when I add
// ChildFrm.h : interface of the CChildFrame class
//
#pragma once

class CChildFrame : public CMDIChildWndEx
{
      DECLARE_DYNCREATE(CChildFrame)
public:
      CChildFrame();
// Attributes
public:
      CTCPGView * m_pPlayerView;  // newly added view member of class previously compiled without error.
gives the following errors ...

Severity      Code      Description      Project      File      Line      Suppression State
Error      C4430      missing type specifier - int assumed. Note: C++ does not support default-int      TCPG      c:\users\donald\documents\visual studio 2017\projects\tcpg\tcpg\childfrm.h      14      

Severity      Code      Description      Project      File      Line      Suppression State
Error      C2143      syntax error: missing ';' before '*'      TCPG      c:\users\donald\documents\visual studio 2017\projects\tcpg\tcpg\childfrm.h      14      

Severity      Code      Description      Project      File      Line      Suppression State
Error      C2238      unexpected token(s) preceding ';'      TCPG      c:\users\donald\documents\visual studio 2017\projects\tcpg\tcpg\childfrm.h      14      

and without that one declaration ...
// Attributes
public:
//      CTCPGView * m_pPlayerView;

I get ....
1>------ Build started: Project: TCPG, Configuration: Debug Win32 ------
1>TarotCard.cpp
1>TCPGView.cpp
1>TCPGDoc.cpp
1>TCPG.cpp
1>ReadingView.cpp
1>QuestionView.cpp
1>Question.cpp
1>Player.cpp
1>NumOfPlayers.cpp
1>MainFrm.cpp
1>LayoutView.cpp
1>Layout.cpp
1>CutNShuffleDlg.cpp
1>ChildFrm.cpp
1>ChangeCardbackDlg.cpp
1>CardLayout.cpp
1>Generating Code...
1>TCPG.vcxproj -> C:\Users\Donald\documents\visual studio 2017\Projects\TCPG\Debug\TCPG.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Go figure ... so what is up with this code, it acts like the file is not included, and yet ...

#include "CardLayout.h"
#include "Layout.h"
#include "NumOfPlayers.h"
#include "Player.h"
#include "Question.h"
#include "Tarot.h"
#include "TarotCard.h"
#include "MainFrm.h"
#include "ChildFrm.h"
#include "TCPGDoc.h"
#include "TCPGView.h"
#include "QuestionView.h"
#include "LayoutView.h"
#include "ReadingView.h"
it is in there ... with 3 others.
Donald P. HutchinsWormhole DiscovererAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

sarabandeCommented:
for MFC mdi you have the following hierarchy:

- one single application class derived from CWinApp
  the application class contains a list of 1 to n document templates
  you can add a new doc template to the list by using CWinApp::AddDocTemplate function
  to retrieve doc templates from application class you were using
      CWinApp::GetFirstDocTemplatePosition and CWinApp::GetNextDocTemplate
 
- each doc template defines a triple of frame window class, document class, view class.
  there are some member functions like CreateNewFrame, CreateNewDocument, InitialUpdateFrame
  which allow to create new frames,  documents, views.
  the document template contains a list of 1 to m documents
  you can add a new document to the list by using CDocTemplate::AddDocument function
  to retrieve documents from doc template class you were using
      CDocTemplate::GetFirstDocumentPosition and CDocTemplate::GetNextDocument

- each document may contain a list of 1 to k views
  you can add a new view to a document by calling CDocument::AddView
  to retrieve views from list you may use
       CDocument::GetFirstViewPosition and CDocument::GetNextView

so for your requirement you would add all the views created to the corresponding document and to show a specific view you would provide a member function in your document class like

void MyDocument::ShowSecondView()
{
     POSITION pos = GetFirstViewPosition();
     if (pos)
     {
          // get first view
          CView * pView = GetNextView(pos);
          if (pView && pos)
          {      
                 // get second view
                 pView = GetNextView(pos);
                 if (pView)
                 {
                       pView->ShowWindow(SW_SHOW);
                       // set focus to a field or hide other views or set the z-order or use docking panes ...
                 }
           }
      }
}

Open in new window


note, the document class has a member function UpdateAllViews. so in case more than one view was shown for a document you could call this function in the document and it would cause the OnUpdate function to be called for each view.

Sara
1
Donald P. HutchinsWormhole DiscovererAuthor Commented:
Thank you Sara.  While the information you gave is very useful, and would seem to work ... for you...
Using AddView in the CDoument class object file.With my current version of VS2018 15.5.6 It compiles OK, yet when I run it, I get this weird unknown error ...
0
sarabandeCommented:
the exception seems to happen in the constructor of the second view. can you post the code for the view class definition and the constructor?

you may set a break point at the statement and step into the constructor by f11. the first f11 probably will go into operator new. then you have to press shift+f11 in order to go out of operator new, then press f11 again to step into the constructor (if it still is not the constructor, repeat shift+f11 and f11 as long as you didn't see the constructor code.

note, if the second view is a formview, you need to pass a valid IDD resource with the constructor.

Sara
0
Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

Donald P. HutchinsWormhole DiscovererAuthor Commented:
The first 3 views that I want to use and see are derived from CFormView, and each does have it's own IDD_xxx.  When doing an AddView(....) for adding CFormView derived class, as you have mentioned, how do you write the statement using the IDD ?
0
sarabandeCommented:
normally you would define an enum in the header file of your view class

//yourview.h
...

class YourView  :  public CFormView
{
	DECLARE_DYNCREATE(CYourView)

protected:
	YourView();           // protected constructor used by dynamic creation
	virtual ~YourView();

public:
        enum { IDD = IDD_YOUR_VIEW };
    ....
};

//yourview.cpp

#include "yourview.h"

IMPLEMENT_DYNCREATE(YourView, CFormView)

YourView::YourView()
	: CFormView(YourView::IDD)
{
      ....

}

Open in new window


by defining the enum constant IDD in the class it is unique. you also could do

YourView::YourView()
	: CFormView(IDD_YOUR_VIEW)

Open in new window


but it is better readable if the class header contains the (only) reference to the resource.

note, the AddView of the document is supposed to "add" a further view to an already existing view of the document. the first view should be inserted by using a doctemplate which creates the triple of frame, document , and view. if you have two documents of the same frame you also can use the same doctemplate in order to first add a new document with its initial view to the existing doctemplate object  and then you may add more views to the document.

Sara
1
Donald P. HutchinsWormhole DiscovererAuthor Commented:
So in my code example, in the screen shot above, it by passed the first set of 'new' and 'Add' statements because that view was already included by the triple DocTemplate class.  So the "CQuestionView" class is based upon CFormView, which has an IDD = IDD_QUESTION_VIEW.  They were created using Class Wizard, very carefully, to generate the classes.  I have data storage member attributes for two radio groups, 2 edit controls, and several buttons, each view is complete, with its bells and whistles.
In the app file:
	CCommandLineInfo cmdInfo;
	cmdInfo.m_nShellCommand = cmdInfo.FileNothing;
	ParseCommandLine(cmdInfo);

Open in new window

In this way I control the number of documents or players in an instance, so as to keep thing properly randomized.
I was just looking at a different example ... I think I may know what I am doing wrong .. I haven't done the following for the view  before I add it ...
 
        m_pView2->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, rectDefault, this, 
            AFX_IDW_PANE_FIRST + 1, NULL);

Open in new window

within the CDocument class.  I am now wondering if it would advantageous to do this in the construction or Initial update function of my document class ...
0
sarabandeCommented:
I am now wondering if it would advantageous to do this in the construction or Initial update function of my document class ...

generally mfc objects have a two-phase creation. in the constructor they create the c++ object, in the create function they create they add the relation to winapi objects. therefore the constructor never should be used for relations like document - view. the Init... member functions are callback functions which explicitly provide the means for customization. providing code for those functions allows you to calling the base class function at begin and then adding stuff, or replacing the baseclass implementation by your code.

so bottom line is  to using the Initializing member function of your document class for to creating new views. if you get a request for a new view within another view (say by button click or context menu), you would use a member function of your document class and call like

GetDocument()->CreateSecondView(this, .....);

Open in new window


Sara
1
Donald P. HutchinsWormhole DiscovererAuthor Commented:
I found this:
 if (nCmdID == ID_VIEW_CHANGE2)
   {
      if (m_pView2 == NULL)
      {
         m_pView1 = GetActiveView();
         m_pView2 = new CMyView2;

         //Note that if OnSize has been overridden in CMyView2 
         //and GetDocument() is used in this override it can 
         //cause assertions and, if the assertions are ignored,
         //cause access violation.

         m_pView2->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, rectDefault, this, 
            AFX_IDW_PANE_FIRST + 1, NULL);
      }
      pViewAdd = m_pView2;
      pViewRemove = m_pView1;
      m_currentView = cvView2;
   }

Open in new window


While I do not have OnSize overridden in my CFormViews, I do have a GetDocument() override in each of them.  And when I go to put a member variable derived from one of my CFormView's in my CDocument class, I get compile errors.

What I am having trouble with is : "requirement you would add all the views created to the corresponding document" Do I create them in the header, and if I do I get:
Severity      Code      Description      Project      File      Line      Suppression State
Error      C4430      missing type specifier - int assumed. Note: C++ does not support default-int      TCPG      c:\users\donald\documents\visual studio 2017\projects\tcpg\tcpg\TCPGDoc.h      30      
Severity      Code      Description      Project      File      Line      Suppression State
Error      C2143      syntax error: missing ';' before '*'      TCPG      c:\users\donald\documents\visual studio 2017\projects\tcpg\tcpg\TCPGDoc.h      30      
Severity      Code      Description      Project      File      Line      Suppression State
Error      C2238      unexpected token(s) preceding ';'      TCPG      c:\users\donald\documents\visual studio 2017\projects\tcpg\tcpg\TCPGDoc.h      30      
Which says I have not included the header file, then when I move #includes for my CFormViews from  the header file of the mainApp header, into the CDocument header I get:
Severity      Code      Description      Project      File      Line      Suppression State
Error      C2761      'CDocument *CView::GetDocument(void) const': redeclaration of member is not allowed      TCPG      c:\users\donald\documents\visual studio 2017\projects\tcpg\tcpg\TCPGView.h      146      
which from before didn't seem to be an issue, however it now is.
0
sarabandeCommented:
if (m_pView2 == NULL)
i don't think it is a good idea to have pointers to views as members in the document. as told, the document already has a container with its views. if a document can have more than one view, you may have different use cases to consider

- all views are shown  (for example in a splitter window)
- there is only one view shown the others are hidden
- there is one view which needs to create dynamically a further view
   + both are shown
   + the second view replaces the first view

in all these use cases you don't need to destroy a view. if you have to replace one view by another, it is much simpler (also in the undo case) to hide the one and to show the other.  if any updates on the document are forwarded to all views by calling CDocument::UpdateAllViews(),  the view to show already is up-to-date.

so the design should be that you create the first view by using the doctemplate which creates frame, document and view. any second view was created by a document member function which adds the view to the view list by using CDocument::AddView. after creation you may show the view by calling the views ShowWindow member function with the SW_SHOW argument. if it shouldn't be shown yet, you use the SW_HIDE argument. if there is a view whcih want to have an additional view, call a member function of the document which does this job. the document then can check whether the view is already created but hidden, or if it needs to be created in the first case. then the document can use the UpdateAllViews function to give the view(s) which should be shown a notice that they should show (themselves) and the other views that the should hide (maybe it is better to send two messages, first the one to hide and then the message to show. this all can be done by designing a bundle of costomized update messages which were passed by UpdateAllViews to each child view and which can be caught by the CView::OnUpdate handler.

Sara
1
sarabandeCommented:
Error      C4430      missing type specifier - int assumed.

this error occurs if you were using a type - for example a classname - which is not known by the header at this time.

normally there are two ways out.

(1) you make a forward declaration

class TCPG;

....

class MyClass
{
     TCPG * m_pTcpg;   // now it compiles
     ...

Open in new window


however, forward declarations only can be made for pointers or reference type. in the sample it is either TCPG * or TCPG & (with or without const). that is because for value types the compiler needs to know the size of the type, while for pointers and references it has pointer size.

(2) you include the header where the type was defined

// myclass.h
#pragma once

#include "tcpg.h"

class MyClass
{
     TCPG m_tcpg;

Open in new window


you see you now even can define value types. however, include files in headers may cause a deadlock if a.h includes b.h and b.h includes a.h it won't work. so you should go with forward declarations in the header whenever possible and include other headers only if really necessary. note, stdafx.h never can be included in a header since it includes all winapi and mfc and might be used for precompiled headers which only can be used in cpp files.

Sara
1
Donald P. HutchinsWormhole DiscovererAuthor Commented:
Here is the code for the constructor in the QuestionView.cpp source file.

CQuestionView::CQuestionView()
	: CFormView(IDD_QUESTION_FORM)
	, m_QuLayout(0)
	, m_QuType(0)
	, m_strTheQuestion(_T(""))
	, m_strTotalQNum(_T(""))
	, m_strCurrentQNum(_T(""))
	, m_strPlayerNum(_T(""))
	, m_strOtherQuType(_T(""))
{

}

Open in new window


I like what you did here:
void MyDocument::ShowSecondView()
{
     POSITION pos = GetFirstViewPosition();
     if (pos)
     {
          // get first view
          CView * pView = GetNextView(pos);
          if (pView && pos)
          {      
                 // get second view
                 pView = GetNextView(pos);
                 if (pView)
                 {
                       pView->ShowWindow(SW_SHOW);
                       // set focus to a field or hide other views or set the z-order or use docking panes ...
                 }
           }
      }
}

Open in new window

And I do this " ...  the first view should be inserted by using a doctemplate which creates the triple of frame, document , and view."
void CMainFrame::OnNewPlayer1()
{
	m_Player = GetPlayer(PLAYER1_NUM);  bPlayer1 = true;
	CBitmap bmpPlayer;
	bmpPlayer.LoadBitmap(IDBMP_PLAYER1);
	m_Player.m_pdcPlayerImage->CreateCompatibleDC(NULL);
	m_Player.m_pdcPlayerImage->SelectObject(&bmpPlayer);
	
	CTCPGDoc* pDoc = (CTCPGDoc*)theApp.m_pDocTemplate->CreateNewDocument();
	CChildFrame* pChild = (CChildFrame*)theApp.m_pDocTemplate->CreateNewFrame(pDoc, NULL);
	pDoc->SetTitle(m_Player.m_strPlayerNum);
	pDoc->InitTarotDocument();
	theApp.m_pDocTemplate->InitialUpdateFrame(pChild, pDoc);
}

Open in new window

which works very well, when it all compiles nicely, which it does until I do something that 'upsets the apple cart'.
Such as trying to do "so bottom line is  to using the Initializing member function of your document class for to creating new views. " which seems to imply that the view member variables could be placed in the Document header and thus be accessible, VS member function which creates new view holders, which you have yet to show me, that may or may not have persistence, and not be accessible directly, but possibly through a second or third programed CDocument member function ...
 

- there is only one view shown the others are hidden
 - there is one view which needs to create dynamically a further view
+ the second view replaces the first view
the above represents, correctly, my 'scheme' to my views.  The Player, enters their information some of which is used by the next view, which is the CQuestionView.  There they need to input the needed information and make some choices, That information is used in the next view, the CLayoutView.  The random results of this view generates the information for the next view, the CReadingView, which has the Print Dialogs enabled.  
"Any second view was created by a document member function which adds the view to the view list by using CDocument::AddView. " would seem to result in inaccessible via a GetDocumet() call directly to a member variable.  

After creation you may show the view by calling the views ShowWindow member function with the SW_SHOW argument.
this requires a member variable call to a CFrameWnd, my CChildFrm class type in this case, to which the new view needs to replace the previous one, within the same child frame.
I would like to pre-create my views, in the CDocument class seems to be one method, yet putting in a CView* member variable in the doc header, just causes compile issues for some reason.  

// TCPGDoc.h : interface of the CTCPGDoc class
//
#pragma once
#include "CuteBundle.h"
typedef CCuteBundle<CQuestion, CQuestion&> CQuestionArray;
typedef CCuteBundle<CCardLayout, CCardLayout&> CSpredArray;

class CTCPGDoc : public CDocument
{
public: 
	CTCPGDoc();
	DECLARE_DYNCREATE(CTCPGDoc)
	static const UINT IID_ITCPGDoc = IDR_PLAYERVIEW;
//Attributes
public:
     CQuestionView* m_pQView;  // adding a view member like this causes compile errors as shown above else where.. 

Open in new window

the above is the header beginning for my CDocument type class.  I also have a "IDR_QUESTIONVIEW", a "IDR_LAYOUTVIEW", AND A "IDR_READINGVIEW", for which I have created resources that I would like to displayed and be useful.  so in order to use them, would it be useful to do the following:
static const UINT IID_ITCPGDoc = IDR_PLAYERVIEW | IDR_QUESTIONVIEW | IDR_LAYOUTVIEW | IDR_READINGVIEW ;

Open in new window

?
In my source code for my Doc class:
// TCPGDoc.cpp : implementation of the CTCPGDoc class
//
#include "stdafx.h"
// SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail
// and search filter handlers and allows sharing of document code with that project.
#ifndef SHARED_HANDLERS
#include "TCPG.h"
#endif
#include "TCPG.h"
#include "TCPGDoc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CTCPGDoc
IMPLEMENT_DYNCREATE(CTCPGDoc, CDocument)

Open in new window

as the intro to the rest of it.  
Interesting, as I have already put the #include "QuestionView.h" in the "TCPG.h" file, and then #include "TCPG.h" in my "TCPGDoc.h" and Intellisence shows it as an available object, so it technically has been included, yet the error has persisted.  I just now have added the forward declaration:
// TCPGDoc.h : interface of the CTCPGDoc class
//
#pragma once
#include "CuteBundle.h"
typedef CCuteBundle<CQuestion, CQuestion&> CQuestionArray;
typedef CCuteBundle<CCardLayout, CCardLayout&> CSpredArray;

class CQuestionView;

class CTCPGDoc : public CDocument
{
public: 
	CTCPGDoc();
	DECLARE_DYNCREATE(CTCPGDoc)
	static const UINT IID_ITCPGDoc = IDR_PLAYERVIEW;

Open in new window

And BADABING! as you said no compile errors.  So (1) did work while trying (2) does not work for some reason, and it gives the following errors:
Severity      Code      Description      Project      File      Line      Suppression State
Error      C2509      'GetDocument': member function not declared in 'CQuestionView'      TCPG      c:\users\donald\documents\visual studio 2017\projects\tcpg\tcpg\questionview.cpp      152      
Severity      Code      Description      Project      File      Line      Suppression State
Error      C2039      'm_arCardLayout4QNum': is not a member of 'CDocument'      TCPG      c:\users\donald\documents\visual studio 2017\projects\tcpg\tcpg\questionview.cpp      255      
Severity      Code      Description      Project      File      Line      Suppression State
Error      C4430      missing type specifier - int assumed. Note: C++ does not support default-int      TCPG      c:\users\donald\documents\visual studio 2017\projects\tcpg\tcpg\questionview.h      47      
and a host of others related to my other classes and members being initialized within my CDocument class.

I like doing (1) better than (2), as I have tried (2) on many different iterations, and as yet has to work properly, however (1) so far seems to be working.  If I can access it later, via a member function, the all may be well ... I' ll let you know.
0
Donald P. HutchinsWormhole DiscovererAuthor Commented:
So you should go with forward declarations in the header whenever possible and include other headers only if really necessary. note, stdafx.h never can be included in a header since it includes all winapi and mfc and might be used for precompiled headers which only can be used in cpp files.
Hhhmmm... view the following:
#include "stdafx.h"
#include "ChangeCardbackDlg.h"

// CQuestionView form view

class CQuestionView : public CFormView
{
	DECLARE_DYNCREATE(CQuestionView)
	enum { IDD = IDD_QUESTION_FORM};

//Constuction
public:
	CQuestionView();  
	virtual ~CQuestionView();

//Attributes
public:

Open in new window

As you can see, I have #included "stdafx.h" in my view header, and no issues.  Sometimes I'll some macro defined in the stdafx.h file which might get used in the headers somehow...  In this case I have removed it as now there is no longer a need for it to be there.
0
sarabandeCommented:
which seems to imply that the view member variables could be placed in the Document header
no, the creation of a view in a member function doesn't bother with member variables. view creation is a two-phase action. first, you create the object by calling 'new MyViewClass(...)'. second, you call the Create member function of the view what creates the windows object. a document can show - but normally doesn't show - the view created. instead the view better should be hidden and (the pointer) put into the list of views for this document. you probably should have some status members in your document class which say what kind of views exist and which are shown or hidden (of course you also could iterate the view list in order to gain the status).  for to hide a view and to show another you normally should use the CDocument::UpdateAllViews functions. this function would iterate the view list and pass the message to all views. such a message can be "view 1 should hide and view 2 should show". then, view 1 would hide itself by calling ShowWindow(SW_HIDE); in the OnUpdate function while view 2 would show itself by calling ShowWindo(SW_SHOW). all other views would ignore the message and keep their current status.

as told, it is better to not use a pointer member for a view as they are already in a container. instead you might write a little function which iterates the view list and use the IsKindOf member function to return a view pointer of a specific class

MyFirstView * MyDocument::GetFirstViewPtr()
{
      // add here the iteration of the view list
      ....
                 pView = GetNextView(pos);
                 if (pView && pView->IsKindOf(RUNTIME_CLASS(MyFirstView)))
                 {
                        return (MyFirstView *)pView;   // it is a dynamic_cast if you like this better

Open in new window

               

if not using the RUNTIME_CLASS macro (but the GetRuntimeClass() member function) you also could pass the view class as a string to search for arbitrary view classes.

Sara
1
sarabandeCommented:
would seem to result in inaccessible via a GetDocumet() call directly to a member variable.

if you need to exchange data between views, you indeed have to use the common document as a vehicle. that could be by providing access to data members of the document by Getters and/or Setters, for example by a function 'CString MyDocument::GetTitle();' which can be called in every view via the GetDocument function. if the member needed in a second view isn't a document member but a member of another view (this shouldn't be the case if the view can't be used to edit the data member. even then, you need both a document member and a view member).

if for example you have a form view, you should use the OnInitialUpdate function to retrieve (persistent of default) data from your document. if data have been changed in the form and are valid for the document, the view should call UpdataData(TRUE) to get data from screen, and then call a Document member function in order get the modified data. the document then would update its own data members and call SaveDocument function. after the document is updated each view might update itself by using the OnUpdate function.

Sara
1
sarabandeCommented:
this requires a member variable call to a CFrameWnd, my CChildFrm class type in this case, to which the new view needs to replace the previous one, within the same child frame.

the frame window is the windows parent of the view. a call to this parent is (only) necessary if the frame's controls, menus, toolbar buttons, title, would need a change. if the changes were due to the new view to show, the view simply may use its GetParent() function to directly give notification. as a general rule, each object should update its own members and controls. never try to wag another object's tail. and the best way is to using the OnUpdate functions as those would guarantee that the handlers were called in the correct order and not that some changes were made reverse by a participient which keeps old data.

Sara
1
sarabandeCommented:
would it be useful to do the following:

static const UINT IID_ITCPGDoc = IDR_PLAYERVIEW | IDR_QUESTIONVIEW ...

no, that is big mistake. the | operator is a binary or  what means if  IDR_PLAYERVIEW is 5001 what is 4096+4+1 and IDR_QUESTIONVIEW is 5067 what is 4096 + 64 + 4 + 2 + 1, the bits for 1, 4, and 4096 are set even if only IDR_QUESTIONVIEW was checked.

note, the IDR_... ids are only numbers which should be unique (among other IDR constants). so you can check where they are defined (should be resource.h) and make a redefine

#define IDR_MAINFRAME  99

#define IDR_FIRSTCHILDFRAME 100

#define IDR_PLAYERFRAME    IDR_FIRSTCHILDFRAME + 0    // 100
#define IDR_QUESTIONFRAME IDR_FIRSTCHILDFRAME+1   // 101
....
#define IDR_SOMEOTHERFRAME IDR_FIRSTCHILDFRAME+9  //109
#define  IDR_LAST_FRAME  IDR_SOMEOTHERFRAME
...

Open in new window


Sara
0
sarabandeCommented:
I have #included "stdafx.h" in my view header, and no issues.  

no issues because all your cpp files have stdafx.h already included and the include statements for other headers are below.

so definitively, you don't need to include stdafx.h in a header file. this will lead to a (not-easy-to-understand) preprocessor error in case you ever would include that header in a cpp source which doesn't use stdafx.h and the precompiled headers. such sources can be useful for helper classes which don't use mfc and winapi.

also it makes little sense to include a header under certain (macro) condition and then include it again without any condition. if you want to try whether a header was needed simply comment the include statement and compile. if you get new errors, because of the missing header you could try with forward declarations. if you get the errors at a statement in another header, you either have to use forward declaration in that header or include the commented header in the header file where you got the error. generally it is good - but sadfully rarely used - practice to include in each header file only the minimal of other headers. to check this but don't be tricked by the fact that inclusion of stdafx.h is required for mfc sources (regardless whether you were using precompiled headers or not) you may add a copy of stdafx.cpp to your project, but make it a normal cpp file (i. e. change in the c++ - precompiled header properties the 'create stdafx.h' by 'not using precompiled headers'). the copied source only contains stdafx.h and nothing else. if you now include any other header file, it should compile without errors. if not, the header file is not complete, i. e. either forward declarations or other header files must be added. it also could be that the header file has an include statement not really needed. with the copy of the stdafx.cpp and the included header you simply may comment any of the include statements and compile. if it compiles the include statement is not really necessary.

note, as far as i remember the generated mfc mdi code has a common header named like the project, which contains all header files of the generated classes. this concept to not using minimal header includes but maximum in one central header is not good practice but much easier to handle both for the wizard creation and for you. that means, if you wouldn't like to go the stony way to minimum includes as described above, you simply can add header files of new frames, docs, views into the project header file (should be tcpg.h). be aware to have the correct order app header above mainframe.h, doctemplate headers above frame and doc headers, view and dialog headers below.

if you do so, don't forget to include this central header below stdafx.h in all of your cpp files. you even could add it to stdafx.h, what i wouldn't do as long as the project is not into maintanance phase. note, for current pc power the usage of precompiled headers (where all mfc stuff needed was compiled only once and not with each source) is little. you can try by changing 'use precompiled header thru stdafx.h' by 'not using precompiled header' for all cpp files (debug) and do a rebuild (note, the stdafx.h still must be included as first include file). measure build times.

Sara
1
sarabandeCommented:
#include "stdafx.h"

#include "ChangeCardbackDlg.h"

// CQuestionView form view

class CQuestionView : public CFormView

the class CQuestionView definitively has to be defined in an own header file or into tcpgview.h (if this is the name of the view header generated by the wizard).

so any of your mfc sources should look like

//anytcpg.cpp 
#include "stdafx.h"
#include "tcpg.h"      //include main header file

#include "ChangeCardbackDlg.h"  // include special headers (not already included in "tcpg.h")

...

Open in new window


Sara
0
sarabandeCommented:
Error      C2039      'm_arCardLayout4QNum': is not a member of 'CDocument'      TCPG      ..\tcpg\questionview.cpp
 
this error  occurs because you are using the expression

GetDocument()->m_arCardLayout4QNum

Open in new window


or similar. the problem is that the base class function CView::GetDocument  returns a pointer of type CDocument, while for the member you need a pointer of type CTCPGDoc. you can solve this with casting like

((CTCPGDoc * )GetDocument())->m_arCardLayout4QNum

Open in new window


but that is very ugly. much better is to overload the GetDocument function in the header of your view classes like

class CTCPGView : public CView
{
     ...
protected:
     CTCPGDoc * GetDocument();  

Open in new window


and in the view.cpp file

CTCPGDoc * CTCPGView::GetDocument()
{
     return (CTCPGDoc * )CView::GetDocument();
}

Open in new window


 the usage of CView::GetDocument prevents from a compiler error as the call of GetDocument would give an infinite recursion.

Sara
1
Donald P. HutchinsWormhole DiscovererAuthor Commented:
Error C2039,  this I understand.  The issue with it and all of the other data members, was the same.  The view class was not being "included" even though it was being included via TCPG.h, as are all of the other needed headers.  That is what was so confusing.  The forward declaration scheme is used by Microsoft in defining it's base classes and the derived ones from those.
As far as my GetDocument() overrides,
#ifndef _DEBUG  // debug version in QuestionView.cpp
inline virtual CTCPGDoc* CQuestionView::GetDocument() const 
{
	return reinterpret_cast<CTCPGDoc*>(m_pDocument);
}
#endif

Open in new window

is the standard release form of the function that resides in the header file, while the function body in the source file is the debug version which looks like:
CTCPGDoc* CQuestionView::GetDocument()const
{
	_ASSERTE(m_pDocument->IsKindOf(RUNTIME_CLASS(CTCPGDoc)));
	return (CTCPGDoc*)m_pDocument;
}

Open in new window

This presumes that the CDoument* m_pDocument is a member variable within the CView class, so that it can be used through inheritance.  This works so far as I have been using it,    I am curious as to why you 'protected' your version of CTCPGDoc* GetDocument() ...
void CQuestionView::OnInitialUpdate()
{
	CBitmap bmpCardBack;
	bmpCardBack.LoadBitmap(m_nCBNum);
	m_pdcCardBackImage->CreateCompatibleDC(NULL);
	m_pdcCardBackImage->SelectObject(&bmpCardBack);
	GetQuestionInfo();
	CFormView::OnInitialUpdate();
}

And the GetQuestionInfo()
void CQuestionView::GetQuestionInfo()
{
	m_strPlayerNum = GetDocument()->m_Player.m_strPlayerNum;
	m_strCurrentQNum = GetQNumStr(GetDocument()->m_nCurQuestNum);
	m_strTotalQNum = GetNumStr(GetDocument()->m_Player.m_nPlayerNumOfQ);
	m_strTheQuestion = GetDocument()->m_arPlayersQuestions.GetAt(GetDocument()->m_nCurQuestNum).m_strQuestion;
	m_QuType = GetDocument()->m_arPlayersQuestions.GetAt(GetDocument()->m_nCurQuestNum).m_nQuestionType;
	m_strQuestionType  = GetTypeStr(m_QuType);
	if (m_QuType == QUEST_TYPE9_NUM)
	{
		m_strOtherQuType = GetDocument()->m_arPlayersQuestions.GetAt(GetDocument()->m_nCurQuestNum).m_strOtherQT;
	}
	else
	{
		m_strOtherQuType = GetTypeStr(GetDocument()->m_arPlayersQuestions.GetAt(GetDocument()->m_nCurQuestNum).m_nQuestionType);
	}
	m_QuLayout = GetDocument()->m_arCardLayout4QNum.GetAt(GetDocument()->m_nCurQuestNum).m_nCardLayoutNum;
	m_nCBNum = GetDocument()->m_arCardLayout4QNum.GetAt(GetDocument()->m_nCurQuestNum).m_nCardBackNum;
}

Open in new window

Here is my OnInitialUpdate().  As you can see I make extensive use of my GetDocument() function.
My base issue was just having a view member variable at all.  I recently was thinking of using the RUNTIME_CLASS macro as the CRuntimeClass* m_pQViewClass; member variables had no issues being in the header of the document class.  
And maybe to do a "GetView()" function of some type similar to GetDocument and use it in the switch view function ... ?
	_ASSERTE(m_pView->IsKindOf(RUNTIME_CLASS(CQuestionView)));
	return (CQuestionView*)m_pView;

Open in new window

0
sarabandeCommented:
As far as my GetDocument() overrides,

unfortunately MFC wizard generated code has malchanged with the decades and produces different code for release and debug what in my opinion is completely wrong, or at least make the code proprietary without advantage.

- you never should use different member functions for debug or release because that spoils all tests you do in the debug phase.
- it also doesn't make any sense for a 100 percent c++ compatible function like the CView::GetDocument function.
- the CView::GetDocument function is not virtual and simply returns a protected pointer member m_pDocument;
- by overriding GetDocument in your derived view class you "HAVE" to use the CView::GetDocument base class function to
  retrieve the pointer of the document which "IS A" CTCPGDoc* but was returned by CView::GetDocument as a CDocument *.
- then the override would do a dynamic cast from CDocument* to CTCPGDoc* which would fail if the pointer "IS NOT" a CTCPGDoc*.
- the wizard code now makes the override a virtual function.
  this allows that you may have a further view class derived from your current view class and that documents created
  for this further view class may also have a derived document class.

return reinterpret_cast<CTCPGDoc*>(m_pDocument);

this is dangerous code and in my opinion a bug. the problem is that it assumes that the CTCPGDoc directly is derived from CDocument, for example CTCPGDoc derived from MyCDocument and MyCDocument derived from CDocument.

this is guaranteed for wizard code but not if you create a document class yourself, say by

class SomeDocument : public MyData, public: CDocument
{
   ...
}; 

Open in new window


here the pointer of the CDocument would be different to the pointer of SomeDocument and a reinterpret_cast would not fail but create a wrong pointer that crashes. MS would tell you that MFC objects are not allowed to be multi-inherited (what isn't quite true, since the only restriction is that always the first class you would derive from would lead  to the MFC class and you never derive from a MFC class as second class).

I am curious as to why you 'protected' your version of CTCPGDoc* GetDocument() ...

generally only the view class may use the GetDocument class. so it even could be declared as 'private'.

the CView class has a protected member m_pDocument, what means that you can't call CView::GetDocument from other classes, e. g. you can't call it from a frame class.

so the only significant difference is that the my version of GetDocument was not declared as const. that means you could do

CView::GetDocument() = pSomeOtherDocument;

Open in new window


what is a bad mistake, as we know that each document has a list of its views, which would become invalid if we change the internal document pointer of a view.

you should add the const to my code if you want to use it. then you have to remove the wizard-generated code.

you also may use the wizard generated code which would work, even if i think it is bad code.

the overrides are not really overrides because they have a different return type. nevertheless, if you call GetDocument() in your view class it automatically would prefer the special YourView::GetDocument over the CView::GetDocument, what is the goal.

return (CQuestionView*)m_pView;

no, you must see the hierarchies which is

    Application
          DocTemplate
                 Document
                        View

Open in new window


and

    MainFrame
            MDIChildWnd
                    View 

Open in new window


so the view has a pointer to its document, the document may have a pointer  to its doctemplate and the doctemplate could have a pointer to its application (it has not because the application is a singleton and retrievable by MFC AfxGetApp() function)

but if you would store pointers to a view - say in the document - it is a problem if there is more than one view. even if you have a pointer member for each kind of view, this is redundant because the document already has a list of its views.

as said, if you need information from another view somewhere and the "somewhere" should be questioned thoroughly, because a view is a graphical user interface to view a document and not an arbitrary window containing data for all documents. if the latter is needed you may use the mainframe window, a new document class - say MainFrameData - and a view which is shown somewhere in the mainframe (or for example in a splitter of another child frame). the required data you would not retrieve from view but from MainFrameData document. if you need the data in a view, the view would ask its own document which would ask the application. the application holds a pointer for each doctemplate and asks the doctemplate which holds the MainFrameData document. if the main frame data document is a singleton you may cut corners by providing the data via static functions of the application class.

Sara
0
Donald P. HutchinsWormhole DiscovererAuthor Commented:
it is a problem if there is more than one view. even if you have a pointer member for each kind of view, this is redundant because the document already has a list of its views.
 Exactly how is this list generated, if not with member variables?  AddView(CView* pview), adding a view to the document requires a pointer to the view, thanks to you, and the forward class declarations, I can now do.  I ran many different tests, and the document class now seems to be to only class to which I can actually add view members.  Previously, I was able to put them in the CChildFrm class, to switch my views, in the child frame, for each document tab / player.  Then they changed the logic structure, and now it is nearly impossible to put them any place else.
The 'const' keywod, is use for Getters, while lack of it allows it to be used as a Setter.
so the only significant difference is that the my version of GetDocument was not declared as const. that means you could do
		GetDocument()->m_arCardLayout4QNum.GetAt(GetDocument()->m_nCurQuestNum).m_nCardLayoutNum = LAYOUT0_NUM;

Open in new window

And I make extensive use of this kind of statement as well.
0
sarabandeCommented:
I make extensive use of this kind of statement

no, no. the GetDocument() const means that the pointer to the document of your view is const, i. e. you can't assign a different document as "your" document. it doesn't mean that the constant pointer you got by GetDocument cannot be used to get or set any public document member (data or function) of your document class by your views.

Exactly how is this list generated, if not with member variables?

it is a singly-linked list where the first node pointer indeed is a member of CDocument. but what do you want to say? that because the mfc uses member variables for managing the views, you are allowed to do the same? you may have overseen that you were using a framework which provides many functionality. but it only can do that if it is established with the means of the framework and not if you go your own way.

if you create views which are not bound to a document but only to the frame window, this might be valid but you shouldn't call them views (of a document) but windows.

thanks to you, and the forward class declarations
actually, the forward declarations are the right way for to using other class pointers or references without including their headers, but of course they require that the headers are included nevertheless in the cpp file where you were using the forward declared types. i told you, that mfc has a different way by incxluding all headers into one main header file. i don't like this solution but actually since you already have this header, you also could use or even have to use it. the only point to consider is, if you add two classes say a new document class and a new view class, you need to include the document header first because the view needs the document, and it needs the full class definition, and not only the forward declaration of the document name. if the document has a function which creates a new view of the new view kind, then a forward declaration is sufficient, as you have the implementation in the document.cpp which includes the general header (and so all headers) after stdafx.h.

Previously, I was able to put them in the CChildFrm class, to switch my views
if the views are in the same child frame and both visible, you still can switch them by the frame. if you need a view's document, call CFrameWnd::GetActiveDocument from your mdi child window frame. then call any puplic document function.

if there are still issues, please post some code which doesn't compile (with the errors put at the lines where they occurred) or which doesn't work. tell in detail what you intent to do, verbally not in code. how the requirement was triggered and how you designed the user interface.

Sara
0
Donald P. HutchinsWormhole DiscovererAuthor Commented:
Hi Sara.  Let me ask you, ARE you using MSVS 2017 Community Edition 15.6?  It is the IDE that I currently am using.  A lot has changed in it since the 4.0 version.  The whole CString issues between ANSI, wide character, and UNICODE, all had their headers modified, and modified as to how the literal text string was to be 'formatted' within the code itself and so on.
private:
	TYPE valueType; 
public:
	explicit Units(TYPE initVal = 0):valueType(initVal) { }  //initializer
	TYPE& value() { return valueType; }
	const TYPE& value() const { return valueType; }
	
	operator TYPE() const { return valueType; } // allow implicit conversion to/from values of TYPE
	Units& operator=(TYPE newVal) { valueType = newVal; return *this; } // allow assignments from values of TYPE

Open in new window

Here are some different statements.  Please explain how the statement pairs under public: are supposed to be working.  Note that 2 of the statements use the 'const' keyword.  I am not sure exactly what 'const' is supposed to do except to constrain the value to be used as a constant and not a variable.  Typically, if I want to put text into a string variable attached to an edit control inside a view, from the document, then that is when the 'const' comes into play, and if I want to put changed text from the string variable, to store it back into the document, then the function is used without the 'const' keyword.  
void CTCPGView::OnInitialUpdate()
{
	player = GetDocument()->m_Player; // Here I am retrieving pre-initialized info from the m_Player variable in the document 
	GetPlayerInfo();
	CFormView::OnInitialUpdate();
}

void CTCPGView::GetPlayerInfo(void)
{
	m_strPlayerName = player.m_strPlayerName;  //Variables to left of = are view members being initialized from the initialized player variable, that had been initialized earlier, from the document.
	m_nPlayerAge = player.m_nPlayerAge;
	m_strPlayerLocation = player.m_strPlayerLocation;
	m_nPlayerNumOfQ = player.m_nPlayerNumOfQ;
	m_nPlayerSexType = player.m_nPlayerSexID;
	m_nPlayerColor = player.m_nPlayerColor;
	m_oledtBirthday = player.m_oledtBirthday;
}

void CTCPGView::OnClickedPlayerEnter()
{
	UpdateData(TRUE);
	GetDocument()->m_Player = player; // Here I change the old info with the new info in the document.
	GetDocument()->UpdateAllViews(this);
}

Open in new window

 This all compiles well, and executes well.  My issue was getting the new views implemented, and switched in and out correctly so if the player went back and forth between the views, the imputed information, when saved, does not change, unless the player changes it, within the appropriate view.  The initial triple, attaches the first view to the document, which is contained inside of the CChildFrame, which derived all the way down to CWnd.  So using an architectural window structure as an example,  Views are not the frame but the glass itself, and what it is that you see when you look through the glass.  The Frame holds the glass.  The garden in the backyard is the document, which is what is being viewed though the window glass, as I understand it.  What I want is to put different pieces of glass, into my window frame, so I can see the different parts of garden using the different pieces of glass, which I presume is done by creating view class members within the document for the AddView() function.  It was very messy doing it in the CChildFrame class.
0
Donald P. HutchinsWormhole DiscovererAuthor Commented:
My Compiled program with 7 documents / players only.  Initial view for Player 1.Here is an image of my program with 7 players / document only.  As you can see I have Tab Views of each different Player.  I want to use my SwitchViews command on my menu, for the active tab / document, and go to the next view of the document, which has a different set of view variables in the same document.  Below are the main information storage devices, 3 of which are arrays of different classes, each class feeds/holds information for the view associated with it, but is not a view class itself.
	CPlayer m_Player;
	CQuestionArray m_arPlayersQuestions;
	CSpredArray m_arCardLayout4QNum;
	CStringArray m_ReadingArray;

Open in new window

 Each view feeds the next.  The ReadingView is a view of the text stored in a string within the CStringArray, which is a result of the previous views and inputs therefrom.
0
sarabandeCommented:
i am using VS2017 both at home and at business, but my current project uses the vs2010 compiler and linker for compatibility reasons.

     TYPE& value() { return valueType; }

      const TYPE& value() const { return valueType; }
      operator TYPE() const { return valueType; } // allow implicit conversion to/from values of TYPE
      Units & operator=(TYPE newVal) { valueType = newVal; return *this; } // allow assignments from values of TYPE

the first function allows to retrieve a non-const reference to the 'value_type'. hence, you have a writeable object  which also could be passed to other functions which require a non-const reference argument.

the second function only retrieves a const reference. hence the function itself can be daclared as to be const what means that by calling the function there is no change to the non-public data member possible (beside of casting or corruption).

since both functions only differ by constness attributes, it is the compiler that decides whether the first or the second were used fro a concrete statement. for example if you have  class Units with a constructor Units::Units(const TYPE & vt) : valueType(vt) {}

 // assume TYPE is int 
   Units<int> weight1(100);
   int & x = weight1.value();

Open in new window


the compiler would take the first value function because the assign statement requires a non-const type to be assigned to the non-const lvalue x.

   //forward declaration
   void f(const double & t);
   Units<double> miles(55.5);
   f(miles.value());  

Open in new window


here the second value function was used as the argument was declared as const

the third function is a so-called cast operator. it allows to use a class type instead of the member type, i. e. we can use class YourObject variable instead of TYPE.

   
   
   int sum (const int & t1, const int & t2) { return t1 + t2; }
   Units<int> wid1(123);
   Units<int> wid2(11);

   // pass variables of type Units<int> instead of int
   int s = sum(wid1, wid2);

Open in new window



here the compiler will use the cast operator defined in class Units to return const reference of int.

Sara
1

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
sarabandeCommented:
my program with 7 players / document only.  As you can see I have Tab Views of each different Player.  

hmm. it would have been better to have each player be represented by an own document. so you should have 1 frame, 7 documents and 1 or more views for each player.

if you don't have multiple games, i would say you could do it with an SDI which would use the main frame class to handle all the player tabs .

you would use the doctemplate from wizard code to create the mainframe and the first player  with the initial view. for each further player you can use the same doctemplate pointer to creating more players. you would use the CDocTemplate::CreateNewDocument function for this purpose. see https://docs.microsoft.com/en-us/cpp/mfc/reference/cdoctemplate-class for information

if the document was created you would use the associated frame window to create a new view (so far all you have done was ok). put the view onto a new child tab of your frame window and call the document's AddView function to establish the document view association. you must manually set the view to active and set it to be visible; these tasks are not automatically performed by CFrameWnd::CreateView.

an alternative to the above design could be to use an MDI and have a new doctemplate for each new player. that way you could create the players with a triple of frame, document, and view, and finally use mainframe class to show all child frames as tabs.

Sara
1
Donald P. HutchinsWormhole DiscovererAuthor Commented:
it would have been better to have each player be represented by an own document.
 And this is what I have done already.
you would use the doctemplate from wizard code to create the mainframe and the first player  with the initial view. for each further player you can use the same doctemplate pointer to creating more players.
 And I have done this as well, already.
And I did
use an MDI and have a new doctemplate for each new player. that way you could create the players with a triple of frame, document, and view, and finally use mainframe class to show all child frames as tabs.
.  So then, so far so good it would seem, and as we both use the same IDE then we are on the same page, so far.  
I want to
put the view onto a {current} rather than new child tab of your frame window, {as I have already limited the number of tabs / documents / players I would run out of tabs to use.} and {when / where do I }call the document's AddView function {presuming view members can be established to do so, or do I AddView(CreateView()) in order to avoid view member variables all together?} to establish the document view association. you must manually set the view to active and set it to be visible; these tasks are not automatically performed by CFrameWnd::CreateView.
which I have done else where in another program, and will do again in this one once a certain mfcXXX.dll gets it's code together.
0
sarabandeCommented:
I would run out of tabs to use
you may look at the design of visual studio itself. they use tabs for the first x source files. all files are available thru a listview popup which was invoked by CTRL+TAB and alternatively by a listbox at the right of the currently selected tab.  

say you have the first ten players each accessible by an own tab. then. you need a 11th player to be created and visualized at the last tab. then,  player 1 would removed from first tab. plyer 2 to player 9 would move left and so tab 10 is free to take new player 11. if the user opens the listbox or listview where all players are listed, they could choose one of 1 - 11 and if they choose a player not available by a tab you would shift all players from tab 1 to tab 9 one tab to the right what makes the first tab free to take the selected player which then becomes active (use SetActiveView . if they choose one of the players already accessible by a tab, you would make that tab the active tab (you can do that by using the mainframe class which would hold a list of a mdi child window frames and calll ShowWindow(SW_HIDE) for the currently active child frame  and ShowWindow(SW_SHOW) for the new active frame. note that is only one way out of many. you also can hold members in the application class which tell how many players you have and which of them is active ).

for any use case you would have  1 to x players where 10 of them can't be accessed by tab  and any one of them by using a control belonging to the mainframe. you never would replace a player x by player y but always create a new doctemplate with same triple of frame class, document class (player), and view class. call AddDocTemplate in your application class to add the doc template. call InitialUpdateFrame to automatically create document and view and make it visible if you have prepared the tabs by the mainframe and have a free tab where you could associate withe the new player. instead of CDocTemplate::InitialUpdateFrame, you alternatively could call pNewDocTemplate->CreateNewFrame and pNewDocTemplate->CreateNewDocument. then use the new frame window to calling CreateNewView. if you do so, all the AddDocument and AddView already are called by the framework.

with this design, you could allow that a current player was deleted and its entry was removed from tab and all players right from deleted player would shift left. if a player was deleted that was not on a tab, you simply CloseAllDocuments of the associated doc template. the framework would properly delete all of the triple and remove their entries.  

Sara
1
Donald P. HutchinsWormhole DiscovererAuthor Commented:
Hi Sara...I am very familiar with the file menu, and I limit, on purpose, the number of documents to be created.  I have a dialog that has an edit control, for numbers only, which accepts a numerical input from 1 - 7, as it is initialized with 0, you have to enter a number from 1 - 7 or you get a "nasty message" related to your error.  It also has a random choice of congratulatory phrases, after you do correctly enter a number from 1-7, and press the OK button.  I have a Bitmap image, a sound wave, and a midi file to play, for each of the 7, these are accessed via menu and toolbar.  As far as 'Frames', I do have the one MainFrame object as displayed, and I have the 7 ChildFrames, Tab style, and one document per child frame.  So only 7 documents, after they are used, then you have to close the program, then you can start again with a new set of "players", i.e. documents.  It is done by design to keep the readings random enough just to be scary.
So I should be in the MainFrame to work with the 1-7 child frames, yes?  
void CChildFrame::OnViewQuestionview()
{
	CCreateContext context;
	context.m_pCurrentDoc = (CTCPGDoc*)GetActiveDocument();
	context.m_pCurrentFrame = this;
	context.m_pLastView = GetActiveView();
	context.m_pNewViewClass = RUNTIME_CLASS(CQuestionView);
	CreateView(&context, IDR_QUESTIONVIEW);// Maybe I should use the form view ID, ... e.g. IDD_QUESTION_FORM
//IDR_QUESTIONVIEW HOLDS THE RESOURCES for the menu, icon, toolbar, and accelerator, but not the IDD, but I can change the IDD to IDR and then maybe it will work that way ... 
	LoadFrame(IDR_QUESTIONVIEW, WS_CHILD | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | FWS_ADDTOTITLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, GetParent(), &context);
//I get the error below, and it points to a file that doesn't seem to exist, or IF it did, then it was when CPU's were 16bit i386, I had a i486DX50, a true 32 at the time, as it is looking for a file name 'winmdi.cpp', the entire code of which, has probably been moved in it's entirety to a differently named file and of course has been modified past being recognizable as backwards compatibility.  
	//mfc140ud.i386.pdb contains the debug information required to find the source for the module mfc140ud.dll
	//winmdi.cpp is the evil culprit.  i386 is so old, no wonder there is a problem.  What about i686?
	this->ActivateFrame(SW_SHOW);
        ShowWindow(SW_SHOW);
}

Open in new window

AS to the error it is a mystery, as I have unchecked or cleared all of the Exception Settings, and still get unknown ...
0
Donald P. HutchinsWormhole DiscovererAuthor Commented:
This last bit is what I have been trying.   I have dropped this one for now as well.  I will try again, later, and put the view members and their Create in the appropriate class, either CDoc or CChild.  I just is frustrating that I think I got it done then bam ... and as you last bit of help didn't have a Best answer button I chose My last one in order to close it.
0
Donald P. HutchinsWormhole DiscovererAuthor Commented:
While Sara seems fairly knowledgeable about C++, she didn't quite seem to grasp what I had already done, to get to the point I had specifically.   Maybe her installation works better than mine, I am not sure.  I just sometimes get weird intelisense, or it compiles fine, yet errors during the execution popup referencing the .dll  when I do as suggested, and then she was not specific as to which class, the Child window class or the Document class, where these view member would be tolerated to be constructed and created so they could be added into the AddView function in the document class.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.