How should I create controls on my dialog box that has a tab control?

Raymond Chen

Raymond

The tab control from the shell common controls provides the tab selector control that is popular in tabbed dialogs. You’d be tempted to create the content of the tab control’s display area as children of the tab control, but that’s the wrong thing to do.

You should create them as siblings of the tab control.

What you want to do is create your tab control to cover the portion of the dialog box that you want to be tabbed. You then use the TCM_ADJUST­RECT message (or the equivalent TabCtrl_AdjustRect macro) to determine the display area of the tab control. Inside that display area, you can place your content, but do it with the dialog box as the parent, not the tab control.

 Dialog 
  
    
Tab control Content 1 Content 2

Depending on which tab in the tab control is selected, you show exactly one of the content windows and hide the others.

If you think about how focus works in dialog boxes, you’ll realize that it has to be this way.

The tab control itself is focusable, and presumably you want to be able to put focus on your content, too. Now consider what happens if you create the content as children of the tab control:

 Dialog 
  
 Tab control 
  
      
 Content 1 Content 2 

By default, the tab order in a dialog box follows the dialog box’s immediate children. In this case, it means that the tab control can receive focus, but the content cannot, since they are not immediate children of the dialog box.

You can alter this behavior with the WS_EX_CONTROL­PARENT extended window style, which means “I’m just a container. My children are the things that can get focus, not me.” So let’s try that and put the WS_EX_CONTROL­PARENT extended window style on the tab control.

 Dialog 
  
 Tab control 
  
      
 Content 1 Content 2 

This time, the tab control drops out of the tab order, and its children, the content controls, join in.

With this window hierarchy, no amount of fiddling with the WS_EX_CONTROL­PARENT extended window style will allow the tab control and its children to all be part of the tab order. Because a window and its children cannot both be part of the tab order.

The only solution is to move the content controls out, so they aren’t children of the tab control. Making them siblings of the tab control, as they are in the original diagram, allows all three to participate in the tab order.

Bonus chatter: The content windows are typically nested dialogs which are marked with the WS_EX_CONTROL­PARENT extended window style. This permits the children of the nested dialogs to participate in the tab order, but keeping them inside a nested dialog lets you hide and show the controls in bulk by hiding and showing the nested dialog.

Raymond Chen
Raymond Chen

Follow Raymond   

5 comments

Comments are closed.

  • skSdnW
    skSdnW

    Why does WS_EX_CONTROL­PARENT block the ability to join the tab order? You can already toggle that with WS_TABSTOP. It would just go: “Whatever” -> Container ->First child.

    • Avatar
      Kalle Niemitalo

      In the “How to Create a Tab Control in the Main Window” sample, the child window of the tab control is a static control, so it would not receive the focus; and the tab control is not in a dialog box, so nobody calls IsDialogMessage and keyboard navigation won’t work anyway. It is somewhat misleading, though.
      In the “How to Create a Tabbed Dialog Box” sample, the OnSelChanged function creates the child dialog as a child window of the main dialog, not as a child window of the tab control.
      Windows Forms appears to implement keyboard navigation on its own, in ContainerControl.ProcessDialogKey.

  • Avatar
    Neil Rashbrook

    A third-party GUI builder I used to use would automatically create both an outer parent control that contained the tab control plus all of the panes as separate nested dialogs, which also allowed you to think of the entire tab control as its own window as well.

  • Avatar
    jasondbs@hotmail.com

    I just used WS_EX_CONTROL­PARENT to join a nested dialog into a parent one.
    The tab order works great, alt keys work as well.
    However, buttons in the nested dialog now don’t respond to the Enter Key. (when the tab focus is on them)
    Without WS_EX_CONTROL­PARENT they respond correctly.
    Hitting the Space bar on the button does work, enter does not.
    How to address that?