Solved

Linking a CFrameWnd class to a resource

Posted on 2004-08-03
30
1,225 Views
Last Modified: 2013-11-20

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.
0
Comment
Question by:pikco
  • 11
  • 10
  • 5
  • +1
30 Comments
 
LVL 55

Expert Comment

by:Jaime Olivares
Comment Utility
>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
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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
 

Author Comment

by:pikco
Comment Utility
thanks for your replies..

so Jaime, does that mean that I need to add buttons etc. in code?
is this easy to do?
0
 
LVL 3

Expert Comment

by:jimbucci
Comment Utility
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
 

Author Comment

by:pikco
Comment Utility

ahhh, okay, so where can i find out how to add buttons manually?
0
 
LVL 3

Expert Comment

by:jimbucci
Comment Utility
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
 
LVL 55

Assisted Solution

by:Jaime Olivares
Jaime Olivares earned 133 total points
Comment Utility
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
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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
 

Author Comment

by:pikco
Comment Utility
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
 
LVL 44

Accepted Solution

by:
AndyAinscow earned 134 total points
Comment Utility
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
 

Author Comment

by:pikco
Comment Utility

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
 
LVL 3

Assisted Solution

by:jimbucci
jimbucci earned 133 total points
Comment Utility
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
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
m_pFormView->ShowWindow(SW_SHOW);

does that help?
0
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
Your form view is based on the dialog isn't it?
0
 
LVL 3

Expert Comment

by:jimbucci
Comment Utility
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
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:pikco
Comment Utility
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
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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
 
LVL 3

Expert Comment

by:jimbucci
Comment Utility
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
 

Author Comment

by:pikco
Comment Utility
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
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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
 
LVL 55

Expert Comment

by:Jaime Olivares
Comment Utility
I think you was in the right way when presenting on a CFrameWnd.
0
 

Author Comment

by:pikco
Comment Utility
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
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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
 

Author Comment

by:pikco
Comment Utility
Yes, in the header:


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

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

etc.........
0
 

Author Comment

by:pikco
Comment Utility
What I wrote before was from the .cpp file.
0
 

Author Comment

by:pikco
Comment Utility
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
 
LVL 55

Expert Comment

by:Jaime Olivares
Comment Utility
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
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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
 

Author Comment

by:pikco
Comment Utility
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
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
I don't like garbage collection in general - A memory leak tells me I haven't got the logic correct.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now