Creating and Using Annotations (C++ 5.0 and later)

Note:

This topic is for Document/Medical only.

Take the following steps to add code that demonstrates the creation and deletion, saving and loading, and copying and pasting of annotation objects. This code also demonstrates the related events. Message boxes prompt for user actions that trigger events.

1.

Start with the project that you created in Loading and Displaying an Image.

2.

Add The #import and #include statements to your program so you can access LEAD Annotation COM:

 

a.

In the Project Workspace, click the FileView tab.

 

b.

Double-click the tutor files folder to open it.

 

c.

Double-click the Header Files folder to open it.

 

d.

Double-click the StdAfx.h file to edit it.

 

e.

Add the following lines to the end of the file (keep in mind, you may have to change the path to where the dll's reside):

 #import "c:\\winnt\\system32\\ltran14n.dll" no_namespace, named_guids

3.

Add an ILEADRasterAnnotation pointer to the class and Set it to NULL in the constructor.

 

a.

In the Project Workspace, click the Class View tab.

 

b

Select the CTutorDlg class

 

c.

Right-click and choose "Add Member Variable"

 

d.

For Variable Type enter ILEADRasterAnnotation

 

e.

For Variable Declaration enter *m_pRasterAnn

 

f.

Leave Access as Public

 

g.

Click the OK button

 

h.

In the Class View tab, double-click the CTutorDlg constructor function

 

i.

Add the following line to the end of the construtor

m_pRasterAnn = NULL;

4.

Go to the Project WorkSpace and click the ResourceView tab. Double-click Dialog and double-click IDD_TUTOR_DIALOG to bring up the application's dialog box.

5.

Add four new buttons at the top of the form. To do this for each button, select the button control on the Controls toolbar. Then, click and drag to position the button on the dialog box. Then double-click the button to change its properties. Set the properties as follows:

 

ID

Caption

 

IDC_ANNTOGGLE

Start

 

IDC_IOTOGGLE

Save

 

IDC_CLIPBOARDTOGGLE

Copy

 

IDC_REALIZE

Realize

6.

Add the following code to the end of OnInitDialog before the return statement:

 

   if (m_pRasterAnn == NULL)
   {
      CoCreateInstance(
         CLSID_LEADRasterAnnotation, 
         NULL, 
         CLSCTX_ALL,
         IID_ILEADRasterAnnotation, 
         (void**)&m_pRasterAnn);
   }

7.

Add code for the user mode toggle button (IDC_ANNTOGGLE). To do so, press Ctrl-W to go to the MFC Class Wizard; then do the following:

 

a.

Click the Message Maps tab.

 

b.

In the Class Name combo box, select CTutorDlg.

 

c.

In the Object IDs list box, select IDC_ANNTOGGLE

 

d.

In the Messages list box, select BN_CLICKED.

 

e.

Click the Add function button. Choose OK for the default function name (OnAnntoggle).

 

f.

Click the Edit Code button to start entering the code.

void CTutorDlg::OnAnntoggle() 
{
   CString Caption;
   // Use the button to toggle between design mode and run mode
   CWnd *pButton = GetDlgItem(IDC_ANNTOGGLE);
   pButton->GetWindowText(Caption);
   if (Caption == TEXT("Start"))
   {
      m_pRasterAnn->PutAnnUserMode(ANN_USERMODE_DESIGN);
      m_pRasterAnn->PutAnnTool(ANN_TOOL_BUTTON);
      // Make run mode the next thing.
      pButton->SetWindowText(TEXT("Run Mode"));
      MessageBox(TEXT("In design mode now. Draw a button object."));
   }
   else if (Caption == TEXT("Design Mode"))
   {
      m_pRasterAnn->PutAnnUserMode(ANN_USERMODE_DESIGN);
      m_pRasterAnn->PutAnnTool(ANN_TOOL_BUTTON);
      // Make run mode the next thing.
      pButton->SetWindowText(TEXT("Run Mode"));
   }
   else // The button takes us to run mode
   {
      m_pRasterAnn->PutAnnUserMode(ANN_USERMODE_RUN);
      MessageBox(TEXT("Click on your new button."));
      pButton->SetWindowText(TEXT("Design Mode"));
   }
}

8.

Add code for the load and save toggle button (IDC_IOTOGGLE). To do so, press Ctrl-W to go to the MFC Class Wizard; then do the following:

 

a.

Click the Message Maps tab.

 

b.

In the Class Name combo box, select CTutorDlg.

 

c.

In the Object IDs list box, select IDC_IOTOGGLE.

 

d.

In the Messages list box, select BN_CLICKED.

 

e.

Click the Add function button. Choose OK for the default function name (OnIotoggle).

 

f.

Click the Edit Code button to start entering the code.

void CTutorDlg::OnIotoggle() 
{
   CString strFileName = TEXT("c:\\lead\\images\\tmp.ann");
   CString Caption;
   int nRet;
   // Disable errors so that we can trap our own.
   m_pRasterAnn->PutEnableMethodErrors(VARIANT_FALSE);
   // Use the button to toggle between saving and loading annotations
   CWnd *pButton = GetDlgItem(IDC_IOTOGGLE);
   pButton->GetWindowText(Caption);
   if (Caption == TEXT("Save"))
   {
      // Do nothing if there are no annotations.
    HANDLE hAnnContainer = NULL;
      hAnnContainer = (HANDLE)m_pRasterAnn->GetAnnContainer ();
      if (hAnnContainer == 0)
            return;
      // Save All annotations.
      nRet = m_pRasterAnn->AnnSave(strFileName.AllocSysString(), ANN_FMT_NATIVE, FALSE, SAVE_OVERWRITE, 0);
      if (nRet == 0)
      {
         pButton->SetWindowText(TEXT("Load"));
         // Make loading the next thing.
         MessageBox(TEXT("Use the right mouse button to delete any annotations, then click Load."));
      }
      else
      {
         TCHAR  buffer[50];
         wsprintf(buffer, TEXT("LEAD Error %d"), nRet);
         MessageBox(buffer, TEXT("ERROR"), MB_OK);
      }
   }
   else // We are loading annotations
   {
      // Make sure we are in design mode
      m_pRasterAnn->PutAnnUserMode(ANN_USERMODE_DESIGN);
      // Load the annotations.
      nRet = m_pRasterAnn->AnnLoad( strFileName.AllocSysString(), 1);
      if (nRet == 0)
         pButton->SetWindowText(TEXT("Save"));
      else
         MessageBox(TEXT("No annotations to load."));
   }
}

9.

Add code for the clipboard toggle button (IDC_CLIPBOARDTOGGLE). To do so, press Ctrl-W to go to the MFC Class Wizard; then do the following. (Note that Copy, Cut, and Paste are available as automated popup menu options. This code is for tailoring your application.)

 

a.

Click the Message Maps tab.

 

b.

In the Class Name combo box, select CTutorDlg.

 

c.

In the Object IDs list box, select IDC_CLIPBOARDTOGGLE.

 

d.

In the Messages list box, select BN_CLICKED.

 

e.

Click the Add function button. Choose OK for the default function name (OnIotoggle).

 

f.

Click the Edit Code button to start entering the code.

void CTutorDlg::OnClipboardtoggle() 
{
   CString Caption;
   int nRet;
   // Disable errors so that we can trap our own.
   m_pRasterAnn->PutEnableMethodErrors(VARIANT_FALSE);
   // Use the button to toggle between copying and pasting annotations
   CWnd *pButton = GetDlgItem(IDC_CLIPBOARDTOGGLE);
   pButton->GetWindowText(Caption);
   if (Caption == TEXT("Copy")
   {
      // Do nothing if there are no annotations.
      HANDLE hAnnContainer = NULL;
      hAnnContainer  = (HANDLE) m_pRasterAnn->GetAnnContainer();
      if (hAnnContainer == NULL)
         return;
      // Copy all annotations to the clipboard.
      nRet = m_pRasterAnn->AnnCopy(ANN_FMT_NATIVE, FALSE, -1);
      if (nRet == 0)
      {
         // Make pasting the next thing.
         pButton->SetWindowText(TEXT("Paste");
         MessageBox(TEXT("Use the right mouse button to delete any annotations, then click Paste"));
      }
      else
      {
         TCHAR  buffer[50];
         wsprintf(buffer, "LEAD Error %d", nRet);
         MessageBox(buffer, TEXT("ERROR"), MB_OK);
      }
   }
   else // We are pasting annotations
   {
      // Make sure we are in design mode
      
      m_pRasterAnn->PutAnnUserMode(ANN_USERMODE_DESIGN);
      // Paste the annotations
      VARIANT_BOOL bPasteReady = 0;
      bPasteReady = m_pRasterAnn->GetAnnPasteReady();
      if (bPasteReady == VARIANT_TRUE)
      {
         m_pRasterAnn->AnnPaste();
         pButton->SetWindowText(TEXT("Copy");
      }
      else
      {
         MessageBox(TEXT("No annotations to paste"));
      }
   }
}

10.

Add code for the realize button (IDC_REALIZE), which renders the annotation objects to the bitmap. To do so, press Ctrl-W to go to the MFC Class Wizard; then do the following:

 

a.

Click the Message Maps tab.

 

b.

In the Class Name combo box, select CTutorDlg.

 

c.

In the Object IDs list box, select IDC_REALIZE.

 

d.

In the Messages list box, select BN_CLICKED.

 

e.

Click the Add function button. Choose OK for the default function name (OnIotoggle).

 

f.

Click the Edit Code button to start entering the code.

void CTutorDlg::OnRealize() 
{
   m_pRasterAnn->AnnRealize(VARIANT_FALSE);
   MessageBox(TEXT("Annotations are now rendered to the bitmap."));
}

11.

To add the code for annotation events, edit the TUTORDLG.H file and change the definition of CTutorDlg : CDialog by inserting the following lines after DECLARE_MESSAGE_MAP()

public:
   CRasterAnnSink    *m_pRasterAnnSink;
   IConnectionPoint   *m_pCP;
   DWORD               m_dwCookie;

12.

Edit the TUTORDLG.CPP file and add the following code to the end of the OnInitDialog function:

//Unlock the annotation support
   //Note that L_KEY_DOCUMENT is a #define for the support key that you must supply
   m_LEADRasterView1.GetRaster().UnlockSupport(L_SUPPORT_DOCUMENT, L_KEY_DOCUMENT);
   
   //Instantiate the sink class and hold a pointer to it.
   m_pRasterAnnSink = new CRasterAnnSink;
   m_pRasterAnnSink->m_pDlg = this;
   
   //Attach the annotation object to the raster view control      
   IDispatch *pDispatch=NULL;
   (m_LEADRasterView1.GetControlUnknown())->QueryInterface(IID_IDispatch, (void**)&pDispatch);
   m_pRasterAnn->PutAnnParentRasterView(pDispatch);
   
   if(pDispatch)
      pDispatch->Release();
   
   //Establish a connection between source and sink.
   LPUNKNOWN pUnkSink = m_pRasterAnnSink->GetIDispatch(FALSE);
   AfxConnectionAdvise(m_pRasterAnn, DIID__LEADRasterAnnotationEvents, pUnkSink, FALSE, &m_dwCookie); 

13.

Press Ctrl-W to go to the MFC Class Wizard; then do the following:

 

a.

Click the Add Class button.

 

b.

Click New....

 

c.

Type CRasterAnnSink for the name of the class

 

d.

Select CCmdTarget for the base class of the new class.

 

e.

Under Automation, click the Automation radio button.

 

f.

Click OK to create the class.

 

g.

In the RasterAnnSink.h file, move the destructor so that it is public:

// Implementation
   virtual ~CRasterAnnSink();
protected:

 

h.

In the RasterAnnSink.h file, add the following to the top of the file:

 

 

class CTutorDlg;

 

i.

In the RasterAnnSink.h file, add the following to the CRasterAnnSink class in the //Attributes public section:

  // Attributes

  public:

 CTutorDlg *m_pDlg;

 

j.

In the RasterAnnSink.cpp file, add the following to the top of the file (after the #include "RasterAnnSink.h")

#include "tutorDlg.h"

14.

Add #include statements so you can access the new class:

 

a.

In the Project Workspace, click the FileView tab.

 

b.

Double-click the tutor files folder to open it.

 

c.

Double-click the Header Files folder to open it.

 

d.

Double-click the StdAfx.h file to edit it.

 

e.

Add the following lines to the end of the file:

 

 

#include <AFXCTL.H>

 

 

#include "RasterAnnSink.h"

15.

Edit the header for the Sink class:

 

a.

In the Project Workspace, click the FileView tab.

 

b.

Double-click the tutor files folder to open it.

 

c.

Double-click the Header Files folder to open it.

 

d.

Double-click the RasterAnnSink.h file to edit it.

 

e.

Add the following just before //}}AFX_MSG:

 

 

afx_msg void OnAnnCreate(long hAnnObject);

 

 

afx_msg void OnAnnDestroy(long hAnnObject);

 

 

afx_msg void OnAnnClicked(long hAnnObject);

 

 

afx_msg void OnAnnDrawn(long hAnnObject);

16.

Edit the source for the Sink class:

 

a.

In the Project Workspace, click the FileView tab.

 

b.

Double-click the tutor files folder to open it.

 

c.

Double-click the Source Files folder.

 

d.

Double-click the RasterAnnSink.cpp file to edit it.

 

e.

Add the following to the DISPATCH_MAP:

 

   DISP_FUNCTION_ID(CRasterAnnSink, "OnAnnCreate", 5, OnAnnCreate,  VT_EMPTY,VTS_I4)
   DISP_FUNCTION_ID(CRasterAnnSink, "OnAnnDestroy",6, OnAnnDestroy, VT_EMPTY,VTS_I4)
   DISP_FUNCTION_ID(CRasterAnnSink, "OnAnnClicked",7, OnAnnClicked, VT_EMPTY,VTS_I4)
   DISP_FUNCTION_ID(CRasterAnnSink, "OnAnnDrawn",  8, OnAnnDrawn,   VT_EMPTY,VTS_I4)

 

 

f.

Inside the BEGIN_INTERFACE_MAP section, change the INTERFACE_PART to the following:

INTERFACE_PART(CRasterAnnSink, DIID__LEADRasterAnnotationEvents, Dispatch)

 

g.

Add the following to the end of the file:

void CRasterAnnSink::OnAnnClicked(long hAnnObject)
{
   long lTag;
   CString strMsg;
   
   m_pDlg->m_pRasterAnn->AnnGetTag(hAnnObject);
   lTag  = m_pDlg->m_pRasterAnn->GetAnnTag();
   strMsg.Format(TEXT("This is what we do for the button tagged %d"), lTag);
   AfxMessageBox( strMsg);
}

void CRasterAnnSink::OnAnnCreate(long hAnnObject)
{
   AnnObjectType ObjectType;
   
   //Update the tag if we need one.
   static int nNewTag=0;
   m_pDlg->m_pRasterAnn->AnnGetType(hAnnObject);
   ObjectType =  m_pDlg->m_pRasterAnn->GetAnnType();
   if ((ObjectType == ANN_OBJECT_BUTTON) || (ObjectType == ANN_OBJECT_HOTSPOT))
   {
      nNewTag++;
      m_pDlg->m_pRasterAnn->AnnSetTag(hAnnObject, nNewTag);
   }
}

void CRasterAnnSink::OnAnnDestroy(long hAnnObject)
{
   CString strMsg;
   long lTag;
   m_pDlg->m_pRasterAnn->AnnGetTag(hAnnObject);
   lTag = m_pDlg->m_pRasterAnn->GetAnnTag();

   strMsg.Format(TEXT("The object tagged %d is deleted"), lTag);
   AfxMessageBox(strMsg);
}

void CRasterAnnSink::OnAnnDrawn(long hAnnObject)
{
   m_pDlg->m_pRasterAnn->PutAnnTool(ANN_TOOL_SELECT);
   AfxMessageBox(TEXT("Use the right mouse button to modify this object; then click on Run Mode to test it."));
}

17.

Press Ctrl-W to go to the MFC Class Wizard; then do the following:

 

a.

In the Class name combo box, select CTutorDlg.

 

b.

In the Object IDs list box, select CTutorDlg.

 

c.

In the Messages list box, select WM_DESTROY.

 

d.

Click the Add function button. Choose OK for the default function name (OnDestroy).

 

e.

Click the Edit Code button to start entering the code.

18.

Enter new code as follows:

void CTutorDlg::OnDestroy() 
{
   //Terminate a connection between source and sink.
   LPUNKNOWN pUnkSink = m_pRasterAnnSink->GetIDispatch(FALSE);
   AfxConnectionUnadvise(m_pRasterAnn, DIID__LEADRasterAnnotationEvents,
                         pUnkSink, FALSE, m_dwCookie); 
   delete m_pRasterAnnSink;
   m_pRasterAnn->Release();
   CDialog::OnDestroy();
}

19.

Compile and run your program to test it.