本文代码借鉴CMFCEditBrowseCtrl代码,综合CSWEdit代码整理成稿。
头文件定义(CSWBrowseEdit.h):
#pragma once
// CSWBrowseEdit
class CSWBrowseEdit : public CSWEdit
{
DECLARE_DYNAMIC(CSWBrowseEdit)
public:
CSWBrowseEdit();
// Attributes
public:
enum BrowseMode
{
BrowseMode_None,
BrowseMode_Default,
BrowseMode_File,
BrowseMode_Folder,
};
CSWBrowseEdit::BrowseMode GetMode() const { return m_Mode; }
protected:
int m_nButtonWidth;
BOOL m_bIsPressed;
BOOL m_bIsHighLighted;
BOOL m_bIsCaptured;
BOOL m_bDefaultImage;
CRect m_rcButton;
CSize m_szImage;
std::string m_sLabel;
std::string m_sDefFileExt;
std::string m_sFileFilter;
BrowseMode m_Mode;
CImageList m_ImageBrowse;
// Operations
public:
void EnableBrowseButton(BOOL bEnable = TRUE, LPCTSTR szLabel = _T("..."));
void EnableFileBrowseButton(LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFilter = NULL);
void EnableFolderBrowseButton();
void SetBrowseButtonImage(HICON hIcon, BOOL bAutoDestroy = TRUE);
void SetBrowseButtonImage(HBITMAP hBitmap, BOOL bAutoDestroy = TRUE);
void SetBrowseButtonImage(UINT uiBmpResId);
// Overrides
public:
virtual BOOL PreTranslateMessage(MSG* pMsg);
virtual void OnBrowse();
virtual void OnDrawBrowseButton(CDC* pDC, CRect rect, BOOL bIsPressed, BOOL bIsButtonHot);
virtual void OnChangeLayout();
virtual void OnAfterUpdate();
virtual BOOL OnIllegalFileName(CString& strFileName);
// Implementation
public:
virtual ~CSWBrowseEdit();
protected:
//{{AFX_MSG(CSWBrowseEdit)
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp);
afx_msg void OnNcPaint();
afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
afx_msg void OnNcLButtonDblClk(UINT nHitTest, CPoint point);
afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point);
afx_msg void OnCancelMode();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg LRESULT OnNcHitTest(CPoint point);
afx_msg LRESULT OnInitControl(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
void SetInternalImage();
};
源码实现(CSWBrowseEdit.cpp):
// ..\Controls\Edit\SWEditBrowseCtrl.cpp : 实现文件
//
#include "stdafx.h"
#include "CSWBrowseEdit.h"
// CSWBrowseEdit
IMPLEMENT_DYNAMIC(CSWBrowseEdit, CEdit)
CSWBrowseEdit::CSWBrowseEdit()
{
m_rcButton.SetRectEmpty();
m_bIsPressed = FALSE;
m_bIsHighLighted = FALSE;
m_bIsCaptured = FALSE;
m_Mode = BrowseMode_None;
m_szImage = CSize(0, 0);
m_nButtonWidth = 20;
m_bDefaultImage = TRUE;
}
CSWBrowseEdit::~CSWBrowseEdit()
{
}
BEGIN_MESSAGE_MAP(CSWBrowseEdit, CEdit)
//{{AFX_MSG_MAP(CSWBrowseEdit)
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_NCCALCSIZE()
ON_WM_NCPAINT()
ON_WM_NCHITTEST()
ON_WM_NCMOUSEMOVE()
ON_WM_CANCELMODE()
ON_WM_LBUTTONDOWN()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONUP()
ON_MESSAGE(WM_MFC_INITCTRL, &CSWBrowseEdit::OnInitControl)
ON_WM_CTLCOLOR_REFLECT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// CSWBrowseEdit 消息处理程序
void CSWBrowseEdit::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_bIsCaptured)
{
ReleaseCapture();
m_bIsPressed = FALSE;
m_bIsCaptured = FALSE;
m_bIsHighLighted = FALSE;
RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
if (m_rcButton.PtInRect(point))
OnBrowse();
return;
}
CEdit::OnLButtonUp(nFlags, point);
}
void CSWBrowseEdit::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bIsCaptured)
{
BOOL bIsPressed = m_rcButton.PtInRect(point);
if (bIsPressed != m_bIsPressed)
{
m_bIsPressed = bIsPressed;
RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
}
return;
}
if (m_bIsHighLighted)
{
if (!m_rcButton.PtInRect(point))
{
m_bIsHighLighted = FALSE;
ReleaseCapture();
RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
}
}
CEdit::OnMouseMove(nFlags, point);
}
void CSWBrowseEdit::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)
{
CSWEdit::OnNcCalcSize(bCalcValidRects, lpncsp);
if (m_Mode != BrowseMode_None)
{
lpncsp->rgrc [0].right -= m_nButtonWidth;
}
}
HBRUSH CSWBrowseEdit::CtlColor(CDC* pDC, UINT nCtlColor)
{
return CSWEdit::CtlColor(pDC, nCtlColor);
}
void CSWBrowseEdit::OnNcPaint()
{
CSWEdit::OnNcPaint();
if (m_Mode == BrowseMode_None)
return;
CWindowDC dc(this);
CRect rcWindow;
GetWindowRect(rcWindow);
ScreenToClient(rcWindow);
rcWindow.OffsetRect(-rcWindow.left, -rcWindow.top);
m_rcButton = rcWindow;
m_rcButton.left = m_rcButton.right - m_nButtonWidth;
m_rcButton.DeflateRect(1, 1);
m_rcButton.top += 1;
m_rcButton.bottom -= 1;
CRect rcClip = m_rcButton;
CRgn rgnClip;
rgnClip.CreateRectRgnIndirect(&rcClip);
dc.SelectClipRgn(&rgnClip);
OnDrawBrowseButton(&dc, rcClip, m_bIsPressed, m_bIsHighLighted);
dc.SelectClipRgn(NULL);
}
LRESULT CSWBrowseEdit::OnNcHitTest(CPoint point)
{
CPoint ptClient = point;
ScreenToClient(&ptClient);
if (m_Mode != BrowseMode_None && m_rcButton.PtInRect(ptClient))
{
return HTCAPTION;
}
return CEdit::OnNcHitTest(point);
}
void CSWBrowseEdit::OnDrawBrowseButton(CDC* pOrgDC, CRect rect, BOOL bIsPressed, BOOL bHighlight)
{
ASSERT(m_Mode != BrowseMode_None);
ASSERT_VALID(pOrgDC);
CMemDC dcMem(*pOrgDC, rect);
CDC* pDC = &dcMem.GetDC();
COLORREF clrText = afxGlobalData.clrBtnText;
pDC->FillRect(&rect, &afxGlobalData.brBtnFace);
CRect rectFrame = rect;
rectFrame.InflateRect(0, 1, 1, 1);
pDC->Draw3dRect(rectFrame, afxGlobalData.clrBtnDkShadow, afxGlobalData.clrBtnDkShadow);
rectFrame.DeflateRect(1, 1);
pDC->DrawEdge(rectFrame, bIsPressed ? BDR_SUNKENINNER : BDR_RAISEDINNER, BF_RECT);
int iImage = 0;
if (m_ImageBrowse.GetSafeHandle() != NULL)
{
if (m_bDefaultImage)
{
switch (m_Mode)
{
case BrowseMode_Folder:
iImage = 0;
break;
case BrowseMode_File:
iImage = 1;
break;
}
}
CPoint ptImage;
ptImage.x = rect.CenterPoint().x - m_szImage.cx / 2;
ptImage.y = rect.CenterPoint().y - m_szImage.cy / 2;
if (bIsPressed)
{
ptImage.x++;
ptImage.y++;
}
m_ImageBrowse.Draw(pDC, iImage, ptImage, ILD_NORMAL);
}
else if (!m_sLabel.empty())
{
COLORREF clrTextOld = pDC->SetTextColor(clrText);
int nTextMode = pDC->SetBkMode(TRANSPARENT);
CFont* pOldFont = (CFont*) pDC->SelectStockObject(DEFAULT_GUI_FONT);
CRect rectText = rect;
rectText.DeflateRect(1, 2);
rectText.OffsetRect(0, -2);
if (bIsPressed)
rectText.OffsetRect(1, 1);
pDC->DrawText(m_sLabel.c_str(), rectText, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
pDC->SetTextColor(clrTextOld);
pDC->SetBkMode(nTextMode);
pDC->SelectObject(pOldFont);
}
}
void CSWBrowseEdit::EnableBrowseButton(BOOL bEnable/* = TRUE*/, LPCTSTR szLabel/* = _T("...")*/)
{
ASSERT_VALID(this);
ENSURE(GetSafeHwnd() != NULL);
ENSURE(szLabel != NULL);
m_Mode = bEnable ? BrowseMode_Default : BrowseMode_None;
m_sLabel = szLabel;
m_ImageBrowse.DeleteImageList();
m_szImage = CSize(0, 0);
OnChangeLayout();
}
void CSWBrowseEdit::OnChangeLayout()
{
ASSERT_VALID(this);
ENSURE(GetSafeHwnd() != NULL);
m_nButtonWidth = max(20, m_szImage.cx + 8);
SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE);
if (m_Mode != BrowseMode_None)
{
GetWindowRect(m_rcButton);
ScreenToClient(&m_rcButton);
m_rcButton.left = m_rcButton.right - m_nButtonWidth;
}
else
{
m_rcButton.SetRectEmpty();
}
}
void CSWBrowseEdit::OnBrowse()
{
ASSERT_VALID(this);
ENSURE(GetSafeHwnd() != NULL);
switch (m_Mode)
{
case BrowseMode_Folder:
if (afxShellManager != NULL)
{
CString strFolder;
GetWindowText(strFolder);
CString strResult;
CFolderPickerDialog dlg(strFolder);
if (dlg.DoModal() == IDOK && strFolder != dlg.GetPathName())
{
SetWindowText(dlg.GetPathName());
SetModify(TRUE);
OnAfterUpdate();
}
if (GetParent() != NULL)
{
GetParent()->RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
}
//if (afxShellManager->BrowseForFolder(strResult, this, strFolder) &&
// (strResult != strFolder))
//{
// SetWindowText(strResult);
// SetModify(TRUE);
// OnAfterUpdate();
//}
}
else
{
ASSERT(FALSE);
}
break;
case BrowseMode_File:
{
CString strFile;
GetWindowText(strFile);
if (!strFile.IsEmpty())
{
TCHAR fname [_MAX_FNAME];
_tsplitpath_s(strFile, NULL, 0, NULL, 0, fname, _MAX_FNAME, NULL, 0);
CString strFileName = fname;
strFileName.TrimLeft();
strFileName.TrimRight();
if (strFileName.IsEmpty())
{
strFile.Empty();
}
const CString strInvalidChars = _T("*?<>|");
if (strFile.FindOneOf(strInvalidChars) >= 0)
{
if (!OnIllegalFileName(strFile))
{
SetFocus();
return;
}
}
}
CFileDialog dlg(TRUE, !m_sDefFileExt.empty() ? (LPCTSTR)m_sDefFileExt.c_str() : (LPCTSTR)NULL, strFile, 0, !m_sFileFilter.empty() ? (LPCTSTR)m_sFileFilter.c_str() : (LPCTSTR)NULL, NULL);
if (dlg.DoModal() == IDOK && strFile != dlg.GetPathName())
{
SetWindowText(dlg.GetPathName());
SetModify(TRUE);
OnAfterUpdate();
}
if (GetParent() != NULL)
{
GetParent()->RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
}
}
break;
}
SetFocus();
}
BOOL CSWBrowseEdit::OnIllegalFileName(CString& strFileName)
{
CString strError;
strError.LoadString(AFX_IDP_INVALID_FILENAME);
CString strMessage;
strMessage.Format(_T("%s\r\n%s"), strFileName, strError);
MessageBox(strMessage, NULL, MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
void CSWBrowseEdit::SetBrowseButtonImage(HICON hIcon, BOOL bAutoDestroy)
{
if (m_ImageBrowse.GetSafeHandle() != NULL)
{
m_ImageBrowse.DeleteImageList();
}
if (hIcon == NULL)
{
m_szImage = CSize(0, 0);
return;
}
ICONINFO info;
::GetIconInfo(hIcon, &info);
BITMAP bmp;
::GetObject(info.hbmColor, sizeof(BITMAP), (LPVOID) &bmp);
m_szImage.cx = bmp.bmWidth;
m_szImage.cy = bmp.bmHeight;
::DeleteObject(info.hbmColor);
::DeleteObject(info.hbmMask);
UINT nFlags = ILC_MASK;
switch (bmp.bmBitsPixel)
{
case 4:
default:
nFlags |= ILC_COLOR4;
break;
case 8:
nFlags |= ILC_COLOR8;
break;
case 16:
nFlags |= ILC_COLOR16;
break;
case 24:
nFlags |= ILC_COLOR24;
break;
case 32:
nFlags |= ILC_COLOR32;
break;
}
m_ImageBrowse.Create(bmp.bmWidth, bmp.bmHeight, nFlags, 0, 0);
m_ImageBrowse.Add(hIcon);
m_bDefaultImage = FALSE;
if (bAutoDestroy)
{
::DestroyIcon(hIcon);
}
}
void CSWBrowseEdit::SetBrowseButtonImage(HBITMAP hBitmap, BOOL bAutoDestroy)
{
if (m_ImageBrowse.GetSafeHandle() != NULL)
{
m_ImageBrowse.DeleteImageList();
}
if (hBitmap == NULL)
{
m_szImage = CSize(0, 0);
return;
}
BITMAP bmp;
::GetObject(hBitmap, sizeof(BITMAP), (LPVOID) &bmp);
m_szImage.cx = bmp.bmWidth;
m_szImage.cy = bmp.bmHeight;
UINT nFlags = ILC_MASK;
switch (bmp.bmBitsPixel)
{
case 4:
default:
nFlags |= ILC_COLOR4;
break;
case 8:
nFlags |= ILC_COLOR8;
break;
case 16:
nFlags |= ILC_COLOR16;
break;
case 24:
nFlags |= ILC_COLOR24;
break;
case 32:
nFlags |= ILC_COLOR32;
break;
}
m_ImageBrowse.Create(bmp.bmWidth, bmp.bmHeight, nFlags, 0, 0);
HBITMAP hbmpCopy = (HBITMAP) ::CopyImage(hBitmap, IMAGE_BITMAP, 0, 0, 0);
m_ImageBrowse.Add(CBitmap::FromHandle(hbmpCopy), RGB(192, 192, 192));
::DeleteObject(hbmpCopy);
m_bDefaultImage = FALSE;
if (bAutoDestroy)
{
::DeleteObject(hBitmap);
}
}
void CSWBrowseEdit::SetBrowseButtonImage(UINT uiBmpResId)
{
if (m_ImageBrowse.GetSafeHandle() != NULL)
{
m_ImageBrowse.DeleteImageList();
}
if (uiBmpResId == 0)
{
m_szImage = CSize(0, 0);
return;
}
CMFCToolBarImages images;
if (!images.Load(uiBmpResId))
{
ASSERT(FALSE);
return;
}
SetBrowseButtonImage((HBITMAP) ::CopyImage(images.GetImageWell(), IMAGE_BITMAP, 0, 0, 0), TRUE /* bAutoDestroy */);
m_bDefaultImage = FALSE;
}
void CSWBrowseEdit::EnableFileBrowseButton(LPCTSTR lpszDefExt/* = NULL*/, LPCTSTR lpszFilter/* = NULL*/)
{
ASSERT_VALID(this);
ENSURE(GetSafeHwnd() != NULL);
m_Mode = BrowseMode_File;
m_sDefFileExt = lpszDefExt == NULL ? _T("") : lpszDefExt;
m_sFileFilter = lpszFilter == NULL ? _T("") : lpszFilter;
SetInternalImage();
OnChangeLayout();
}
void CSWBrowseEdit::EnableFolderBrowseButton()
{
ASSERT_VALID(this);
ENSURE(GetSafeHwnd() != NULL);
ENSURE(afxShellManager != NULL); // You need to call CWinAppEx::InitShellManager() first!
m_Mode = BrowseMode_Folder;
SetInternalImage();
OnChangeLayout();
}
void CSWBrowseEdit::SetInternalImage()
{
if (m_ImageBrowse.GetSafeHandle() != NULL)
{
m_ImageBrowse.DeleteImageList();
}
UINT uiImageListResID = afxGlobalData.Is32BitIcons() ? IDB_AFXBARRES_BROWSE32 : IDB_AFXBARRES_BROWSE;
LPCTSTR lpszResourceName = MAKEINTRESOURCE(uiImageListResID);
ENSURE(lpszResourceName != NULL);
HBITMAP hbmp = (HBITMAP) ::LoadImage(
AfxFindResourceHandle(lpszResourceName, RT_BITMAP), lpszResourceName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
if (hbmp == NULL)
{
TRACE(_T("Can't load bitmap: %x\n"), uiImageListResID);
return;
}
BITMAP bmpObj;
::GetObject(hbmp, sizeof(BITMAP), &bmpObj);
UINT nFlags = ILC_MASK;
switch (bmpObj.bmBitsPixel)
{
case 4:
default:
nFlags |= ILC_COLOR4;
break;
case 8:
nFlags |= ILC_COLOR8;
break;
case 16:
nFlags |= ILC_COLOR16;
break;
case 24:
nFlags |= ILC_COLOR24;
break;
case 32:
nFlags |= ILC_COLOR32;
break;
}
m_ImageBrowse.Create(16, 16, nFlags, 0, 0);
m_ImageBrowse.Add(CBitmap::FromHandle(hbmp), RGB(255, 0, 255));
m_szImage = CSize(16, 16);
m_bDefaultImage = TRUE;
}
void CSWBrowseEdit::OnAfterUpdate()
{
if (GetOwner() == NULL)
{
return;
}
GetOwner()->PostMessage(EN_CHANGE, GetDlgCtrlID(), (LPARAM) GetSafeHwnd());
GetOwner()->PostMessage(EN_UPDATE, GetDlgCtrlID(), (LPARAM) GetSafeHwnd());
}
void CSWBrowseEdit::OnNcMouseMove(UINT nHitTest, CPoint point)
{
if (!m_bIsCaptured)
{
CPoint ptClient = point;
ScreenToClient(&ptClient);
if (m_rcButton.PtInRect(ptClient))
{
SetCapture();
m_bIsHighLighted = TRUE;
RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
}
}
CEdit::OnNcMouseMove(nHitTest, point);
}
void CSWBrowseEdit::OnCancelMode()
{
CEdit::OnCancelMode();
if (IsWindowEnabled())
{
ReleaseCapture();
}
m_bIsPressed = FALSE;
m_bIsCaptured = FALSE;
m_bIsHighLighted = FALSE;
RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
}
void CSWBrowseEdit::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_Mode != BrowseMode_None && m_rcButton.PtInRect(point))
{
SetFocus();
m_bIsPressed = TRUE;
m_bIsCaptured = TRUE;
SetCapture();
RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
return;
}
CEdit::OnLButtonDown(nFlags, point);
}
void CSWBrowseEdit::OnRButtonDown(UINT nFlags, CPoint point)
{
if (m_Mode != BrowseMode_None && m_rcButton.PtInRect(point))
{
return;
}
CEdit::OnRButtonDown(nFlags, point);
}
void CSWBrowseEdit::OnRButtonUp(UINT nFlags, CPoint point)
{
if (m_Mode != BrowseMode_None && m_rcButton.PtInRect(point))
{
return;
}
CEdit::OnRButtonUp(nFlags, point);
}
BOOL CSWBrowseEdit::PreTranslateMessage(MSG* pMsg)
{
switch (pMsg->message)
{
case WM_SYSKEYDOWN:
if (m_Mode != BrowseMode_None && (pMsg->wParam == VK_DOWN || pMsg->wParam == VK_RIGHT))
{
OnBrowse();
return TRUE;
}
break;
}
return CEdit::PreTranslateMessage(pMsg);
}
int __stdcall UTF8ToString(LPCSTR lpSrc, CString& strDst, int nLength)
{
LPTSTR lpDst = NULL;
int count = ::MultiByteToWideChar(CP_UTF8, 0, lpSrc, nLength, NULL, 0);
if (count <= 0)
{
return 0;
}
LPWSTR lpWide = new WCHAR[count + 1];
memset(lpWide, 0, (count + 1) * sizeof(WCHAR));
::MultiByteToWideChar(CP_UTF8, 0, lpSrc, nLength, lpWide, count);
#ifdef _UNICODE
lpDst = lpWide;
#else
count = ::WideCharToMultiByte(::GetACP(), 0, lpWide, -1, NULL, 0, NULL, 0);
if (count > 0)
{
lpDst = new char[count + 1];
memset(lpDst, 0, count + 1);
::WideCharToMultiByte(::GetACP(), 0, lpWide, -1, lpDst, count, NULL, 0);
}
delete[] lpWide;
#endif
strDst = lpDst;
delete[] lpDst;
return count;
}
#include "afxtagmanager.h"
LRESULT CSWBrowseEdit::OnInitControl(WPARAM wParam, LPARAM lParam)
{
DWORD dwSize = (DWORD)wParam;
BYTE* pbInitData = (BYTE*)lParam;
CString strDst;
::UTF8ToString((LPSTR)pbInitData, strDst, dwSize);
CTagManager tagManager(strDst);
CString strBrowseMode;
if (tagManager.ExcludeTag(PS_MFCEditBrowse_BrowseMode, strBrowseMode))
{
if (!strBrowseMode.IsEmpty())
{
int nBrowseMode = _ttoi((LPCTSTR)strBrowseMode);
switch (nBrowseMode)
{
case MFC_EB_MODE_NONE:
EnableBrowseButton(FALSE);
break;
case MFC_EB_MODE_FILE:
EnableFileBrowseButton();
break;
case MFC_EB_MODE_FOLDER:
EnableFolderBrowseButton();
break;
case MFC_EB_MODE_CUSTOM:
EnableBrowseButton();
break;
}
}
}
return 0;
}
效果图: