Linking a CFrameWnd class to a resource


I am aware that what I am about to ask is vague, but once i get a push in the right direction, I can start to be more specific.

My situation is that I am continuing someone else's project.
The code that opens the main window of the application is done in a way I've never used before, and so am confused about.

It is :

      CMainFrame* pFrame = new CMainFrame();
      m_pMainWnd = pFrame;

      pFrame->LoadFrame(IDR_MAINFRAME,
            WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,
            NULL);

      pFrame->ShowWindow(SW_SHOW);
      pFrame->UpdateWindow();

and this occurs in the InitInstance() method, where CMainFrame is derived from CFrameWnd.

Am i correct in saying that this window is being created on the fly, using the IDR_MAINFRAME toolbar resource only.

Let's say I want to edit this window, add some buttons, change its look and so on.
Up until now I have only done this through editing the resources directly. Since this dialog doesn't exist in the ResourceView, how can I do this?


Cheers for any ideas.
pikcoAsked:
Who is Participating?
 
AndyAinscowConnect With a Mentor Freelance programmer / ConsultantCommented:
You have created a frame, not a dialog.  What I am saying is that when the frame is created you create a dialog (as you would a modeless dialog) and have the parent of the dialog your frame and it is positioned inside the frame to fill the client area.  I would suggest creating this child dialog in the OnCreate of the frame (delete the pointer to the dialog in the destructor of the frame to prevent memory leaks).

eg.  (very roughly)
in header for the frame
CMyDlg* m_pMyDlg;  //CMyDlg is the dialog class you want in the frame

in the .cpp file

int CMyFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
      if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
            return -1;
      
      m_pMyDlg= new CMyDlg(this);
      if (!m_pMyDlg->Create(this,
            WS_CHILD | WS_VISIBLE, 0))
      {
            delete m_pMyDlg;
            m_pMyDlg= NULL;
            return -1;
      }

//the following may need some tweaking to get it sized correctly
      CRect rectClient, rectWindow;
      m_pMyDlg->GetWindowRect(rectWindow);

      SetWindowPos(NULL, 10, 10,
            rectWindow.Width()+20, rectWindow.Height()+20,//20 is just a fudge, you ought to allow for borders, titlebar...
            SWP_NOZORDER | SWP_NOACTIVATE);

      GetClientRect(rectClient);
      m_pMyDlg->SetWindowPos(NULL, 0, h,
            rectClient.Width(), rectClient.Height(),
            SWP_NOZORDER | SWP_NOACTIVATE);

return 0;
}

It may
0
 
Jaime OlivaresSoftware ArchitectCommented:
>Am i correct in saying that this window is being created on the fly, using the IDR_MAINFRAME toolbar resource only.
Yes, you are, it looks like it is not a doc/view architecture project.

>Let's say I want to edit this window, add some buttons, change its look and so on.
This must be done inside CMainFrame implementation (mainfrm.cpp), because this window it is NOT associated with any graphical template like dialog do.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
I suspect inside the frame a dialog will be created dynamically (eg in the OnCreate of the Frame).  It is this dialog resource you need to edit and add buttons and other controls to.
0
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

 
pikcoAuthor Commented:
thanks for your replies..

so Jaime, does that mean that I need to add buttons etc. in code?
is this easy to do?
0
 
jimbucciCommented:
In OnCreate() you can do pretty much anything you want to change the look of the window.  
I would suggest using PreCreateWindow() if you want to set the system properties of the window - like the close button and the minimize/maximize buttons.  You can also remove the menu here - at least that's what I do.

Since you are not using a dialog resource to create a view inside the mainframe then you will have to add buttons manually.  You can also modify/add toolbars here.

Jim
0
 
pikcoAuthor Commented:

ahhh, okay, so where can i find out how to add buttons manually?
0
 
jimbucciCommented:
The easiest way is to add some CButton objects to your CFrameWnd derived class then create them in OnCreate().
Call CButton::Create(...) then if need be call MoveWindow() for the buttons.  You will need an event handler for each button.

Sometimes it's just easier to create a view class then create the view and place it into the frame.
Jim
0
 
Jaime OlivaresConnect With a Mentor Software ArchitectCommented:
in mainfrm.h:

class CMainFrame : public CFrameWnd
{
      // some members
   
      CButton m_Button1, m_Button2, etc...

      // some functions

      void OnClicked1();
      void OnClicked2();    // Buttons event handlers
}

in mainfram.cpp:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
      //{{AFX_MSG_MAP(CMainFrame)
      ON_WM_SIZE()
      ON_WM_CREATE()
      //}}AFX_MSG_MAP
      ON_NOTIFY(BN_CLICKED, ID_BUTTON1, OnClick1)   // <---- Add those events manually
      ON_NOTIFY(BN_CLICKED, ID_BUTTON2, OnClick2)
END_MESSAGE_MAP()

CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
       // Some code

       CRect rect(0,0,1,1);   // dummy values
       m_Button1.Create(WS_CHILD|WS_VISIBLE, rect, this, ID_BUTTON1  );
       m_Button2.Create(WS_CHILD|WS_VISIBLE, rect, this, ID_BUTTON2  );
}

CMainFrame::OnSize(UINT nType, int cx, int cy)
{
       // Some code

       // You can make your controls to resize, according to frame size

       m_Button1.MoveWindow(CRect(10,10,cx-20,25);
       m_Button2.MoveWindow(CRect(10,40,80,55);
}

// add these handlers manually

void CMainFrame::OnClicked1()
{
    // some action here
}

void CMainFrame::OnClicked2()
{
    // some action here
}
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
I would still put a dialog into the frame - no need to do the controls in code, you do them in the resource editor as you would any other dialog.

Just have a member var that is a pointer to the dlg, in the OnCreate of the frame use new to create a new dialog then create.
0
 
pikcoAuthor Commented:
AndyAinscow:

That sounds like exactly what I should do, since its probably faster to do than in code.
I'm still not sure how to do it yet though.

Since it alraedy creates a dialog on the fly, does this mean it will open up two if I do this?

Thanks for your replies also.
0
 
pikcoAuthor Commented:

Hey, thanks for that reply.
I think its getting warmer now, using that idea my main dialog now opens up to be the same size as the CMyDlg class dialog, however, I still can't see any of the things I add in the resource editor. what could i be forgetting?
0
 
jimbucciConnect With a Mentor Commented:
Basically that's what the CFormView class does - you create a dialog resource for the view then pull the view into your frame.  When you create a MFC application with doc/view architecture that's what the wizard does.
Here' some code:

BOOL CMyFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
   if (!CFrameWnd::OnCreateClient(lpcs, pContext))
        return FALSE;
   
    // Create the view (with no document)
    CCreateContext sContext;
    sContext.m_pNewViewClass    = RUNTIME_CLASS(CMyFormView);
    sContext.m_pCurrentDoc      = NULL;
    sContext.m_pNewDocTemplate  = NULL;
    sContext.m_pLastView        = NULL;
    sContext.m_pCurrentFrame    = this;

    m_pFormView = (CMyFormView*) CreateView(&sContext);

    if(!m_pFormView)
        return FALSE;

    SetActiveView(m_pFormView);
    ShowOwnedWindows(TRUE);

    m_pFormView->SetFocus();
    m_pFormView->UpdateWindow();
   
    return TRUE;
}

You add a new MFC class derived from CFormview.  You will then be placed into the resource editor for the dialog resource you will use for the formview.

I hope this helps
Jim
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
m_pFormView->ShowWindow(SW_SHOW);

does that help?
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
Your form view is based on the dialog isn't it?
0
 
jimbucciCommented:
Calling ShowWindow() is not necessary because of the call to ShowOwnedWindows().

CFormviews are CView classes based on a dialog resource - similar to VB forms.  You can pop them in and out like CViews and they can be used in splitters.  I use them quite a lot.

Jim

0
 
pikcoAuthor Commented:
Yeah, ShowWindow() opens up the original dialog as well as the new dialog.

Jim, would this work in my case,

sContext.m_pNewViewClass    = RUNTIME_CLASS(CMyFrame);   doesn't seem to like my class

SetActiveView(m_pMyDlg);    the method is looking for a CView?

I'm not sure what CMyFormView in your example is, is it a class derived from a dialog?


Thanks.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
pikco - you are getting a mix of my idea and that from jimbucci.

I am suggesting a modeless child DIALOG inside your frame.  The other is a CFormView based view inside the frame.
Please post some code so we know what you are doing.

0
 
jimbucciCommented:
CMyView is a CFormView derived class.  The sContext.m_pNewViewClass requires a CView derived class - placing the frame in their would probably just fail.  SetActiveView requires a CView derived class.

All of the code I provided is for using a CView derived class with a CFrameWnd derived class.  The MFC framework handles a lot of the placement and creation of the windows for you - although you can still set the size of the view as you wish.

Using a dialog as a child to a frame window would work just fine - the fact is that I've never done it.  Using the MFC frame-view type of UI seemed easier to me.  

The best way to try what I suggest is to create a new project and where you select the type of view class select CFormView.  You will then be presented with the resource editor for the dialog.  If you run the program your dialog resource will show in the view.  Looking at the code should reveal how the view gets inside the frame.

Jim

0
 
pikcoAuthor Commented:
Andy:

My code at the moment is pretty similar to what you suggested earlier:

    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
          return -1;
     
     m_pMyDlg= new CMyFrame(this);

      
     if(!m_pMyDlg->Create(NULL,NULL,WS_CHILD | WS_VISIBLE,CRect(0,0,0,0),this,NULL))
     {
          delete m_pMyDlg;
          m_pMyDlg= NULL;
          return -1;
     }

//size later
     CRect rectClient, rectWindow;
     m_pMyDlg->GetWindowRect(rectWindow);

     SetWindowPos(NULL, 10, 10,  rectWindow.Width()+20, rectWindow.Height()+20,//check later          SWP_NOZORDER | SWP_NOACTIVATE);

     GetClientRect(rectClient);
     m_pMyDlg->SetWindowPos(NULL, 0, 0,
          rectClient.Width(), rectClient.Height(),
          SWP_NOZORDER | SWP_NOACTIVATE);


At the moment it will open up the dialog as before, at the same size as the CMyFrame dialog.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
from help

CDialog::Create
BOOL Create( LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL );

BOOL Create( UINT nIDTemplate, CWnd* pParentWnd = NULL );


Is your m_pMyDlg based on a CDialog derived class?
 
0
 
Jaime OlivaresSoftware ArchitectCommented:
I think you was in the right way when presenting on a CFrameWnd.
0
 
pikcoAuthor Commented:
Andy:

Yeah, interesting about that, my class definitely is derived from CDialog:

CMyFrame::CMyFrame(CWnd* pParent /*=NULL*/)
      : CDialog(CMyFrame::IDD, pParent)
{   etc......

When i use the classwizard to get the Create method, i get:

BOOL CMyFrame::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
      // TODO: Add your specialized code here and/or call the base class
      
      return CDialog::Create(IDD, pParentWnd);
}

0
 
AndyAinscowFreelance programmer / ConsultantCommented:
I am really confused as to what is what in your app.  Please check the header, you should have something like
class CMyFrame : public CDialog
0
 
pikcoAuthor Commented:
Yes, in the header:


/////////////////////////////////////////////////////////////////////////////
// CMyFrame dialog

class CMyFrame : public CDialog
{
// Construction
public:
      CMyFrame(CWnd* pParent = NULL);   // standard constructor

etc.........
0
 
pikcoAuthor Commented:
What I wrote before was from the .cpp file.
0
 
pikcoAuthor Commented:
Is it fair for me to close this question off?
I haven't really received any ideas that have worked.
Any objections let me know ;)
0
 
Jaime OlivaresSoftware ArchitectCommented:
Does my idea have not worked? Apparently using a dialog template could be simpler, but you have verified this is not necessarily true. When you work with a frame window, it is better to make controls directly as childs, in my opinion.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
This advice may be of help.  It really depends on how much was done by your colleague before you took the app over.

Ask yourself the following questions.
Do I need a toolbar?
Do I need a menu?
Do I need a statusbar?
Will I be using accelerators? (Press alt+A and it acts as if you had pressed a button for example)

If the answers are no then create a new dialog based project.
If an answer is yes then create a new SDI, modify settings as required (KEEP doc/view) and at the final stage change the CView to CFormView.  That will create a dialog resource that you can use the resource editor to add buttons ... to.

A bit of info maybe you don't know.  The dialog based app does NOT automatically provide support for some user interface updating and actions the way a SDI/MDI based project does.  Doing the above will mean you have less to code if you did require one of those features in your app.
0
 
pikcoAuthor Commented:
It doesn't really help, but thanks for the advice anyway. I've chosen to just continue workign on top of the old interface.

I think best thiing for me to do is award points across the 3 of you for being so nice and helping.
On an aside, If any of you three want to point me in the direction of some good garbage collection tips or classes that do it for you if such things may exist, that would be nice too.

=)
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
I don't like garbage collection in general - A memory leak tells me I haven't got the logic correct.
0
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.

All Courses

From novice to tech pro — start learning today.