在GOPaint的設計研究過程中,我一直希望能夠實現這樣的結果(A B C 3個步驟)

在我之前的博客里面,曾經有過縮略圖顯示的現就(
http://www.cnblogs.com/jsxyhelu/p/5493329.html ),也應用到了實際的項目中。但是現在過了一段時間后回頭再看,當時的實現放吧是粗糙的。基於MFC已經提供的基礎庫,通過c++自己的重載機制,應該能夠得到精巧的實現,但是肯定需要去重寫一些東西。
為了解決問題,達到效果,進行了一些研究。
一、CMFCShellList和CMFCShellTree基本結合;
這兩個控件是新出現的,使用起來比較簡單。



DIalog的方便之處就在於“所見及所得”,這里綁定控件變量。
在initdialog中添加兩句,就能得到效果
m_ctrlShellList.ModifyStyle(LVS_TYPEMASK, LVS_ICON);
m_ctrlShellTree.SetRelatedList( &m_ctrlShellList);
m_ctrlShellTree.SetRelatedList( &m_ctrlShellList);

Tree的結果和List的結果是級聯的。但是顯示不了縮略圖,只能夠顯示圖標。
二、對CMFCShellList和CMFCShellTree的繼承和研究;
如果要更好地使用這兩個類,必須首先繼承之后使用,在這個過程中,我才能夠重寫函數和事件:
在原始的mfcshelllistctrl控件中,如果雙擊其中的文件(圖片)的話,是采用默認的打開程序打開文件(圖片),那么我要把這個修改成使用我自己的程序來打開圖片,所以首先就需要進行CMFCShellListCtrl的重載
#
pragma once
# include "afxshelllistctrl.h"
class CGOShellListCtrl :
public CMFCShellListCtrl
{
public :
CGOShellListCtrl( void);
~CGOShellListCtrl( void);
DECLARE_MESSAGE_MAP()
afx_msg void OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult);
};
# include "afxshelllistctrl.h"
class CGOShellListCtrl :
public CMFCShellListCtrl
{
public :
CGOShellListCtrl( void);
~CGOShellListCtrl( void);
DECLARE_MESSAGE_MAP()
afx_msg void OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult);
};
修改
OnNMDblclk事件
void CGOShellListCtrl
:
:OnNMDblclk(NMHDR
*pNMHDR, LRESULT
*pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast <LPNMITEMACTIVATE >(pNMHDR);
CString Filename;
for( int i = 0; i <GetItemCount(); i ++)
{
if( GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED )
{
GetItemPath(Filename,i);
AfxMessageBox(Filename);
}
}
*pResult = 0;
}
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast <LPNMITEMACTIVATE >(pNMHDR);
CString Filename;
for( int i = 0; i <GetItemCount(); i ++)
{
if( GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED )
{
GetItemPath(Filename,i);
AfxMessageBox(Filename);
}
}
*pResult = 0;
}
得到能夠顯示雙擊文件絕對地址的目的:

那么下一步,需要將這個地址傳入主程序,這個方法很多。
同樣,也可以對CMFCShellTreeCtrl進行重載,得到當前的目錄地址。
三、但是還是需要顯示縮略圖;
但是,核心問題還是沒有解決,現在還是顯示不了縮略圖。
一開始我想通過重寫List的CUSTOMDRAW事件來達到效果,但是研究一些資料之后,可以修改ListCtrl的樣式,卻無法修改主要內容。雖然CUSTOMDRAW中也提供了控價重構的機制,但是隱藏在許多宏中,不方便使用;
最后我開始反思之前我的ThumbNail是如何實現的,最后決定還是采用imagelist綁定的方法來解決問題。
這時,可以肯定基本是不用CMFCShellListCtrl了,而是要繼承原始的CListCtrl,基本思路就是從CMFCTreeListCtrl中獲得路徑名稱,而后在自定義的List控件中顯示出來。並且還要截獲List的點擊事件,那么獲得選擇圖片的絕對地址。
其實在這個過程中,過濾后綴名等操作也是可以完成的。
四、DLG下的實驗
為了進行試驗,我首先在DLG下面進行了實驗。效果良好:

雙擊打開圖片,感覺速度上面還是有些問題。
這個DLG的例子可以參考附錄里面的
thumbnail
例子,基本就是根據其修改的。
五、融合到GOPaint中去:
GOPaint是我目前正在做的OpenCV圖像處理框架庫,力圖能夠提供大中型圖像處理軟件所需的基礎環境。那么縮略圖也是必須的一個環節。

采用的是浮動窗口,比較美觀。畢竟要把主要區域用出來,顯示圖片。

在這里融合的時候,我就有意識地將代碼進行合並。

對於ListCtrl和CMFCShellTreeCtrl分別進行了重載。這里還是選擇了ListCtrl進行重載,因為CMFCShellListCtrl中的優秀特性這里用不起來。
SplitePane繼承於CDockablePane,是一個懸浮框類。那么在這個懸浮框中我將
CGOShellTreeCtrl m_wndTree;
CGOListCtrl m_ListThumbnail;
CPaneSplitter m_wndSplitter;
CImageList m_ImageListThumb;
CGOListCtrl m_ListThumbnail;
CPaneSplitter m_wndSplitter;
CImageList m_ImageListThumb;
都放在其中,還包括一些存儲用的變量。這樣的結果就是如果以后在其他地方需要使用,只需要將這幾個文件拷貝過去復用就可以了。
#
pragma once
# include "afxshelltreectrl.h"
# include "afxshelllistctrl.h"
# include "panesplitter.h"
# include "GOShellTreeCtrl.h"
# include "GOListCtrl.h"
# include "afxwin.h"
# include <vector >
// CSplitePane
class CSplitePane : public CDockablePane
{
DECLARE_DYNAMIC(CSplitePane)
public :
CSplitePane();
virtual ~CSplitePane();
protected :
DECLARE_MESSAGE_MAP()
public :
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnDestroy();
public :
CGOShellTreeCtrl m_wndTree;
CGOListCtrl m_ListThumbnail;
CPaneSplitter m_wndSplitter;
CPaneToolBar m_wndToolbar;
CImageList m_ImageListThumb;
int m_nSelectedItem;
void DrawThumbnails( void);
std : :vector <CString > m_VectorImageNames;
BOOL GetImageFileNames( void);
void GetThumbnailsAndShow( void);
};
# include "afxshelltreectrl.h"
# include "afxshelllistctrl.h"
# include "panesplitter.h"
# include "GOShellTreeCtrl.h"
# include "GOListCtrl.h"
# include "afxwin.h"
# include <vector >
// CSplitePane
class CSplitePane : public CDockablePane
{
DECLARE_DYNAMIC(CSplitePane)
public :
CSplitePane();
virtual ~CSplitePane();
protected :
DECLARE_MESSAGE_MAP()
public :
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnDestroy();
public :
CGOShellTreeCtrl m_wndTree;
CGOListCtrl m_ListThumbnail;
CPaneSplitter m_wndSplitter;
CPaneToolBar m_wndToolbar;
CImageList m_ImageListThumb;
int m_nSelectedItem;
void DrawThumbnails( void);
std : :vector <CString > m_VectorImageNames;
BOOL GetImageFileNames( void);
void GetThumbnailsAndShow( void);
};
具體的實現代碼已經不重要了,因為原理已經講明白了。這里的代碼編寫需要對繼承、控件等都有一些了解。如果有不清楚的地方可以跟帖討論。
五、小結:
這樣一個效果,前后做了有2天,6-8個小時。我想還需要加強以下幾個方面的聯系:
1、對VS環境中提供的幾個新控件的認識。不僅是能夠了解使用,最好是能夠找到實現的代碼去跟一根。這樣以后需要實現自己想要的效果的時候有所依據。
MFC本身是系統的、連貫的。它自己的代碼很多時候就是最好的參考;
2、對繼承、復用等面向對象基本原理要加強理解。
3、
解決問題的方法比結果更重要。這個縮略圖的問題可以說我一直就在思考和想解決,最后還是下定決心,達到了預計目的,各中過程也比較漫長。現在反思過來看,還是要緊緊抓住需要解決問題的核心,不要過度耽擱於細節。解決問題的方法一定是有的,相關的資料及時少,也是肯定有幫助的;
4、不斷積累。這里探索的過程和探索的結果,將來都會成為很好的基礎。
六、參考資料
找到一了一些的例子:

能夠直接顯示縮略圖,但是版本比較老了,很多地方需要修改。
3、codeprojects Thumbnails viewer and image processing using GDI+ and MFC 這篇我跟了一下,效果很好,但是太復雜。
3、最后還是在自己的以前看過的代碼里面找到了最合適的例子 thumbnail。原始鏈接可能是codeprojects上的,這里直接放出代碼。

4、如果想學習DockPane,那么codeprojects Understanding CDockablePane 這篇是最好的

感謝閱讀至此,希望有所幫助。