摘要: 本文主要介紹了一種在MFC應用程序中實現起來比較方便的浏覽PDF、Word格式文檔文件的方法,同時給出了具體的編程步驟和較詳細的實現代碼。
概述
隨著網絡技術的迅速發展,越來越多的電子圖書資料能夠更加方便的從網上被檢索、下載。其文件格式也不僅限於Html格式的Web頁,PDF、Word等多種格式也逐漸成為網絡資料交換的主流文件格式。尤其在一些科研、技術類網站,有相當數量的科技文獻都是以上述格式來發布的,而且從傳統習慣上大多數科研人員也更傾向於閱讀PDF或Word格式的文獻資料。
雖然使用Acrobat Reader和Word等專用軟件能夠比較方便的閱讀上述格式的資料文件,但如果需要在自己編寫的應用程序中打開上述格式文檔仍免不了自己動手進行處理。有多種途徑可以實現此目的:通過創建子進程直接調用外部Acrobat Reader或Word應用程序打開指定文檔;使用COM自動化技術在應用程序中嵌入Acrobat Reader或Word而打開指定文檔;使用合適的ActiveX控件等等。其中,第一種方法是在應用程序之外打開文檔,會使程序顯的不是很“專業”,第二種方法同樣會在打開文檔而使嵌入對象處於現場激活狀態時將Acrobat Reader或Word程序控制菜單嵌入到自己的程序當中,而在許多情況下這並不是我們所希望的。本文將針對最後一種方式,即通過對“Microsoft Web浏覽器”ActiveX控件的使用而在應用程序中完成對PDF、Word格式文檔文件的打開、顯示。當用戶用以該方法編寫的應用程序在打開這些格式文檔文件時將不再感覺是在Acrobat Reader或Word程序中的浏覽。
控件的創建
“Microsoft Web浏覽器”控件隨Visual C++開發環境一起安裝到系統。從“Project”菜單下“Add To Project”彈出菜單的“Components and Controls…”子菜單彈出“Components and Controls Gallery”對話框,進入“Registered ActiveX Controls”目錄並選中“Microsoft Web浏覽器”控件,點擊“Insert”按鈕將其添加到VC++開發環境的控件工具欄中。
通常對ActiveX控件的使用多是在資源視圖中將指定的ActiveX控件拖拽到相應的對話框中,並完成對其屬性的設置和對事件處理函數的添加。但由於本程序應用“Microsoft Web浏覽器”控件的目的是為了浏覽PDF和Word等格式的文檔,因此應用程序框架采取多文檔視圖結構比較合適,在這種情況下顯然不能再以傳統方式創建控件而應通過代碼來完成動態創建。
在將 “Microsoft Web浏覽器”控件插入到工程後,派生於CWnd類的CWebBrowser2類被添加到工程,它提供了一個可供重載使用的虛函數Create()和一個類成員函數Create():
virtual BOOL Create(LPCTSTR lpszClassName,LPCTSTR lpszWindowName,DWord dwStyle,const RECT& rect,CWnd* pParentWnd, UINT nID,CCreateContext* pContext = NULL);
BOOL Create(LPCTSTR lpszWindowName,DWord dwStyle,const RECT& rect, CWnd* pParentWnd, UINT nID,
CFile* pPersist = NULL, BOOL bStorage = FALSE,
BSTR bstrLicKey = NULL);
通過該函數將可以象動態創建編輯框、按鈕等標准控件一樣動態創建。這裡需要特別指出的是,一個“Microsoft Web浏覽器”控件只能負責對一個文檔的維護,也就是說,在多文檔結構的本程序中需要為每一個打開的文檔分配一個“Microsoft Web浏覽器”控件以進行管理。這在具體實施上,只需在文檔或視圖類中聲明CWebBrowser2類對象即可。下面這段代碼在視圖類完成,在OnInitialUpdate()函數更新視圖時完成對控件的動態創建,創建的控件將占據視圖的全部客戶區:
CWebBrowser2 m_Web;
……
// 得到客戶區
CRect rect;
GetClIEntRect(&rect);
// 創建控件窗體
m_Web.Create(NULL, WS_CHILD | WS_VISIBLE, rect, this, ID_Word);
文檔的打開顯示
本程序在文件打開顯示上采取的策略是:由程序框架負責獲取需要打開的文件路徑,並新建一文檔。在視圖更新“Microsoft Web浏覽器”控件創建完畢後,由CWebBrowser2類成員函數Navigate ()負責對具體文檔的維護管理。這部分工作的具體處理代碼如下:
// 主框架類:
// 顯示打開文件對話框
CFileDialog fileDlg(TRUE, "*.doc", "*.doc", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Word文件(*.doc)|*.doc|PDF文件(*.pdf)|*.pdf|Web頁(*.htm)|*.htm|所有文件(*.*)|*.*||", NULL);
if (fileDlg.DoModal() == IDOK)
{
// 得到文件路徑
m_sPath = fileDlg.GetPathName();
// 新建文檔
PostMessage(WM_COMMAND, ID_FILE_NEW, 0);
}
……
// 視圖類:
// 得到並保存要打開的文件路徑
m_sFilePath = ((CMainFrame*)AfxGetApp()-〉GetMainWnd())-〉m_sPath;
((CMainFrame*)AfxGetApp()-〉GetMainWnd())-〉m_sPath = "about:blank";
// 打開指定的文件
m_Web.Navigate(m_sFilePath, NULL, NULL, NULL, NULL);
// 窗體設置為大小可變
m_Web.SetResizable(TRUE);
為了在刷新視圖或窗口尺寸變更時能夠即使刷新顯示,還需要在OnDraw()函數和WM_SIZE消息響應函數OnSize()中添加額外的處理代碼:
// 重繪窗口 (OnDraw()函數)
if (m_Web.m_hWnd != NULL)
m_Web.RedrawWindow();
……
void CShowWordVIEw::OnSize(UINT nType, int cx, int cy)
{
CVIEw::OnSize(nType, cx, cy);
if (m_Web.m_hWnd != NULL)
{
// 得到新的客戶區
CRect rect;
GetClIEntRect(&rect);
// 設置新的窗口位置
m_Web.SetWindowPos(&wndTop, rect.left, rect.top, rect.Width(), rect.Height(), NULL);
// 重繪窗體
m_Web.RedrawWindow();
}
}
其中,SetWindowPos()函數將重新設置“Microsoft Web浏覽器”控件窗口的放置位置以使其能夠占據尺寸更改後的文檔窗口的全部客戶區大小。
小結
上圖展示了程序實際運行效果,不僅能夠同時浏覽Word格式文檔和PDF文檔,還能夠同時打開、並列顯示多個PDF文檔(在Acrobat Reader中雖然能夠同時打開多個文檔但不能並列顯示)。此外,本文雖然論述的是PDF和Word格式文檔文件的打開,但由於實際是通過CWebBrowser2類來完成具體的文檔打開和顯示處理的,因此支持的文檔格式並不局限於PDF和Word格式,只要符合IE接口規范的任意一種文件格式如Html、JPEG等,使用本文所述方法同樣能夠將其打開、顯示。本文所述程序在Windows 2000 Professional下由Microsoft Visual C++ 6.0編譯運行通過。需要有Microsoft Word 2000和Acrobat Reader 5.0以上版本軟件的支持。