?
Solved

MDI child frame without a close button

Posted on 1998-05-26
12
Medium Priority
?
1,131 Views
Last Modified: 2013-11-20
I'm new to MFC and Windows programming, making the leap from DOS (a dark screen with a C:\>, remember?)

Can I create an MDI child frame that does not have a close button. I do not want the user to be able to close the first child window opened when the program starts. I've played around with the ::LoadFrame(), ::Create(), and ::PreCreateWindow() member functions of the CChildFrame class to no avail. I've tried various combinations of the WS_XXXX bits in the frame styles, but haven't hit the correct one. Is this possible in MFC?

Note that I also have to get rid of the Close option from the Windows system menu.

Thanks,
Nelson Chenkin
0
Comment
Question by:nchenkin
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
12 Comments
 
LVL 15

Expert Comment

by:Tommy Hui
ID: 1315335
No, it is possible. But you can do the next best thing by trapping WM_SYSCOMMAND in the child frame and if the number of child windows is 1 (meaning it is the first), then ignore the command if the wparam has SC_CLOSE in it:

  void MyWnd::OnSysCommand(wp, lp)
  {
    BOOL ignore = FALSE;
    if (count == 1)
      if ((wp & SC_CLOSE) == SC_CLOSE)
        ignore = TRUE;
    if (!ignore)
      CChildFrame::OnSysCommand(wp, lp);
  }


   
0
 

Expert Comment

by:t004024
ID: 1315336
GetSystemMenu, gives a handle to the system menu. Maybe U can get this and manipulate the menu using the CMenu class functions. U need to call the GetSystemMenu for the MainFrame window. SO Maybe U could do something like
CMenu *tMenu = AfxGetMainWnd()->GetSystemMenu() and then call
tMenu->RemoveMenu(SC_CLOSE, MF_BYCOMMAND); and then call maybe
CMDIChildWnd *ptWnd = GetParent() // This is only if U are in the View class otherwise, call MDIGetActive of the CMDIFrameWnd and call the SetSystemMenu and RemoveMenu for this.
0
 

Expert Comment

by:footloose
ID: 1315337
***** The standard code generated by MFC for CChildFrame contains this override:

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
     // TODO: Modify the Window class or styles here by modifying
     //  the CREATESTRUCT cs

     return CMDIChildWnd::PreCreateWindow(cs);
}

***** Change it as below:

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
     cs.style &= ~WS_SYSMENU;
     cs.style |= WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
     return CMDIChildWnd::PreCreateWindow(cs);
}

***** This gets rid of the system menu but retains the minimize/maximize buttons.
***** As THUI suggested, you need to override WM_SYSCOMMAND handler as below.
***** WM_SYSCOMMAND may not appear on the standard message list, so you will
***** have to go to the CLASSINFO tab of class wizard (for CChildFrame), change
***** MESSAGE FILTER option to WINDOW, and then go back to MESSAGE MAPS tab
***** and override WM_SYSCOMMAND handler as below:

void CChildFrame::OnSysCommand(UINT nID, LPARAM lParam)
{
     if ( nID == SC_CLOSE )
     {
          //do some checking, as THUI suggested and/or call the default
     }
     CMDIChildWnd::OnSysCommand(nID, lParam);
}

***** Also remember to go to IDR_appTYPE menu on the resource editor and get rid of
***** FILE/CLOSE menu item.
0
Learn how to optimize MySQL for your business need

With the increasing importance of apps & networks in both business & personal interconnections, perfor. has become one of the key metrics of successful communication. This ebook is a hands-on business-case-driven guide to understanding MySQL query parameter tuning & database perf

 

Author Comment

by:nchenkin
ID: 1315338
Footloose,

I tried as you suggested in the ::PreCreateWindow() function. However this got rid of ALL three buttons: the minimize and maximize buttons were not displayed. I could still maximize the child by double clicking on the title bar, and then use Window/Cascade to restore it, but the buttons weren't there. This was one of the things I stumbled on in my attempts.

By the way, to ensure nothing else had changed I did this in newly generated App Wizard code.

Thanks,
nchenkin
0
 

Author Comment

by:nchenkin
ID: 1315339
Adjusted points to 100
0
 

Expert Comment

by:Beatachon
ID: 1315340
Does the window still have the normal looking title bar? Make sure you have your operators right. I.E: cs.style |= and NOT cs.style =.....
0
 

Author Comment

by:nchenkin
ID: 1315341
The title bar looks normal execpt the system menu icon on the left is gone and there are no buttons at all on the right.

Here's the code lifted from the file. Again, this is the only change to a new App Wizard app using all defaults.

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
   // TODO: Modify the Window class or styles here by modifying
   //  the CREATESTRUCT cs

   cs.style &= ~WS_SYSMENU;
   cs.style |= (WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
   return CMDIChildWnd::PreCreateWindow(cs);
}


0
 

Expert Comment

by:footloose
ID: 1315342
duh! how come I missed the missing minimize/maximize boxes!! Sorry! Will keep trying.
0
 

Accepted Solution

by:
footloose earned 200 total points
ID: 1315343
OK, let's try again: t004024's earlier suggestion on using GetSysMenu works. I tried this out, and the close button is disabled. Thui's earlier suggestion to trap WM_SYSCOMMAND still has to be carried out if you want to prevent Ctrl-F4 from closing the child window.

Override CChildFrame::Create as below:

BOOL CChildFrame::Create(  LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
                                                     DWORD dwStyle, const RECT& rect,
                                                     CMDIFrameWnd* pParentWnd, CCreateContext* pContext )
{
   if ( CMDIChildWnd::Create( lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd,
                                                    pContext ) )
   {
      CMenu *p = GetSystemMenu( FALSE );
      p->RemoveMenu( 5, MF_BYPOSITION );
      p->RemoveMenu( 5, MF_BYPOSITION );

      return TRUE;
   }

   return FALSE;
}

0
 

Author Comment

by:nchenkin
ID: 1315344
Footloose, Thanks it worked!

But I wound up combining your suggesstion with t004024's comment. The final code is:

BOOL CChildFrame::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
                         DWORD dwStyle, const RECT& rect,
                         CMDIFrameWnd* pParentWnd, CCreateContext* pContext)
{
   if ( CMDIChildWnd::Create( lpszClassName, lpszWindowName, dwStyle,
                              rect, pParentWnd, pContext ) )
   {
      CMenu *p = GetSystemMenu( FALSE );
      p->RemoveMenu( SC_CLOSE, MF_BYCOMMAND );
      return TRUE;
   }
   return FALSE;
}

This gets rid of having to call RemoveMenu twice as your example required (why is that?!),
and also changes the hardcoded '5' to a friendlier SC_CLOSE symbol.

I realize I also need to implement Thui's trap.
Thanks all for your help.
0
 

Expert Comment

by:footloose
ID: 1315345
Final comment: RemoveMenu is called twice because you have to remove CLOSE first and then the seperator below it. Otherwise you get two seperators one next to another.
0
 

Author Comment

by:nchenkin
ID: 1315346
Footloose, A final comment to your final comment:

Gotcha. Given that, I'll probably put the 2nd call back in to get rid of the seperator.
Thanks for the clarification.
0

Featured Post

Get MongoDB database support online, now!

At Percona’s web store you can order your MongoDB database support needs in minutes. No hassles, no fuss, just pick and click. Pay online with a credit card. Handle your MongoDB database support now!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
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.
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
Suggested Courses

770 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