📄 ch14.htm
字号:
<P>This new member variable shows up again in the view constructor, Listing 14.4,
and the revised OnDraw(), Listing 14.5.</P>
<P>
<H4>Listing 14.4  ShowStringView.cpp--Constructor</H4>
<PRE>CShowStringView::CShowStringView()
{
m_pSelection = NULL;
// TODO: add construction code here
</PRE>
<PRE>}
</PRE>
<H4>Listing 14.5   ShowStringView.cpp--CShowStringView::OnDraw()</H4>
<PRE>void CShowStringView::OnDraw(CDC* pDC)
{
CShowStringDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
// TODO: also draw all OLE items in the document
// Draw the selection at an arbitrary position. This code should be
// removed once your real drawing code is implemented. This position
// corresponds exactly to the rectangle returned by CShowStringCntrItem,
// to give the effect of in-place editing.
// TODO: remove this code when final draw code is complete.
if (m_pSelection == NULL)
{
POSITION pos = pDoc->GetStartPosition();
m_pSelection = (CShowStringCntrItem*)pDoc->GetNextClientItem(pos);
}
if (m_pSelection != NULL)
m_pSelection->Draw(pDC, CRect(10, 10, 210, 210));
</PRE>
<PRE>}
</PRE>
<P>The code supplied for OnDraw() draws only a single contained item. It doesn't
draw any native data--in other words, elements of ShowString that are not contained
items. At the moment there is no native data, but after the string is added to the
application, OnDraw() is going to have to draw it. What's more, this code only draws
one contained item, and it does so in an arbitrary rectangle. OnDraw() is going to
see a lot of changes as you work through this chapter.</P>
<P>The view class has gained a lot of new functions. They are as follows:</P>
<UL>
<LI>OnInitialUpdate()
<P>
<LI>IsSelected()
<P>
<LI>OnInsertObject()
<P>
<LI>OnSetFocus()
<P>
<LI>OnSize()
<P>
<LI>OnCancelEditCntr()
</UL>
<P>Each of these new functions is discussed in the subsections that follow.</P>
<P><B><I>OnInitialUpdate()  </I></B>OnInitialUpdate()is called just before
the very first time the view is to be displayed. The boilerplate code (see Listing
14.6) is pretty dull.</P>
<P>
<H4>Listing 14.6  ShowStringView.cpp--CShowStringView::OnInitialUpdate()</H4>
<PRE>void CShowStringView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: remove this code when final selection
// model code is written
m_pSelection = NULL; // initialize selection
</PRE>
<PRE>}
</PRE>
<P>The base class OnInitialUpdate() calls the base class OnUpdate(), which calls
Invalidate(), requiring a full repaint of the client area.</P>
<P><B><I>IsSelected()  </I></B>IsSelected() currently isn't working because
the selection mechanism is so rudimentary. Listing 14.7 shows the code that was generated
for you. Later, when you have implemented a proper selection method, you will improve
how this code works.</P>
<P>
<H4>Listing 14.7  ShowStringView.cpp--CShowStringView::IsSelected()</H4>
<PRE>BOOL CShowStringView::IsSelected(const CObject* pDocItem) const
{
// The implementation below is adequate if your selection consists of
// only CShowStringCntrItem objects. To handle different selection
// mechanisms, the implementation here should be replaced.
// TODO: implement this function that tests for a selected OLE
// client item
return pDocItem == m_pSelection;
</PRE>
<PRE>}
</PRE>
<P>This function is passed a pointer to a container item. If that pointer is the
same as the current selection, it returns TRUE.</P>
<P><B><I>OnInsertObject()  </I></B>OnInsertObject()is called when the user
chooses Edit, Insert New Object. It's quite a long function, so it is presented in
parts. The overall structure is presented in Listing 14.8.</P>
<P>
<H4>Listing 14.8  ShowStringView.cpp--CShowStringView::OnInsertObject()</H4>
<PRE>void CShowStringView::OnInsertObject()
{
// Display the Insert Object dialog box.
CShowStringCntrItem* pItem = NULL;
TRY
{
// Create a new item connected to this document.
// Initialize the item.
// Set selection and update all views.
}
CATCH(CException, e)
{
// Handle failed create.
}
END_CATCH
// Tidy up.
</PRE>
<PRE>}
</PRE>
<P>Each comment here is replaced with a small block of code, discussed in the remainder
of this section. The TRY and CATCH statements, by the way, are on old-fashioned form
of exception handling, discussed in Chapter 26, "Exceptions and Templates."</P>
<P>First, this function displays the Insert Object dialog box, as shown in Listing
14.9.</P>
<P>
<H4>Listing 14.9  ShowStringView.cpp--Display the Insert Object Dialog
Box</H4>
<PRE> // Invoke the standard Insert Object dialog box to obtain information
// for new CShowStringCntrItem object.
COleInsertDialog dlg;
if (dlg.DoModal() != IDOK)
return;
</PRE>
<PRE> BeginWaitCursor();
</PRE>
<P>If the user clicks Cancel, this function returns and nothing is inserted. If the
user clicks OK, the cursor is set to an hourglass while the rest of the processing
occurs.</P>
<P>To create a new item, the code in Listing 14.10 is inserted.</P>
<P>
<H4>Listing 14.10  ShowStringView.cpp--Create a New Item</H4>
<PRE> // Create new item connected to this document.
CShowStringDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pItem = new CShowStringCntrItem(pDoc);
</PRE>
<PRE> ASSERT_VALID(pItem);
</PRE>
<P>This code makes sure there is a document, even though the menu item is enabled
only if there is one, and then creates a new container item, passing it the pointer
to the document. As you see in the CShowStringCntrItem section, container items hold
a pointer to the document that contains them.</P>
<P>The code in Listing 14.11 initializes that item.</P>
<P>
<H4>Listing 14.11  ShowStringView.cpp--Initializing the Inserted Item</H4>
<PRE> // Initialize the item from the dialog data.
if (!dlg.CreateItem(pItem))
AfxThrowMemoryException(); // any exception will do
ASSERT_VALID(pItem);
// If item created from class list (not from file) then launch
// the server to edit the item.
if (dlg.GetSelectionType() == COleInsertDialog::createNewItem)
pItem->DoVerb(OLEIVERB_SHOW, this);
</PRE>
<PRE> ASSERT_VALID(pItem);
</PRE>
<P>The code in Listing 14.11 calls the CreateItem() function of the dialog class,
COleInsertDialog. That might seem like a strange place to keep such a function, but
the function needs to know all the answers that were given on the dialog box. If
it was a member of another class, it would have to interrogate the dialog for the
type and filename, find out whether it was linked or embedded, and so on. It calls
member functions of the container item like CreateLinkFromFile(), CreateFromFile(),
CreateNewItem(), and so on. So it's not that the code has to actually fill the object
from the file that is in the dialog box, but rather that the work is partitioned
between the objects instead of passing information back and forth between them.</P>
<P>Then, one question is asked of the dialog box: Was this a new item? If so, the
server is called to edit it. Objects created from a file can just be displayed.</P>
<P>Finally, the selection is updated and so are the views, as shown in Listing 14.12.</P>
<P>
<H4>Listing 14.12  ShowStringView.cpp--Update Selection and Views</H4>
<PRE> // As an arbitrary user interface design, this sets the selection
// to the last item inserted.
// TODO: reimplement selection as appropriate for your application
m_pSelection = pItem; // set selection to last inserted item
</PRE>
<PRE> pDoc->UpdateAllViews(NULL);
</PRE>
<P>If the creation of the object failed, execution ends up in the CATCH block, shown
in Listing 14.13.</P>
<P>
<H4>Listing 14.13  ShowStringView.cpp--CATCH Block</H4>
<PRE> CATCH(CException, e)
{
if (pItem != NULL)
{
ASSERT_VALID(pItem);
pItem->Delete();
}
AfxMessageBox(IDP_FAILED_TO_CREATE);
}
</PRE>
<PRE> END_CATCH
</PRE>
<P>This deletes the item that was created and gives the user a message box.</P>
<P>Finally, that hourglass cursor can go away:</P>
<P>
<PRE> EndWaitCursor();
</PRE>
<P><B><I>OnSetFocus()  </I></B>OnSetFocus(), shown in Listing 14.14, is
called whenever this view gets focus.</P>
<P>
<H4>Listing 14.14  ShowStringView.cpp--CShowStringView::OnSetFocus()</H4>
<PRE>void CShowStringView::OnSetFocus(CWnd* pOldWnd)
{
COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
if (pActiveItem != NULL &&
pActiveItem->GetItemState() == COleClientItem::activeUIState)
{
// need to set focus to this item if it is in the same view
CWnd* pWnd = pActiveItem->GetInPlaceWindow();
if (pWnd != NULL)
{
pWnd->SetFocus(); // don't call the base class
return;
}
}
CView::OnSetFocus(pOldWnd);
</PRE>
<PRE>}
</PRE>
<P>If there is an active item and its server is loaded, that active item gets focus.
If not, focus remains with the old window, and it appears to the user that the click
was ignored.</P>
<P><B><I>OnSize()  </I></B>OnSize(), shown in Listing 14.15, is called
when the application is resized by the user.</P>
<P>
<H4>Listing 14.15  ShowStringView.cpp--CShowStringView::OnSize()</H4>
<PRE>void CShowStringView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
if (pActiveItem != NULL)
pActiveItem->SetItemRects();
</PRE>
<PRE>}
</PRE>
<P>This resizes the view using the base class function, and then, if there is an
active item, tells it to adjust to the resized view.</P>
<P><B><I>OnCancelEditCntr()  </I></B>OnCancelEditCntr() is called when
a user who has been editing in place presses Esc. The server must be closed, and
the object stops being active. The code is shown in Listing 14.16.</P>
<P>
<H4>Listing 14.16  ShowStringView.cpp--CShowStringView::OnCancelEditCntr()</H4>
<PRE>void CShowStringView::OnCancelEditCntr()
{
// Close any in-place active item on this view.
COleClientItem* pActiveItem =
GetDocument()->GetInPlaceActiveItem(this);
if (pActiveItem != NULL)
{
pActiveItem->Close();
}
ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
</PRE>
<PRE>}
</PRE>
<P><B><I>CShowStringCntrItem</I>  </B>The container item class is a completely
new addition to ShowString. It describes an item that is contained in the document.
As you've already seen, the document and the view use this object quite a lot, primarily
through the m_pSelection member variable of CShowStringView. It has no member variables
other than those inherited from the base class, COleClientItem. It has overrides
for a lot of functions, though. They are as follows:</P>
<UL>
<LI>A constructor
<P>
<LI>A destructor
<P>
<LI>GetDocument()
<P>
<LI>GetActiveView()
<P>
<LI>OnChange()
<P>
<LI>OnActivate()
<P>
<LI>OnGetItemPosition()
<P>
<LI>OnDeactivateUI()
<P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -