Access MFC edit controls within a CFormView

I have an dialog based application that uses PropertySheets and PropertyPages. There is 1 PropertySheet and the 29 PropertyPages (dialogs) are children of the Sheet. On one of the pages, I have a scrollable CFormView that shows a dialog created visually. I can access the data from the edit controls by just calling UpdateData() and then just retreiving data from the variables. My problem is that I want to mask certain edit controls using Subclass. And I have not been able to access them using a GetDlgItem( {IDENTIFIER} ); I have tried comparing the CDC pointer from the OnDraw(CDC*) to a pointer I retrieve from the DC that I try to get using:
CDC *mDC = pWnd->GetDC();
if (mDC == pDC) {
    HWND hwnd = pWnd->GetSafeHwnd();
    SPMaskEdit m_maskEdit;
    m_maskEdit.SubclassWindow(hwnd);
    m_maskEdit.setMask("###.#");
}
But it never evaluates as true. I am assuming that maybe pDC is just a temp DC and not pointing to the actual control.
The SPMaskEdit class is just used to mask the edit control so that the entry will only allow values in the form of '300.2'. If there is a better way of doing this better than trying to retreive the CWnd* and then modify it that way please let me know.
The dialog for the form is directly attached to the CMyFormView class and not to a document that is then added to the view.
krissandersAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

DexstarCommented:
krissanders:

> CDC *mDC = pWnd->GetDC();
> if (mDC == pDC) {
>     HWND hwnd = pWnd->GetSafeHwnd();
>     SPMaskEdit m_maskEdit;
>     m_maskEdit.SubclassWindow(hwnd);
>     m_maskEdit.setMask("###.#");
> }
> But it never evaluates as true. I am assuming that maybe pDC is just a temp
> DC and not pointing to the actual control.

You are comparing pointers to CDC objects, not actual Device Context handles.  I'm not even sure that you really want to be doing that, but if you are, then you need to get the HDC values out of the CDC classes and compare them.

     if ( mDC->m_hDC == pDC->m_hDC )

I'm not even sure why you are comparing DC's like that, but at least you're comparing the right values.  Why do you want to compare DC's?

Hope That Helps,
Dex*
0
krissandersAuthor Commented:
Thanks for the responce. Although that has not solved the problem. The reason that I am comparing the DCs in this case is that the OnDraw(CDC *pDC); is the function where I am trying to gain access to the edit control. I know the IDC_* of each of the edits that I want to mask and was doing:
void CMyFormViewView::OnDraw(CDC* pDC)
{
//      CMyFormViewDoc *pDoc = (CMyFormViewDoc*)GetDocument();
      CRect rect;
      GetClientRect(rect);

      GetTempFields();                // populates a vector that contains all of the IDC_EDIT* for the edit controls that I want to mask
      for (int i=0; i<37; i++) {      // there are 37 edit controls that I want to mask
            CWnd *pWnd = (CWnd*)maskEdits.back();  // get the window pointer to the edit control
            maskEdits.pop_back();                                // clear the current edit control from the vector
            CDC *mDC = pWnd->GetDC();                    // get the DC of the edit control
            if (mDC->m_hDC == pDC->m_hDC) {          // check to see if the item to be drawn is the edit control that I want to mask
                  HWND hwnd = pWnd->GetSafeHwnd();    // if it is, get the handle
                  SPMaskEdit m_maskEdit;                         // create a mask class object
                  m_maskEdit.SubclassWindow(hwnd);       // subclass the window/edit control to the mask object
                  m_maskEdit.setMask("###.#");               // set the mask for the edit control
                  break;                                                    // since the item to be drawn has been masked, break from the loop
            }
            ReleaseDC(mDC);      
      }
      
      CPaintDC dc(this);                    
      dc.SetBkMode(TRANSPARENT);
}

Again, I dont know if the OnDraw function is the best to try to modify the control or not. But my thinking is that it will have been created, I can then modify it, and then it will be draw to the display.
0
DexstarCommented:
Yeah, you don't want to subclass a control like that...  You should do it once, right after the control is created...  Or, in your OnInitDialog handler, get the handle to the control, and then subclass it.  You don't need to keep doing it everytime you want to paint it.  Just do it once, and leave it subclassed.

Dex*
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

krissandersAuthor Commented:
Exactly. The problem is that I am not sure exactly when the control is being created and the CView->CFormView->CMyFormViewView class does not have a OnInitDialog handler even though it controlls a dialog. I don't have much experience with Views and looked around on the web for info on how to implement one inside a propertypage and it worked. Now it is just a matter of accessing the controls within the view's dialog.
0
DexstarCommented:
krissanders:

It's weird that CFormView is based on a dialog resource, but doesn't have OnInitDialog().  Have you tried adding on manually?  Add a handler for WM_INITDIALOG and see if you get the message.

If that doesn't work, then override OnCreate(), and inside, call the base class, and then try and hook up the controls and subclass them.

Dex*
0
krissandersAuthor Commented:
Dex:
  Thanks for the responce. I have tried the OnCreate() and found that it will work for the creation of the view window but does not seem to handle the creation of the controls. I do not have a separate class that the dialog is attached to to override and gain control of the edits. In my formview header there is the line:
      enum { IDD = IDD_MYFORM_DIALOG };
which to my understanding tells the app that the view class will have control of that dialog. But maybe what I should do is create a Document class and then add the document to the view and then just see if I can control within the document class. Please let me know what you think of this idea.

Kris
0
DexstarCommented:
You don't need to create a document class.  There is an easy way to do this, we just need to figure it out.

Inside of your CMyFormViewView::OnCreate function, did you call the base class version of OnCreate BEFORE trying to get the dialog controls?  I think the base class is what sets all of that up, so you need to call that before you can get to the controls.

Then, in your class, you should declare one variable for each control you want to sub-class.  Get the handle to the control, and assign it to that class.

Dex*
0
krissandersAuthor Commented:
Dex:

Yes. What I did was something like this:

// the OnCreate is called by the framework after the Create has taken place but before the window is displayed
int CMyFormViewView::OnCreate(CREATESTRUCT lpCreateStruct) {  // this function is only called 1 time in my app
   int result = CFormView::OnCreate(lpCreateStruct);
   for (int i=0; i<37; i++) { // the maskEdits vector only contains 37 IDDs
      CWnd *pWnd = GetDlgItem(maskEdits[i]);      /* Here is a problem. It is returning NULL */
      if (pWnd != NULL) {
         SPMaskEdit m_maskEdit;                                          // create a mask class object
         m_maskEdit.SubclassWindow(pWnd->m_hWnd);       // subclass the window/edit control to the mask object
         m_maskEdit.setMask("###.#");                                // set the mask for the edit control
       } // end if statement
    } // end for loop
   return result;
}

Now, for some reason it is not able to obtain the CWnd pointer to each of the IDDs of the controls. I think that we are on the right track here. The above should, if the CWnd* is retreived, subclass each of the 37 controls and then return the 0 from the CFormView::OnCreate
0
DexstarCommented:
Okay, I'm not sure what you're doing with SPMaskEdit is going to work because I'm not familiar with that class.  What is it?  Where did you get it?  My concern is that when you destroy the variable after falling out of the for loop, that it will UN-subclass the window.

But, we're getting ahead of ourselves, because you still can't get the CWnd* for the control.  To get past that, here's what I want you to do:
1) Open the dialog IDD_MYFORM_DIALOG in the editor.
2) Select one of the controls that you want to subclass, and get its ID value (I'll assume it is IDC_EDIT1 in my sample, but you should change it to reflect a value actually on the dialog.  This is important).
3) Use this code:
int CMyFormViewView::OnCreate(CREATESTRUCT lpCreateStruct) {  // this function is only called 1 time in my app
   int result = CFormView::OnCreate(lpCreateStruct);

   CWnd* pWnd = GetDlgItem( IDC_EDIT1 );
   return result;
}

Just set a breakpoint on the "return" line, and see if the value of pWnd is NULL or not.  If it is, then OnCreate isn't the right spot to hook up these values.

Dex*
0
freewellCommented:
It is better to handle the controls initilization in  OnActivateView when it is called at first time.

void CMyFormViewView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
    // TODO: Add your specialized code here and/or call the base class
    static BOOL bInit = FALSE;

    if(!bInit)
    {
        bInit = TRUE;

        for (int i=0; i<37; i++) { // the maskEdits vector only contains 37 IDDs
            CWnd *pWnd = GetDlgItem(maskEdits[i]);      /* Here is a problem. It is returning NULL */
            if (pWnd != NULL) {
                SPMaskEdit m_maskEdit;                                          // create a mask class object
                m_maskEdit.SubclassWindow(pWnd->m_hWnd);       // subclass the window/edit control to the mask object
                m_maskEdit.setMask("###.#");                                // set the mask for the edit control
            } // end if statement
        } // end for loop
    }
    CFormView::OnActivateView(bActivate, pActivateView, pDeactiveView);
}
0
krissandersAuthor Commented:
Dex:

I tried that and it is reporting NULL.

Freewell:

The problem that I am having is that the OnActivateView() is not being called. I have tried putting ON_WM_ACTIVATE() in the message map but it is still not calling the routine.
0
DexstarCommented:
It doesn't have to be OnActivateView() ... Try OnShow() ... Try any of them...  Just to see if there is a place where
     CWnd* pWnd = GetDlgItem( IDC_EDIT1 );

Will not return NULL.  Once you have that, we can identify the best place.  But if there is no place where that function will not return NULL, then there is something else wrong.

Dex*
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
freewellCommented:
May be you should try to call your control initialization in CFormView::OnInitialUpdate.
0
krissandersAuthor Commented:
I do get a pointer from within the OnInitialUpdate(). However, upon execute of the code, I get a debug assertion error when the framework calls
HWND CDataExchange::PrepareCtrl(int nIDC)
{
      ASSERT(nIDC != 0);
      ASSERT(nIDC != -1); // not allowed
      HWND hWndCtrl;
      m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
      if (hWndCtrl == NULL)
      {
            TRACE1("Error: no data exchange control with ID 0x%04X.\n", nIDC);
            ASSERT(FALSE);                                                                                    /* app fails here */
            AfxThrowNotSupportedException();
      }
      m_hWndLastControl = hWndCtrl;
      m_bEditLastControl = FALSE; // not an edit item by default
      ASSERT(hWndCtrl != NULL);   // never return NULL handle
      return hWndCtrl;
}

There is another function:
HWND CDataExchange::PrepareEditCtrl(int nIDC)
{
      HWND hWndCtrl = PrepareCtrl(nIDC);
      ASSERT(hWndCtrl != NULL);
      m_bEditLastControl = TRUE;
      return hWndCtrl;
}

This is going just off CWnd *pWnd = GetDlgItem(IDC_EDIT3); On my previous attempt from within this routine I assumed that the control had not yet been initialized
0
krissandersAuthor Commented:
Here is something.. Let me know what you guys think.
I tried the same deal from within the OnPaint(). It will then take that control and not display that single control. All the rest of the edit controls show up normally but the one that was just subclassed. I was able to actually gain control of the edit box.

Here is where I got the SPMaskClass http://www.codeguru.com/editctrl/masked_edit3.shtml
The SubclassDlgItem was giving me a "instruction at memory could not be read" error.
0
krissandersAuthor Commented:
I think that I almost have it working. The edit control is now being drawn and shows the mask. I can only enter 1 number rather than the ###.# it comes out 1___._ And I think that it has to do with using the edit control variable instead of the maskedit control variable. I also had to create a global SPMaskEdit array for the variables of the masked edits. I appreciate the help and I will award the points to Dex for all of your help. I really appreciate the time that you put in to this effort.
0
DexstarCommented:
I'm not sure how much I helped, but you're welcome for the effort...  :)

Good luck!

Dex*
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.