Nasty Doc/View Problem
Martin Welch -- 106114.1126@CompuServe.COM Wednesday, November 06, 1996 Environment: VC++ 4.2b, Win 95, VC++ 2.1 NT 3.51 Hi, I've hit the MFC brick wall. I hope you folks can help. I need to implement a find dialog in an MDI Doc/View database application that has raised a number of issues. The find dialog needs to behave in a similar fashion to the find dialog in Word but with a couple of twists. The user takes the Find option from the menu and invokes the modeless Find Dialog. The user selects some criteria and clicks Find. If a document is currently open the CEditView replaces its contents with the data that matches the find criteria. If there are no documents open then a new document is created with the selected data. This sounded easy at first. I created the Find menu option for both the CMainFrame and the CMDIChildFrame. If there are no documents then the CMainFrame handles the command and creates a new document. However, if a document already exists then how does the document handler inform the current view to update itself with the details of the new find criteria? I came up with a number of solutions: 1. Add an m_wndCaller attribute to the CFindDialog. When the user clicks the Find button CFindDialog posts a WM_USER message to the caller who responds appropriately. 2. CFindDialog broadcasts a WM_USER message and the appropriate handler in either CMainFrame or CMDIChildFrame/CMyDocument/CMyView is called. This doesn't work because the message does not get routed to the Doc/View. Is this because WM_USER is not a command? 3. I attempt to identify the current view in the CFindDialog by identifying the CDocTemplate information that is an attribute of my CWinApp class and posting a message directly. However, the GetActiveFrame, GetActiveDocument and GetActiveView functions return NULL. I've assumed that this is the case because the CFindDialog is active. Option 3 seems very long winded. I prefer option 2 but doesn't work so currently I have implemented option 1. Option 2 is also flawed because if multiple documents were open they would all update themselves! However option 1 is still flawed. If I summon the CFindDialog with no CMDIChildFrame the m_wndCaller is set to the CMainFrame and a new CMDIChildFrame is created. If I select another criteria it will once again create another CMDIChildFrame when it should replace the existing CMDIChildFrame. The same problem manifests itself in reverse - CFindDialog attempts to replace the contents of a CMDIChildFrame that has since been closed. I can partially get around this problem by making the pointer to the CFindDialog global or a member of CWinApp and track the 'current' frame but this is messy and probably as long winded as option 3. This is a mess. Is there a better, more elegant, OO, way of handling this problem? Thanks for your time. Martin.
Gonzalo Isaza -- gonzaloi@microsoft.com Thursday, November 07, 1996 [Mini-digest: 2 responses] I'm not sure if I understood your problem correctly, but assuming I did, here is my 2 cents worth: Assuming your document has the information matching the criteria for the find, all you would have to do is call CDocument::UpdateAllViews for the document which is already open. If you don't want to update ALL the views, you can loop through each one of them (see GetFirstViewPosition and GetNextView documentation) and call Update for the views you want to change, by calling pView->OnUpdate(....) I hope this helps. By the way, which Brick Wall are you talking about? Gonzalo I speak for myself. I don't speak for Microsoft. >---------- >From: Martin Welch[SMTP:106114.1126@CompuServe.COM] >Sent: Wednesday, November 06, 1996 2:45 PM >To: 'mfc-l mailing list' >Subject: Nasty Doc/View Problem > >Environment: VC++ 4.2b, Win 95, VC++ 2.1 NT 3.51 > >Hi, > >I've hit the MFC brick wall. I hope you folks can help. > >I need to implement a find dialog in an MDI Doc/View database application >that has raised a number of issues. > >The find dialog needs to behave in a similar fashion to the find dialog in >Word but with a couple of twists. > >The user takes the Find option from the menu and invokes the modeless Find >Dialog. The user selects some criteria and clicks Find. If a document is >currently open the CEditView replaces its contents with the data that >matches the find criteria. If there are no documents open then a new >document is created with the selected data. > >This sounded easy at first. I created the Find menu option for both the >CMainFrame and the CMDIChildFrame. If there are no documents then the >CMainFrame handles the command and creates a new document. > >However, if a document already exists then how does the document handler >inform the current view to update itself with the details of the new find >criteria? I came up with a number of solutions: > >1. Add an m_wndCaller attribute to the CFindDialog. When the user clicks >the Find button CFindDialog posts a WM_USER message to the caller who >responds appropriately. > >2. CFindDialog broadcasts a WM_USER message and the appropriate handler in >either CMainFrame or CMDIChildFrame/CMyDocument/CMyView is called. This >doesn't work because the message does not get routed to the Doc/View. Is >this because WM_USER is not a command? > >3. I attempt to identify the current view in the CFindDialog by >identifying the CDocTemplate information that is an attribute of my CWinApp >class and posting a message directly. However, the >GetActiveFrame, GetActiveDocument and GetActiveView functions return NULL. >I've assumed that this is the case because the CFindDialog is active. > >Option 3 seems very long winded. I prefer option 2 but doesn't work so >currently I have implemented option 1. > >Option 2 is also flawed because if multiple documents were open they would >all update themselves! > >However option 1 is still flawed. If I summon the CFindDialog with no >CMDIChildFrame the m_wndCaller is set to the CMainFrame and a new >CMDIChildFrame is created. If I select another criteria it will once again >create another CMDIChildFrame when it should replace the existing >CMDIChildFrame. The same problem manifests itself in reverse - CFindDialog >attempts to replace the contents of a CMDIChildFrame that has since been >closed. > >I can partially get around this problem by making the pointer to the >CFindDialog global or a member of CWinApp and track the 'current' frame but >this is messy and probably as long winded as option 3. > >This is a mess. Is there a better, more elegant, OO, way of handling this >problem? > >Thanks for your time. > >Martin. > > -----From: "C.Zhang"You can implement the Find menu command in both CMainFrame and CYourDoc. CYourDoc can replace itself with the right information and call UpdateAllViews(...) so that all views attached to the document will be updated.
Jim Lawson Williams -- jimlw@mail.ccur.com.au Saturday, November 09, 1996 G'day! Most likely I don't understand your problem, but it seems to me that the Doc. "knows" that its view(s) need replacing, so why not GetFirstViewPosition(), GetNextView(), & Invalidate()? Regards, Jim LW
Stuart Downing -- sdowning@fame.com Monday, November 11, 1996 Gonzalo, I agree that the OnUpdate mechanism is the way to go here, however, if you don't want to update ALL the views, you shouldn't rewrite UpdateAllViews and only call Update for the views you want updated, use the hinting mechanism built into the UpdateAllViews/OnUpdate mechanism to limit the scope of the update. Target views for the OnUpdate "message" should look at the hint argument, and if the hint type (create a CObject derived hint object, use IsKindOf to determine if desired hint type) is appropriate, update the view, otherwise do nothing in OnUpdate (unless, of course, it's some other hint type you also care about). ------- Stuart Downing (formerly of Creative Solutions) FAME Information Services, Inc. sdowning@fame.com ---------- From: Gonzalo Isaza[SMTP:gonzaloi@MICROSOFT.com] Sent: Thursday, November 07, 1996 7:37 PM To: 'mfc-l@netcom.com' Subject: RE: Nasty Doc/View Problem [Mini-digest: 2 responses] I'm not sure if I understood your problem correctly, but assuming I did, here is my 2 cents worth: Assuming your document has the information matching the criteria for the find, all you would have to do is call CDocument::UpdateAllViews for the document which is already open. If you don't want to update ALL the views, you can loop through each one of them (see GetFirstViewPosition and GetNextView documentation) and call Update for the views you want to change, by calling pView->OnUpdate(....) I hope this helps. By the way, which Brick Wall are you talking about? Gonzalo I speak for myself. I don't speak for Microsoft. >---------- >From: Martin Welch[SMTP:106114.1126@CompuServe.COM] >Sent: Wednesday, November 06, 1996 2:45 PM >To: 'mfc-l mailing list' >Subject: Nasty Doc/View Problem > >Environment: VC++ 4.2b, Win 95, VC++ 2.1 NT 3.51 > >Hi, > >I've hit the MFC brick wall. I hope you folks can help. > >I need to implement a find dialog in an MDI Doc/View database application >that has raised a number of issues. > >The find dialog needs to behave in a similar fashion to the find dialog in >Word but with a couple of twists. > >The user takes the Find option from the menu and invokes the modeless Find >Dialog. The user selects some criteria and clicks Find. If a document is >currently open the CEditView replaces its contents with the data that >matches the find criteria. If there are no documents open then a new >document is created with the selected data. > >This sounded easy at first. I created the Find menu option for both the >CMainFrame and the CMDIChildFrame. If there are no documents then the >CMainFrame handles the command and creates a new document. > >However, if a document already exists then how does the document handler >inform the current view to update itself with the details of the new find >criteria? I came up with a number of solutions: > >1. Add an m_wndCaller attribute to the CFindDialog. When the user clicks >the Find button CFindDialog posts a WM_USER message to the caller who >responds appropriately. > >2. CFindDialog broadcasts a WM_USER message and the appropriate handler in >either CMainFrame or CMDIChildFrame/CMyDocument/CMyView is called. This >doesn't work because the message does not get routed to the Doc/View. Is >this because WM_USER is not a command? > >3. I attempt to identify the current view in the CFindDialog by >identifying the CDocTemplate information that is an attribute of my CWinApp >class and posting a message directly. However, the >GetActiveFrame, GetActiveDocument and GetActiveView functions return NULL. >I've assumed that this is the case because the CFindDialog is active. > >Option 3 seems very long winded. I prefer option 2 but doesn't work so >currently I have implemented option 1. > >Option 2 is also flawed because if multiple documents were open they would >all update themselves! > >However option 1 is still flawed. If I summon the CFindDialog with no >CMDIChildFrame the m_wndCaller is set to the CMainFrame and a new >CMDIChildFrame is created. If I select another criteria it will once again >create another CMDIChildFrame when it should replace the existing >CMDIChildFrame. The same problem manifests itself in reverse - CFindDialog >attempts to replace the contents of a CMDIChildFrame that has since been >closed. > >I can partially get around this problem by making the pointer to the >CFindDialog global or a member of CWinApp and track the 'current' frame but >this is messy and probably as long winded as option 3. > >This is a mess. Is there a better, more elegant, OO, way of handling this >problem? > >Thanks for your time. > >Martin.
Martin Welch -- 106114.1126@CompuServe.COM Wednesday, November 13, 1996 Environment: VC++ 4.2b, Win 95, VC++ 2.1 NT 3.51 Thanks for your help so far. It would seem that part of the solution is explaining the problem properly :-) Everyone has kindly pointed out that the solution would be to use UpdateAllViews() or GetFirstViewPosition(), GetNextView(), & Invalidate(). This is fine if the Find Dialog is modal, but not if its modeless: i.e. the user selects a criteria in the find dialog which either updates the current, topmost doc/view or creates a new doc/view if none are open. However, the user may reselect a new criteria without dismissing the find dialog (which must again update the current doc/view). This is why I tried posting a WM_USER message from within the find dialog. Posting the message is easy, its handling the message which is causing the problem! Thanks for your patience! BTW: 'Brick Wall' is shorthand for 'I've Run Out Of Ideas!' Martin
C. Zhang -- cz17309@goodnet.com Friday, November 15, 1996 Martin Welch wrote: > > Environment: VC++ 4.2b, Win 95, VC++ 2.1 NT 3.51 > > Thanks for your help so far. It would seem that part of the solution is > explaining the problem properly :-) Everyone has kindly pointed out that > the solution would be to use UpdateAllViews() or GetFirstViewPosition(), > GetNextView(), & Invalidate(). > > This is fine if the Find Dialog is modal, but not if its modeless: i.e. the > user selects a criteria in the find dialog which either updates the > current, topmost doc/view or creates a new doc/view if none are open. > However, the user may reselect a new criteria without dismissing the find > dialog (which must again update the current doc/view). This is why I tried > posting a WM_USER message from within the find dialog. Posting the message > is easy, its handling the message which is causing the problem! > > Thanks for your patience! > > BTW: 'Brick Wall' is shorthand for 'I've Run Out Of Ideas!' > > Martin Why don't you send WM_COMMAND instead of WM_USER to main frame which in turn will pass the command to top view which will pass it to the document. You can pack all necessary parameters into a structure and pass the pointer to the structure as the LPARAM. In your document, you can use the MACRO OnCommandEx to handle it.
Jim Tannenbaum -- jimt1@voicenet.com Saturday, November 16, 1996 Martin, I was not paying close attention to your initial post, but this one caught my eye. If you are playing with modeless dialogs, I suggest you skim through Kruglinski's book. He provides some good examples of document view with modeless windows. In short, the project view maintains pointers to all the modeless windows, since it creates them. Simple post (or send) a WM_USER message to your base view and then "forward" it to the view of interest. Hope this helps. It has worked successfully for me in the past. Jet JJM Systems, Inc Phone: (215) 672-3660 1 Ivybrook Blvd, Suite 190 Fax: (215) 672-5702 Ivyland, PA 19874 Net: jimt1@voicenet.com
Martin Welch -- 106114.1126@CompuServe.COM Monday, November 18, 1996 Environment: VC++ 4.2b, Win 95, VC++ 2.1 NT 3.51 > Why don't you send WM_COMMAND instead of WM_USER to main frame which in > turn will pass the command to top view which will pass it to the > document. You can pack all necessary parameters into a structure and > pass the pointer to the structure as the LPARAM. In your document, you > can use the MACRO OnCommandEx to handle it. I've already tried broadcasting a WM_COMMAND instead of a WM_USER. However, the Doc/View architecture only routes WM_COMMAND messages to the active view, doc or frame. Of course, the doc/view is not active because of my modeless dialog box!
Jim Lawson Williams -- jimlw@mail.ccur.com.au Thursday, November 21, 1996 G'day Martin! Much earlier you wrote: >Everyone has kindly pointed out that the solution would be to use >UpdateAllViews() or GetFirstViewPosition(), GetNextView(), & Invalidate(). >This is fine if the Find Dialog is modal, but not if its modeless! I'm still lost. Are you saying that only the topmost view's OnUpdate() is invoked when you issue CDocument::UpdateAllViews()/iterate through the doc.'s views? Regards, Jim LW
Martin Welch -- 106114.1126@CompuServe.COM Thursday, November 28, 1996 Environment: VC++ 4.2b, Win 95, VC++ 2.1 NT 3.51 > I'm still lost. Are you saying that only the topmost view's OnUpdate() is > invoked when you issue CDocument::UpdateAllViews()/iterate through the > doc.'s views? Jim, OK, from the top. This is how I'd implement a modal Find dialog. CMyMDIChildFrame::OnFind() { CFindDialog dlg; if ( dlg.DoModal() == IDOK ) { CreateDocument(dlg.m_strFindCriteria); } } CMyDoc::OnFind() { CFindDialog dlg; if ( dlg.DoModal() == IDOK ) { UpdateAllViews(...); } } This is OK but I want a modeless Find dialog. Here are the situations that I need to cope with: 1. User has no document open but can select the find dialog which will then create a document based on the criteria. (As Above). However, If the user changes the criteria the newly created document changes to reflect the changed criteria. 2. User already has one or more documents open when he/she invokes the find dialog. In this case the topmost document changes to reflect the find criteria. Initially I intended the modeless find dialog to broadcast a WM_USER message that would be handled by the Doc/View/Frame or, if no documents were open, by the mainframe. However, the doc/view/frame does not handle WM_USER messages. Next, I tried a WM_COMMAND but again it seems that because the Find dialog is active the Doc/View doesn't receive them. After that I attempted to call GetActiveDocument() and GetActiveView() but they both return NULL again presumably because the Find dialog is the active window. Its about this time that I posted the message to MFC-L. I hope that clarifies the situation. Martin
Jim Lawson Williams -- jimlw@mail.ccur.com.au Monday, December 02, 1996 OK Martin, Then why not something along the lines of these code snippets: class CFREDDoc; class CFREDApp : public CWinApp { private: CFREDDoc* m_pDocCurrent; public: void SetDocCurrent(CFREDDoc* pDoc) {m_pDocCurrent = pDoc;};CFREDApp::CFREDApp(): m_pDocCurrent(NULL) { } void CFREDDoc::SetDocCurrent() { TRACE("CFREDDoc::SetDocCurrent() %s\n", GetTitle()); ((CFREDApp*)AfxGetApp())->SetDocCurrent(this); } void CFREDView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView) { if (bActivate) GetDocument()->SetDocCurrent(); } The TRACE I ran clearly showed that each Doc. knew that it was being activated. I didn't go any further, but I would be amazed if you couldn't get the results you seek through CMyApp::m_pMyActiveDoc or somesuch. Or maybe I STILL don't understand your problem... Regards, Jim LW At 02:22 AM 28-11-96 -0500, you wrote: >Environment: VC++ 4.2b, Win 95, VC++ 2.1 NT 3.51 > >> I'm still lost. Are you saying that only the topmost view's OnUpdate() >is >> invoked when you issue CDocument::UpdateAllViews()/iterate through the >> doc.'s views? > >Jim, > >OK, from the top. > >This is how I'd implement a modal Find dialog. > >CMyMDIChildFrame::OnFind() >{ > CFindDialog dlg; > if ( dlg.DoModal() == IDOK ) { > CreateDocument(dlg.m_strFindCriteria); > } >} > >CMyDoc::OnFind() >{ > CFindDialog dlg; > if ( dlg.DoModal() == IDOK ) { > UpdateAllViews(...); > } >} > >This is OK but I want a modeless Find dialog. Here are the >situations that I need to cope with: > >1. User has no document open but can select the find dialog which > will then create a document based on the criteria. (As Above). > However, If the user changes the criteria the newly created > document changes to reflect the changed criteria. > >2. User already has one or more documents open when he/she invokes > the find dialog. In this case the topmost document changes to > reflect the find criteria. > >Initially I intended the modeless find dialog to broadcast a WM_USER >message that would be handled by the Doc/View/Frame or, if no >documents were open, by the mainframe. However, the doc/view/frame >does not handle WM_USER messages. Next, I tried a WM_COMMAND but again >it seems that because the Find dialog is active the Doc/View doesn't >receive them. > >After that I attempted to call GetActiveDocument() and GetActiveView() >but they both return NULL again presumably because the Find dialog is >the active window. > >Its about this time that I posted the message to MFC-L. > >I hope that clarifies the situation. > >Martin > >From the BBC's "Barchester Chronicles": "I know that ultimately we are not supposed to understand. But I also know that we must try." -- the Reverend Septimus Harding, C++ programmer
mwelch@tsbbank.co.uk Tuesday, December 03, 1996 Environment: VC++ 4.2b, Win 95, VC++ 2.2 NT 3.51 Hi Jim, Thanks for your response, and your solution. I arrived at a near identical solution and it solves the problem. Its bette= r=20 than my first attempt which had a member variable m_wndCaller in the dialog= =20 box but which didn't handle every scenario. My ultimate aim was to resolve the problem by sending WM_USER messages from= =20 the find dialog to the currently active view/doc. The idea was to produce a= =20 generic find dialog which I could use across different applications, i.e.=20 eliminate the need for ((CFREDApp*)AfxGetApp())->MyFunc(). In my original post I posed two questions: a) How do I solve this problem=20 using MFC? and b) is there a better, more OO, solution using MFC? Your last post answers the first question but I'm still interested in an=20 answer to the second. Thanks again, Jim. Martin. --------------------------------------------------------------------------- This email is only for the use of the addressee. It may contain information which is legally privileged, confidential and exempt from disclosure. If you are not the intended recipient you are hereby notified that any dissemination, distribution, or copying of this communication and its=20 attachments is strictly prohibited. If you receive this communication in=20 error, please email nadmin@tsbbank.co.uk. ---------------------------------------------------------------------------
IK 23 -- Cunningham@tgd.swissptt.ch Thursday, December 05, 1996 [Mini-digest: 3 responses] Sorry if I have the wrong end of the stick here but are you trying to implement a Observer Subject pattern as described in "Design Patterns" by the Gamma et al. I have created a 2 base classes CSubject and CObserver and I use multiple inheritance with MFC classes to do just what I think you are describing. If you want the classes drop me a line. Graham Cunningham 00 41 31 338 0633 >---------- >From: mwelch@tsbbank.co.uk[SMTP:mwelch@tsbbank.co.uk] >Sent: Dienstag, 3. Dezember 1996 15:44 >To: mfc-l@netcom.com >Subject: Nasty Doc/View Problem > >Environment: VC++ 4.2b, Win 95, VC++ 2.2 NT 3.51 > >Hi Jim, > >Thanks for your response, and your solution. > >I arrived at a near identical solution and it solves the problem. Its better >than my first attempt which had a member variable m_wndCaller in the dialog >box but which didn't handle every scenario. > >My ultimate aim was to resolve the problem by sending WM_USER messages from >the find dialog to the currently active view/doc. The idea was to produce a >generic find dialog which I could use across different applications, i.e. >eliminate the need for ((CFREDApp*)AfxGetApp())->MyFunc(). > >In my original post I posed two questions: a) How do I solve this problem >using MFC? and b) is there a better, more OO, solution using MFC? > >Your last post answers the first question but I'm still interested in an >answer to the second. > >Thanks again, Jim. > >Martin. > >--------------------------------------------------------------------------- >This email is only for the use of the addressee. It may contain information >which is legally privileged, confidential and exempt from disclosure. >If you are not the intended recipient you are hereby notified that any >dissemination, distribution, or copying of this communication and its >attachments is strictly prohibited. If you receive this communication in >error, please email nadmin@tsbbank.co.uk. >--------------------------------------------------------------------------- > -----From: Luke StephensWhat was the solution? ---------- From: mwelch@tsbbank.co.uk Sent: Tuesday, December 03, 1996 8:44 AM To: mfc-l@netcom.com Subject: Nasty Doc/View Problem Environment: VC++ 4.2b, Win 95, VC++ 2.2 NT 3.51 Hi Jim, Thanks for your response, and your solution. I arrived at a near identical solution and it solves the problem. Its better than my first attempt which had a member variable m_wndCaller in the dialog box but which didn't handle every scenario. My ultimate aim was to resolve the problem by sending WM_USER messages from the find dialog to the currently active view/doc. The idea was to produce a generic find dialog which I could use across different applications, i.e. eliminate the need for ((CFREDApp*)AfxGetApp())->MyFunc(). In my original post I posed two questions: a) How do I solve this problem using MFC? and b) is there a better, more OO, solution using MFC? Your last post answers the first question but I'm still interested in an answer to the second. Thanks again, Jim. Martin. --------------------------------------------------------------------------- This email is only for the use of the addressee. It may contain information which is legally privileged, confidential and exempt from disclosure. If you are not the intended recipient you are hereby notified that any dissemination, distribution, or copying of this communication and its attachments is strictly prohibited. If you receive this communication in error, please email nadmin@tsbbank.co.uk. --------------------------------------------------------------------------- -----From: Jim Lawson Williams At 02:44 PM 3/12/96 +0000, you wrote: >In my original post I posed two questions: a) How do I solve this problem >using MFC? and b) is there a better, more OO, solution using MFC? > >Your last post answers the first question but I'm still interested in an >answer to the second. > G'day Martin, Well, without thinking too hard about it, it seems to me it could be made generic if you are absolutely determined. It would require you to establish your own base Application, Document, and View Classes and a purpose-built Wizard to employ them rather than those Microsoft supplies. You could do a lot of cut-and-pasting in the equivalent development-time. Then there's the problem of on-going maintenance to keep in step with what Microsoft are doing... Regards, Jim LW >From the BBC's "Barchester Chronicles": "I know that ultimately we are not supposed to understand. But I also know that we must try." -- the Reverend Septimus Harding, C++ programmer
mwelch@tsbbank.co.uk Tuesday, December 17, 1996 Environment: VC++ 4.2b, Win 95, VC++ 2.1 NT 3.51 Graham, Sorry for the delay but my mail bounced while on holiday > Sorry if I have the wrong end of the stick here but are you trying to > implement a Observer Subject pattern as described in > "Design Patterns" by the Gamma et al. > I have created a 2 base classes CSubject and CObserver and I use > multiple inheritance with MFC classes to do just what I think you are > describing. If you want the classes drop me a line. You probably haven't got the wrong end of the stick :-) However, I've never heard of the Observer Subject pattern or Gamma et al.=20 Could you point me in the right direction - it sounds like a must on my=20 reading list. I'd also apprieciate a look at the classes you describe. --------------------------------------------------------------------------- This email is only for the use of the addressee. It may contain information which is legally privileged, confidential and exempt from disclosure. If you are not the intended recipient you are hereby notified that any dissemination, distribution, or copying of this communication and its=20 attachments is strictly prohibited. If you receive this communication in=20 error, please email nadmin@tsbbank.co.uk. ---------------------------------------------------------------------------
| Вернуться в корень Архива |