Link to home
Start Free TrialLog in
Avatar of ris
ris

asked on

Tabstops

I have a tricky situation in my program.  I have a dialog (implemented with a CFormView-derived class) with some normal controls on it as well as a special embedded property sheet (implemented with a CPropertySheet-derived class and a set of CPropertyPage-derived classes).

I have to do it this way because I dynamically change the pages in the property sheet throughout the life of the dialog and it is much easier to use a property sheet embedded as a child window to an invisible static control on the dialog and add and remove pages on it than it would be to manually implement a tab control and dynamically add and remove controls individually.  It would be a lot more code to maintain too.

The embedded property sheet method was relatively straight-forward to implement and I have it all working just how I would like, except for the tab stops.  I have a couple of problems with the tabstops.

The main thing is that the dynamic addition of the property sheet OnInitialUpdate of the dialog in which it is embedded leaves it in a state such that there are two separate tabstop chains: one for the dialog, and one for the property sheet and its pages.  If I tab-around on the dialog, it just skips past the property sheet, its pages, and its controls.  If I tab-around the property sheet, it never moves the focus away back to the dialog controls.  Everything that I want to have a tabstop has one and they pretty much work, but there are these two separate chains of tabstops.  How can I merge these chains?  I am willing to consider any and all options.

My other problem with the tabstops is minor in comparison: I have a text edit control (implemented with a CEdit-derived class) which captures the tab character as text.  I overrode the PreTranslateMessage function in my CEdit-derived class so that it inserts the tab character '\t' into the text of the control instead of changing the input focus.  This "tab capturing" feature may be turned on and off, but when it is off it doesn't function correctly as the input focus changing mechanism that I would expect.  It doesn't appear to do anything.  Below is my code (for this feature only - not for the rest of the tabstop stuff above) please tell me what I can do to change it so that if the feature is turned off, the tab key will move the input focus instead of doing nothing.  I considered calling SetFocus directly from here, but I couldn't figure out how to tell what the next control is in the tab order, other than by hard-coding it to a specific control, but that would make it harder to update and maintain so I'd rather not do that.

class CCodeEdit : public CEdit;

BOOL CCodeEdit::PreTranslateMessage(MSG* pMsg)
{
    //allow tab characters to fall through to the edit text
    if ((pMsg->message == WM_KEYDOWN) && 
        (pMsg->wParam == VK_TAB) && 
        m_pPrefs->Get_bCaptureTabsInCodeEdits())
    {
        //add the TAB character to the control
        ReplaceSel("\t", TRUE);
        //no need to do a msg translation, so quit.
        //that way no further processing of this message will be done
        return TRUE;
    } //end if (inserting tab)

    return CEdit::PreTranslateMessage(pMsg);
} //end PreTranslateMessage()
ASKER CERTIFIED SOLUTION
Avatar of migel
migel

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of DanRollins
migel,
Are you sure about your suggestion for (2)?  The code you posted will never give the base class a chance to do PreTranslateMessage for tab keystrokes.  It seems to me that you want to let the base class do its normal handling...

if ((pMsg->message == WM_KEYDOWN) &&(pMsg->wParam == VK_TAB))
{
    if (m_pPrefs->Get_bCaptureTabsInCodeEdits()) {
        ReplaceSel("\t", TRUE);
    }
    return TRUE; // never *ever* give a chance the CEdit?
}
-==-=-=-=-=-=-=-=-=-=-=-=-=--==-
ris,
I have read many Qs here at EE describing problems that occur when a CPropertySheet is used as a child window.  And when I tried it, I hit enough snags that I shelved the idea.

When I needed to implement a CPropertySheet that changes pages dynamically, I did it quite easily by making calls into my cSheet to remove and add pages to meet the current requirements.  I also added a logo and some additional buttons and a combobox to the cSheet without sweating too hard.

-- Dan
Avatar of migel
migel

oops
not sure at all (:-))
can you use this code?
//error check stripped.
CWnd* pNextCtrl = GetParent()->GetNextDlgTabWindow(this, GetKeyState(VK_SHIFT)<0);
pNextCtrl->SetFocus();
Avatar of ris

ASKER

1) I tried adding the WS_EX_CONTROLPARENT style to all of my applicable windows: the property sheet, and the dialog templates for each of the property pages as well as for the form view that contains the embedded property sheet.  However, when I call CPropertySheet::Create() with this style, it freezes up my program somehow, or it gets into some kind of infinite looping or infinite messaging back and forth or something.  I can step into the MFC code and find that it hangs on the call to PropertySheet(), which is an API function that I can't step into so I don't know why it hangs.  Any thoughts?  My property sheet create call looks like this:

//m_pParamPropSheet is of a derived class from CPropertySheet
//m_ParamPropsheetPlaceholder is of a class derived from CStatic
m_pParamPropSheet->Create(&m_ParamPropsheetPlaceholder, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT)

2) I tried the code that was like this, with comments indicating what occurs:

CWnd* pParent = GetParent();
//pParent now points to the property page that contains the CCodeEdit control
CWnd* pNextCtrl = pParent->GetNextDlgTabWindow(this, GetKeyState(VK_SHIFT)<0);
//the code edit control is the only control on the property page, so pNextCtrl now points to 'this'
//this already has the focus
//so the following SetFocus call does essentially nothing
pNextCtrl->SetFocus();

It must be mentioned that the only way I could test this was to remove the WS_EX_CONTROLPARENT style from the property sheet (so that it would initialize instead of having the problem I mentioned above) which I think prevents it from getting that far.  What I don't understand is why the call to GetNextDlgTabWindow doesn't get the tab control of the property sheet.  Any thoughts on this?
Avatar of ris

ASKER

Oh sorry, I forgot to correct the type in the example code.  The MFC function call involved is not GetNextDlgTabWindow, it is GetNextDlgTabItem.
Avatar of ris

ASKER

After much tweaking, I was able to get it working.  Ultimately, I had to set the WS_EX_CONTROLPARENT style OnInitDialog of my property sheet and in the dialog template resource for the dialog in which the property sheet is embedded.  I also had to mess with my windows' parent/child relationships so that the static control placeholder for the embedded property sheet was not in the parent/child chain.  I had to do that so that the property sheet's parent was the dialog which is the one that is supposed to receive the messages for that tab key and other mnemonics.  This also had the fortunate side effect of fixing another problem I had which was that if the focus was in one of my property pages, none of the mnemonics on the dialog would respond, and now I understand why.  With this CONTROLPARENT issue taken care of, the special edit control issue inherited the repair, so calling CEdit::PreTranslateMessage() started working as I expected it to.

I'm awarding the points to migel for bringing up the WS_EX_CONTROLPARENT style flag as well as for bringing up the GetNextDlgTabItem() function (though I didn't use it in the final solution) which was something I asked for in my original question.  Dan, I really appreciate your help too.

Thank you both for your assistance!
Hm
 I`m so confused... Excuse me Dan...