[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Extend a dialog class

Posted on 2006-03-29
16
Medium Priority
?
287 Views
Last Modified: 2013-11-20
Hi all,

I'm using the MFC AppWizard to create a dialog app called MyTest.  This will generate the CMyTest.h/.cpp and CMyTestDlg.h/.cpp files.
On the Dialog, i have 2 buttons: m_btn1 & m_btn2 of type CButton.

Now I want to create another class that I can extend this MyTestDlg class so I can access these 2 buttons to update button's text or state.  How can I do so?

Thank you!
0
Comment
Question by:TommyN14
  • 9
  • 7
16 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 16327930
You can extend the class object, but perhaps not in the way that you envision.

Each CDialog-derived object expects to find a matching DIALOG resource.   For instance, if you created a new object called CMyTextDlgEx and it was derived from CMyTextDlg, then it would need to be associated with a new resource.  The matching DIALOG resource would have the same buttons, etc as the original ones with some new controls that are peculiar to the derived object.

You can avoid the situation vis-a-vis the separate DIALOG resource by using CreateWindow to create the additional controls in the derived class (rather than easily defining them with the Resource Editor).  But all of the work of individually creating and positioning the new controls, and the loss of the convenience of the Resource Editor for adding and maintaining new controls and events -- would probably make it not worthwhile to go that route.

It is possible to use the ClassWizard to derive from an existing CDialog-derived object with the result being that some common functions and control-handlers are in the base class, with optional overrides in the derived object, but it requires some manual trweaking of the ClassWizard generated code.

If you are intersted in seeing how that will work, please describe exactly what you want to accomplish... how you envision things to work.  I don't want to spend time describing techniques that will be of no use to you.

-- Dan
0
 
LVL 1

Author Comment

by:TommyN14
ID: 16328322
Dan,

Thanks for replying.

What I'm trying to do is that I have a Windows Dialog in my app that has a few CBitmapButtons, 2 CListCtrls and a Flexgrid.  When the user select the entries from the 1st CListCtrl and click on the 'Move To' button, the selected entries should move to the other CListCtrl, as the same time update the Flexgrid items that associate with the selected entries.  And it should work the other way around.  At the same time, I have another thread (UINT processData(LPVOID pParam)) within this app, that is running and reading data from another source (another application) and parse the data and update the CBitmapButtons bitmaps.  For the thread, instead of reading from other source, you can create a for loop and update the CBitmapButtons bitmaps for now.  

If you could please provide me with example, I'd be very appreciated.

Thanks!
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16334692
From your description, I see no need for using any exotic techniques such as deriving from a CDialog-derived object.  Just use the normal/standard CDialog/ClassWizard programming techniques as described in any MFC tutorial.  Use the Resource Editor to position the controls and use the ClassWizard to add event handlers.

The fact that there is a separate thread of execution that needs to interact with the U/I can be a little bit tricky -- the thread itself should not make calls to functions like SetBitmap.  It can use PostMessage to initiate U/I activity or (and this is my preference) it can set globally-accessible variable values and you can have a WM_TIMER handler in the window that's running the U/I to update the U/I based on the current values of those variables

As to moving items from one listbox to another... that is straight-forward programming.... put the code in the onClick handler for the "Move To' button.  I recommend that you look at some the tutorials in the Visual C++ on-line help... for instance:
     http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/HTML/_core_using_clistctrl.asp

-- Dan
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:TommyN14
ID: 16349824
Dan,

Could you please give me some code snipets or show me the link to the examples of how you would do these "It can use PostMessage to initiate U/I activity or (and this is my preference) it can set globally-accessible variable values and you can have a WM_TIMER handler in the window that's running the U/I to update the U/I based on the current values of those variables"

If using the TIMER, what happen if when the TIMER is called and the user click on any of the buttons at the same time, will it cause any problem?  There will be multiple threads running and updating the data, will it cause any race conditions?

Thanks!
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16351573
Let's say that in your main window (BMyTestDlg) you define three HBITMap variables...
     HBITMAP m_hbmRed;
     HBITMAP m_hbmGreen;
     HBITMAP m_hbmBlue;
and you also have...
     HBITMAP m_hbmNeedsToBeSetAs;

In OnIntitDialog, you set up the first three, say by using LoadReasource(), and you set the fourth one to NULL.  

Now in your thread proc, you read some external data that tells you that the bitmap being displayed is red, but it needs to be blue.  All you do is...
 
    // in the thread proc
    CMyTestDlg* pDlg= ( CMyTestDlg*)AfxGetMainWnd(); // if the dlg is the main window
    pDlg->m_hbmNeedsToBeSetAs= m_hbmBlue;

At this poiunt, nothing has changed on the screen.

Finally you create a window timer (use ClassWizard to create an WM_TIMER event handler and in OnInitDIalog start the timer, using for instance:

   SetTimer( 1234, 100, 0 ); /// 1234 is an arbitrary unique value

Now every 100ms (ten times per second) after window creation, your OnTimer function will execute.  In it you add code like:

void CMyTestDlg::OnTimer(UINT nIDEvent)
{
      if ( (nIDEvent==1234) AND (m_hbmNeedsToBeSetAs != 0) ) {
            m_ctlBtnWithImage.SetBitmap(m_hbmNeedsToBeSetAs);
            m_hbmNeedsToBeSetAs= 0;
      }
      CDialog::OnTimer(nIDEvent);
}
-==-=-=-=-=-=-=-=-
The result is that the image changes to the other bitmap within 1/10th of a second... which is virtually instantaeous to the human eye.  The reason to do it this way is tha the thread proc *only* accesses program variables... it did not call SetBitmap itself.

Even if you have dozens of images to change, each with several variations, the process is the same.  You can also use simple Booleans like m_fBtn3NeedsUpdate or whatever... as long as your timer handler can figure out what U/I actions it needs to take.

>> what happen if when the TIMER is called and the user click on any of the buttons at the same time

That cannot happen.  Window events are serialized:  A button click and a WM_TIMER message are handled one after another (that's one of the main advanatages of using this technique with multi-threading... you never have to worry about U/I things happening "simultaneously").

-- Dan
0
 
LVL 1

Author Comment

by:TommyN14
ID: 16353103
Dan,

I tried your suggestions, I received this error:
"error C2065: 'm_hbmBlue' : undeclared identifier" from the thread.

I declared the m_hbmBlue and the other 3 variables inside CMyTestDlg.h file as public.  If I changed the line
pDlg->m_hbmNeedsToBeSetAs= m_hbmBlue;
to
pDlg->m_hbmNeedsToBeSetAs= pDlg->m_hbmBlue; the program crashed.

I don't understand this part "In OnIntitDialog, you set up the first three, say by using LoadReasource(), and you set the fourth one to NULL."  How do you call the LoadResource()?
Also, If i comment out the thread, set the CBitmapButton to gray OnInitDialog, and change the button to green on the OnTimer function, and run the program, the button didn't change the color.  But if I run as debug, the button changes the color.  Do you have any idea?

Thanks in advance for your time & support.

0
 
LVL 1

Author Comment

by:TommyN14
ID: 16364133
Dan,

Just in case you didn't receive email from EE.  Please help!

Thank you!
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16364344
For the C2065 error, you must verify that you have spelled the variables correctly -- in the header file of CMyTestDlg and in the timer proc and in the thread that accesses it.

As to "setting up the HBITMAP" values -- that means that you have loaded the image from the resources of your project or you have read them from a file.  That is, you need to initialize these variables before they get used.
0
 
LVL 1

Author Comment

by:TommyN14
ID: 16364415
Dan,
please re read my question in the previous post.

I did check the spelling of the m_hbmBlue.  Again, I declared these variables inside the header file CMyTestDlg as public.  OnInitDialog, I initialize them.  And on the thread I set the variable.

Please help!
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16364713
Sorry, my earlier post was in error.  The thread needs to qualify the variable, specifying its object.  Also, if there is a chance that th thread runs before the dialog has been created, you need to check for that.  For instace:

    // in the thread proc
    CMyTestDlg* pDlg= ( CMyTestDlg*)AfxGetMainWnd(); // if the dlg is the main window
    if ( pDlg != NULL ) {
           pDlg->m_hbmNeedsToBeSetAs=  pDlg->m_hbmBlue;
    }

One main difference between Debug and Release is that in Debug builds, variables get initialized to 0 automatically.  To avoid many problem with Release builds, be sure to initialize your fariables.  In this case, be sure that in the CMyTestDlg constructo (or in its OnInitDialog handler before you start thr timeer) that you pre-set the flag variable to zero.  E.g.,

   m_hbmNeedsToBeSetAs = 0;
0
 
LVL 1

Author Comment

by:TommyN14
ID: 16365399
Dan,

I added m_hbmNeedsToBeSetAs = 0; OnInitDialog, then run the app.  It didn't change the color.  I added log msgs to see what's happening, it seems like the m_hbmNeedsToBeSetAs variable is always 0 so that's why OnTimer function never execute these lines:
 if ( (nIDEvent==1234) AND (m_hbmNeedsToBeSetAs != 0) ) {
          m_ctlBtnWithImage.SetBitmap(m_hbmNeedsToBeSetAs);
          m_hbmNeedsToBeSetAs= 0;
     }

0
 
LVL 1

Author Comment

by:TommyN14
ID: 16365788
It seems like the variable didn't get updated or pDlg->m_hbmNeedsToBeSetAs is different from the m_hbmNeedsToBeSetAs from the CMyTestDlg class.  I don't know what's going on.  Do you have any idea?

Thanks!
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 1000 total points
ID: 16365947
In the code, I assumed that AfxWmainWnd() would return the CWnd* that points to the CDialog-derived object that contains the variables (that would be true if this is in the main doalog of a dialog-based AppWizard-generated application program).  If it is not working for you, then try this:

Add this line near the top of the CMyTestDlg source file:

        CMyTestDlg* gpMyTestDlg= 0;

Now in the Constructor for that object, add this:

        gpMyTestDlg= this;

Now in the CPP module that contains the thread, put this near at the top:
        #include MyTestDlg.h
        extern  CMyTestDlg* gpMyTestDlg;

And in the thread proc when you need to change the button, use...

    // in the thread proc
    if ( gpMyTestDlg != NULL ) {
           gpMyTestDlg->m_hbmNeedsToBeSetAs=  gpMyTestDlg->m_hbmBlue;
    }
0
 
LVL 1

Author Comment

by:TommyN14
ID: 16367069
Dan,

That works.  But I notice when I first start the app, the CPU for this app is at ~6000K.  But when I minimized and maximized, the CPU dropped down to ~2000K.  Do you have any idea to why this would happen?

Thanks!
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16367152
Do you mean the memory usage?  If so, I do not have any reason for that behavior.  The memory usage goes up when a program allocates memory and goes down when that memory is freeded.  Note that DLLs that are in use by the App also contribute to the memory usage total.  Also ig you are working with large images, that can have an effect.

In general, you need to worry about memroy useage in only one situation:  If, as you prorgam runs, the numbers climb higher and higher and never go down.... that is a sysmptom of a "memory leak" and it is a serious problem.  All other oddness (such as going up momentarily and then down) is probably not important.

-- Dan
0
 
LVL 1

Author Comment

by:TommyN14
ID: 16376715
Thanks for all your help, Dan!!!
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

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

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 …
If you use Adobe Reader X it is possible you can't open OLE PDF documents in the standard. The reason is the 'save box mode' in adobe reader X. Many people think the protected Mode of adobe reader x is only to stop the write access. But this fe…
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.
Screencast - Getting to Know the Pipeline
Suggested Courses
Course of the Month19 days, 22 hours left to enroll

872 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