Solved

MDI child frame without a close button

Posted on 1998-05-26
12
1,077 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
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
Optimizing Cloud Backup for Low Bandwidth

With cloud storage prices going down a growing number of SMBs start to use it for backup storage. Unfortunately, business data volume rarely fits the average Internet speed. This article provides an overview of main Internet speed challenges and reveals backup best practices.

 

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 100 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

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

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

Suggested Solutions

Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
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.
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

809 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