用MFC的對話方塊製作一個簡易的圖片瀏覽器
環境:VS2012,OpenCV 2.4.9
功能描述:
功能1:點選OPEN按鈕,選擇圖片並開啟,下方顯示圖片的資訊;
功能2:把圖片拖曳到OPEN按鈕上,也可以實現開啟功能,支援多檔案同時開啟
意義:MFC練手程式,涉及一些知識點
過程:
1、前期工作
建立MFC工程,命名“showPicture”,取消unicode,選擇對話方塊,其它預設;
選擇Release;
新增opencv的包含目錄和庫目錄,新增依賴項。
2、對話方塊編輯
a.刪除“TODO: 在此放置對話方塊控制元件。”控制元件,把“確認”和“取消”控制元件的“Visible”屬性設為False;
b.新增Button控制元件,修改以下屬性:
ID:IDC_BUTTON_OPEN
Acccept Files:True
Caption:OPEN
c.新增Group Box 控制元件,Caption屬性改為information;
d.新增5個Static Text控制元件,Caption屬性依次改為filename、format、depth、h、w;
e.每個Static Text控制元件對應新增一個Edit Contral控制元件,ID依次為IDC_EDIT_filename、IDC_EDIT_FORMAT、IDC_EDIT_DEPTH、IDC_EDIT_H、IDC_EDIT_W,全部的Read Only屬性設為True,依次新增成員變數Edit_filename、Edit_format、Edit_depth、Edit_h、Edit_w
f.對文字框左對齊和頂端對齊
如圖:
3、編碼實現功能1
a.新增標頭檔案image.h
#pragma once #pragma comment(lib,"opencv_highgui249.lib") #pragma comment(lib,"opencv_core249.lib") #pragma comment(lib,"opencv_imgproc249.lib") #include <opencv2/opencv.hpp> #define EPS 2.2204E-16 using namespace std; using namespace cv; class image { public: image(void); ~image(void); public: Mat img; };
b.為OPEN按鈕新增事件處理程式OnBnClickedButtonOpen()
void CshowPictureDlg::OnBnClickedButtonOpen()
{
// TODO: 在此新增控制元件通知處理程式程式碼
CFileDialog fDlg(TRUE, _TEXT("*"), NULL, 4|2,
_TEXT("全部檔案(*.*)|*.*|全部檔案(*.*)|*.*||"));
// 呼叫 DoModal() 方法來開啟對話方塊
if (fDlg.DoModal() == IDOK)
{
// 設定編輯框1的內容為選擇檔案的路徑
// GetPathName() --> 返回選定檔案的完整路徑
CString path;
path = fDlg.GetPathName();
if(!path.IsEmpty())
{
img = imread((LPCSTR)path,CV_LOAD_IMAGE_ANYCOLOR);
CString imageName;
imageName = path;
imageName.MakeReverse();
int index=imageName.Find('\\');
imageName = imageName.Left(index);
imageName.MakeReverse();
//顯示影象資訊
CString info;
info.Format("%d",img.rows);
Edit_h.SetWindowText(info);
info.Format("%d",img.cols);
Edit_w.SetWindowText(info);
int depth;
switch(img.depth())
{
case 0 :;
case 1 :depth=8;break;
case 2 :;
case 3 :depth=16;break;
}
info.Format("%d",depth);
Edit_depth.SetWindowText(info+"bits");
index = imageName.Find('.');
info = imageName.Right(imageName.GetLength()-index-1);
Edit_format.SetWindowText(info);
info = imageName;
Edit_filename.SetWindowText(info);
//顯示影象
namedWindow((LPCSTR)imageName, CV_WINDOW_NORMAL);
resizeWindow((LPCSTR)imageName,img.cols,img.rows);
imshow((LPCSTR)imageName,img);
}
}
}
showPictureDlg.h中新增
#include "image.h"
以及新增成員變數
private:
Mat img;
至此,執行程式可以實現功能1。
4、編碼實現功能2
在3的基礎上繼續;
a.用類嚮導新增一個MFC類,基類為CButton,類名為CFileButton,該類用於實現拖曳檔案至OPEN按鈕並開啟的功能;
b.為CFileButton新增ON_WM_DROPFILES訊息,並編輯訊息函式
// CFileButton 訊息處理程式
void CFileButton::OnDropFiles(HDROP hDropInfo)
{
// TODO: 在此新增訊息處理程式程式碼和/或呼叫預設值
destroyAllWindows();
char *lpszFileName=new char[512];
int nFileCount,i;
nFileCount=::DragQueryFile
(hDropInfo,0xFFFFFFFF,NULL,512);
CString path;
UINT nChars;
Mat img;
for (i=0;i < nFileCount;i++)
{
nChars=::DragQueryFile
(hDropInfo,i,&lpszFileName[0],512);
path = lpszFileName;
path = path.Left(nChars);
if(!path.IsEmpty())
{
img = imread((LPCSTR)path,CV_LOAD_IMAGE_ANYCOLOR);
if(!img.empty())
{
CString imageName;
imageName = path;
imageName.MakeReverse();
int index=imageName.Find('\\');
imageName = imageName.Left(index);
imageName.MakeReverse();
//顯示影象資訊
HWND hWnd = ::FindWindow(NULL,"showPicture");
info.h.Format("%d",img.rows);
info.w.Format("%d",img.cols);
int depth;
switch(img.depth())
{
case 0 :;
case 1 :depth=8;break;
case 2 :;
case 3 :depth=16;break;
}
info.depth.Format("%d",depth);
index = imageName.Find('.');
info.format = imageName.Right(imageName.GetLength()-index-1);
info.filename = imageName;
HWND hEdit = ::GetDlgItem(hWnd,IDC_EDIT_H); // 取得控制元件的指標
::SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)(LPCSTR)(info.h));
hEdit = ::GetDlgItem(hWnd,IDC_EDIT_W); // 取得控制元件的指標
::SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)(LPCSTR)(info.w));
hEdit = ::GetDlgItem(hWnd,IDC_EDIT_DEPTH); // 取得控制元件的指標
::SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)(LPCSTR)(info.depth));
hEdit = ::GetDlgItem(hWnd,IDC_EDIT_FORMAT); // 取得控制元件的指標
::SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)(LPCSTR)(info.format));
hEdit = ::GetDlgItem(hWnd,IDC_EDIT_filename); // 取得控制元件的指標
::SendMessage(hEdit,WM_SETTEXT,0,(LPARAM)(LPCSTR)(info.filename));
//顯示影象
namedWindow((LPCSTR)imageName, CV_WINDOW_NORMAL);
resizeWindow((LPCSTR)imageName,img.cols,img.rows);
imshow((LPCSTR)imageName,img);
}
else
{
MessageBox("fail to open!");
return;
}
}
else
{
MessageBox("path is invalid!");
return;
}
}
::DragFinish (hDropInfo); //釋放記憶體
i=0;
delete []lpszFileName;
}
FileButton.h中新增成員變數
public:
struct info
{
CString depth;
CString format;
CString filename;
CString h;
CString w;
}info;
並新增
#include "image.h"
c.把CFileButton類繫結到OPEN按鈕
修改showPictureDlg.h
新增成員變數
public:
CFileButton m_FileButton;
新增標頭檔案
#include "FileButton.h"
修改showPictureDlg.cpp
改寫對話方塊的DoDataExchange函式
void CshowPictureDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_EDIT_H, Edit_h);
DDX_Control(pDX, IDC_EDIT_W, Edit_w);
DDX_Control(pDX, IDC_EDIT_FORMAT, Edit_format);
DDX_Control(pDX, IDC_EDIT_DEPTH, Edit_depth);
DDX_Control(pDX, IDC_EDIT_filename, Edit_filename);
DDX_Control(pDX, IDC_BUTTON_OPEN, m_FileButton);//增加了這一句
}
至此,執行程式可以實現功能2和功能1。
附:涉及的知識點
1、CString的使用,例如字串的提取、型別轉換
參考:
2、拖曳檔案的功能
參考:
3、SendMessage向控制元件傳送訊息。為什麼要用這種方式?在對話方塊原本的cpp裡是不需要這麼麻煩的,但因為這裡自定義了一個CFileButton類,不能通過Edit控制元件的成員變數來傳值,只能用這種方法。
參考:
4、擴充套件控制元件功能的一種辦法。這裡通過新建一個CFileButton類,使Button控制元件支援檔案拖曳的功能。很奇怪的一點:Button控制元件有一個接受檔案的屬性,但為什麼就沒有一個類似OnDropFiles的事件處理程式?或者是我不知道而已。
還有一種方法是自定義控制元件,但感覺挺麻煩的。這裡要實現的功能比較簡單,可能這種方式可用於實現一些複雜的功能。