⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 browsectrl.cpp

📁 《MFC窗口程序设计》书籍源码 详细讲解MFC框架程序设计
💻 CPP
📖 第 1 页 / 共 3 页
字号:
///////////////////////////////////////////////////////////////////////////
//				BrowseCtrl.cpp
//
// CBrowseCtrl is a CButton derived control used to let the user browse for
// files or folders on their systems.
//
// CBrowseCtrl integrates an edit-box and a browse-button together so the
// develops only need to maintain one control in their projects instead of two.

// Moreover, CBrowseCtrl draws its own "build-in" images on the browse-button
// without requiring the developers to include any extra icon, bitmap or other
// image resources.
//
// Written by Abin (abinn32@yahoo.com)
//
// History:
// 
// Jan 08, 2004 - Initial public release.
// Jan 09, 2004 - 1, Improved drawing functions to properly handle the case in
//                   which the control client area is too small to be drawn.
//                   In debug mode it will provide a message box to inform the
//                   developer about that issue.
//                2, Improved the edit box so it acts better upon receiving and
//                   losing the input focus. 
// Jan 10, 2004 - 1, Fixed a problem where the edit bix is not properly redrawn
//                   in some mouse events. Thanks to JOHN11.
//                2, Added method "GetSelectedCount" which returns the number of
//                   items the user has selected in the most recent file/folder
//                   dialog that was terminated by IDOK.
//                3, Improved the mouse/focus events monitoring functions.
//                4, Fixed a drawing glitch when the user clicks on the edges of
//                   the edit box.
//                5, Changed the drawing rects calculating methods for performance
//                   improvement.
// Jan 14, 2004 - 1, Updated "SetPathName" and "GetPathName" member functions.
//                2, Altered the message sending method so the lparam is now a
//                   pointer to this CBrowseCtrl object.
// Jan 22, 2004 - 1, Added methods to monitor whether the user has manually changed
//                   the contents of the edit box when BC_CTL_ALLOWEDIT is set. The
//                   return value of "GetPathName" will also be properly affected.
//                2, The window titles of file/folder dialogs can now be accessed
//                   by calling "SetDialogTitle" and "GetDialogTitle".
//                3, The banner text of folder dialogs can now be accessed by calling
//                   "SetDialogBanner" and "GetDialogBanner".
//                4, Added method "ModifyButtonStyle" to allow convenient style changing.
// Feb 07, 2004 - 1, Improved drawing functions so that images/text are partially drawn
//                   if there is not enough space.
//
/////////////////////////////////////////////////////////////////////////// 

#include "stdafx.h"
#include "BrowseCtrl.h"
#include <afxdlgs.h>
#include <string.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define ICON_WIDTH	16
#define ICON_HEIGHT	16
#define BTN_EDGE	2
#define WIDTH_SPACE	(BTN_EDGE * 2 + 7)

#define EDITCTRL_ID				12345
#define TOOLTIPCTRL_ID			12346
#define ID_TMR_MOUSEMONITOR		12347
#define ID_TMR_FOCUSMONITOR		12348

// color defines
#define BC_COLOR_WHITE	RGB(255, 255, 255)
#define BC_COLOR_BLACK	RGB(0, 0, 0)
#define BC_COLOR_DARK	RGB(128, 128, 128)
#define BC_COLOR_GRAY	RGB(192, 192, 192)
#define BC_COLOR_YELLOW	RGB(255, 255, 0)
#define BC_COLOR_BLUE	RGB(0, 0, 255)
#define BC_COLOR_OLIVE	RGB(128, 128, 0)
#define BC_COLOR_CYAN	RGB(0, 255, 255)
#define BC_COLOR_NAVY	RGB(0, 0, 128)

// maximum buffer length for retrieving pathname
#define MAX_SUM_PATHNAME	65535

// "CLineDraw" class is used for helping on drawing lines, the default behavior of
// CDC::LineTo on not drawing the last pixel could be extremely inconvenient in
// certain cases.
class CLineDraw
{
public:

	// Constructor
	CLineDraw(CDC* pDC, long lInitX = 0, long lInitY = 0)
	{
		ASSERT(pDC != NULL);
		m_pDC = pDC;
		m_ptCur.x = lInitX;
		m_ptCur.y = lInitY;
		m_ptInit.x = lInitX;
		m_ptInit.y = lInitY;
	}

	// Set the point the top-lect corner of the rect, offset the point,
	// then move dc to that point
	void InitOffsetMoveTo(long x, long y)
	{
		m_ptCur = m_ptInit;
		m_ptCur.Offset(x, y);
		m_pDC->MoveTo(m_ptCur);
	}

	// Offset the point and move dc to the point
	void OffsetMoveTo(long x, long y)
	{
		m_ptCur.Offset(x, y);
		m_pDC->MoveTo(m_ptCur);
	}

	// Offset the point and draw a line to the point, then set pixel at the point
	// using the color of current pen stored in the dc
	void OffsetLineTo(long x, long y)
	{
		m_ptCur.Offset(x, y);
		m_pDC->LineTo(m_ptCur);
		m_pDC->GetCurrentPen()->GetLogPen(&m_lgp);
		m_pDC->SetPixel(m_ptCur, m_lgp.lopnColor);
	}

private:
	CDC* m_pDC;
	CPoint m_ptCur;
	LOGPEN m_lgp;
	CPoint m_ptInit;
};

/////////////////////////////////////////////////////////////////////////////
// CBrowseCtrl Implementations
/////////////////////////////////////////////////////////////////////////////

CBrowseCtrl::CBrowseCtrl()
{
	m_dwStyle = BC_BTN_ICON | BC_ICO_ARROWFOLDER; // By default, the "arrow folder" icon is drawn on the browse button
	m_nSelCount = 0;
	m_bEditFocused = FALSE;
	m_nPathNamesLen = 0;
	m_bDlgPopped = FALSE;
	m_nNotifyMsg = 0;
	m_bOwnCreate = FALSE;
	m_bBtnPushed = FALSE;
	m_bMouseIn = FALSE;
	m_sTootipText = _T("浏览");
	m_sDlgBanner = _T("请从列表中选择文件:");
	m_bReadOnlyRef = FALSE;
	m_bOpenFileDialog = TRUE;
	m_dwFileFlags = OFN_ALLOWMULTISELECT | OFN_OVERWRITEPROMPT | OFN_CREATEPROMPT | OFN_ENABLESIZING | OFN_EXPLORER;
	m_nFolderFlags = BIF_RETURNONLYFSDIRS;
	m_sFilter = _T("All Files (*.*)|*.*||");
	m_lpszPathNames = NULL;
	m_bEditChanged = FALSE;
}

CBrowseCtrl::~CBrowseCtrl()
{
	if (m_lpszPathNames != NULL)
		delete [] m_lpszPathNames;
}

BEGIN_MESSAGE_MAP(CBrowseCtrl, CButton)
	//{{AFX_MSG_MAP(CBrowseCtrl)
	ON_WM_PAINT()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	ON_WM_MOUSEMOVE()
	ON_WM_SETFOCUS()
	ON_WM_MOVE()
	ON_WM_SIZE()
	ON_WM_ENABLE()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	//}}AFX_MSG_MAP
	ON_EN_CHANGE(EDITCTRL_ID, OnChangeEdit)
END_MESSAGE_MAP()

void CBrowseCtrl::OnChangeEdit()
{
	if (!m_bDlgPopped && (m_dwStyle & BC_CTL_ALLOWEDIT))
	{
		// The user has changed the edit box contents manually
		m_wndEdit.GetWindowText(m_sEditText);
		m_bEditChanged = TRUE;
	}
}

void CBrowseCtrl::PreSubclassWindow() 
{
	// TODO: Add your specialized code here and/or call the base class
	CButton::PreSubclassWindow();
	if (!m_bOwnCreate)
		CreateCtrl(); // only create the edit/tooltip control once!
}

void CBrowseCtrl::SetButtonStyle(DWORD dwStyles)
{
	// Change the control style
	if (m_dwStyle != dwStyles)
	{
		m_dwStyle = dwStyles;
		if (::IsWindow(m_hWnd))
		{
			RecalculateRects();
			CreateEdit();
			RedrawWindow();
		}	
	}
}

DWORD CBrowseCtrl::GetButtonStyle() const
{
	return m_dwStyle;
}

BOOL CBrowseCtrl::CreateCtrl()
{
	if (!::IsWindow(m_hWnd))
		return FALSE;

	RecalculateRects();

	// Move window text from actual window to the fake button
	if (m_sButtonText.IsEmpty())
		CButton::GetWindowText(m_sButtonText);
	CButton::SetWindowText(_T(""));

	if (!CreateEdit())
	{
		ASSERT(FALSE);
		return FALSE;
	}

	// Create tooltip control
	if (!m_wndTooltip.Create(this))
	{
		ASSERT(FALSE);
		return FALSE;
	}
	
	m_wndTooltip.AddTool(this, m_sTootipText, m_rcButton, TOOLTIPCTRL_ID);
	SetTimer(ID_TMR_FOCUSMONITOR, 1, NULL);
	return TRUE;
}

void CBrowseCtrl::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	COLORREF bkColor = ::GetSysColor(COLOR_BTNFACE);
	
	// TODO: Add your message handler code here
	DrawButtonFrame(&dc, bkColor);

	// Draw text or different images on the browse button
	CRect rect = m_rcContent;

	// If the button is pushed down, make it look sunken.
	if (m_bBtnPushed)
		rect.OffsetRect(1, 1);

	if (m_dwStyle & BC_BTN_ICON)
	{
		if (m_dwStyle & BC_ICO_ARROWFOLDER)
		{
			DrawButtonArrowFolder(&dc, bkColor, rect);
		}
		else if (m_dwStyle & BC_ICO_FOLDER)
		{
			DrawButtonFolder(&dc, bkColor, rect);
		}
		else if (m_dwStyle & BC_ICO_EXPLORER)
		{
			DrawButtonExplorer(&dc, bkColor, rect);
		}
		else 
		{
			// Do we have any other stuff to draw?
		}
	}
	else
	{
		DrawButtonText(&dc, bkColor, rect);
	}
}

void CBrowseCtrl::OnSetFocus(CWnd* pOldWnd) 
{
	KillTimer(ID_TMR_FOCUSMONITOR);
	if (!m_bEditFocused && pOldWnd != &m_wndEdit)
	{
		CButton::OnSetFocus(pOldWnd);
		m_wndEdit.SetFocus();
		m_wndEdit.SetSel(0, -1);
		m_bEditFocused = TRUE;
	}
	SetTimer(ID_TMR_FOCUSMONITOR, 1, NULL);
}

void CBrowseCtrl::OnSetEditFocus()
{
	m_wndEdit.SetSel(0, -1);
}

void CBrowseCtrl::OnKillEditFocus()
{
	m_wndEdit.SetSel(-1, -1);
}

int CBrowseCtrl::DoModal()
{
	// Popup the file/folder dialog
	if (m_bDlgPopped)
		return IDCANCEL;

	m_bDlgPopped = TRUE;

	// Either popup a file dialog, or a folder dialog
	int nRes = (m_dwStyle & BC_CTL_FOLDERSONLY) ? FolderDoModal() : FileDoModal();

	if (m_nNotifyMsg > 0)
		GetParent()->SendMessage(m_nNotifyMsg, (WPARAM)nRes, (LPARAM)this);

	m_bDlgPopped = FALSE;
	return nRes;
}

int CBrowseCtrl::GetSelectedCount() const
{
	return m_nSelCount;
}

void CBrowseCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	CButton::OnLButtonDown(nFlags, point);
	if (m_rcButton.PtInRect(point))
	{
		OnKillEditFocus();
		SetCapture();
		m_bBtnPushed = TRUE;
	}
	RedrawWindow();
}

void CBrowseCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	CButton::OnLButtonUp(nFlags, point);
	if (GetCapture() == this)	
	{
		ReleaseCapture();
		m_bBtnPushed = FALSE;
		RedrawWindow(&m_rcButton);

		if (m_rcButton.PtInRect(point))
			OnButtonClicked();
	}
}

void CBrowseCtrl::DrawButtonFrame(CDC *pDC, COLORREF bkColor) const
{
	CRect rect = m_rcButton;
	pDC->FillSolidRect(&rect, bkColor);

	if (m_dwStyle & BC_BTN_FLAT)
	{
		if (m_bBtnPushed)
		{
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DDKSHADOW), ::GetSysColor(COLOR_3DHIGHLIGHT));
		}
		else
		{
			if (m_bMouseIn)
				pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DHIGHLIGHT), ::GetSysColor(COLOR_3DSHADOW));
		}
	}
	else
	{
		if (!m_bBtnPushed)
		{
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DHIGHLIGHT), ::GetSysColor(COLOR_3DDKSHADOW));
			rect.DeflateRect(1, 1);
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DLIGHT), ::GetSysColor(COLOR_3DSHADOW));
		}
		else
		{
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DDKSHADOW), ::GetSysColor(COLOR_3DDKSHADOW));
			rect.DeflateRect(1, 1);
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DSHADOW), ::GetSysColor(COLOR_3DSHADOW));
		}
	}	
}

BOOL CBrowseCtrl::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class
	m_wndTooltip.RelayEvent(pMsg);

	// Popup the file/folder dialog when user hits "Enter" key when the
	// control window is active
	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
	{
		OnButtonClicked();
		return TRUE;
	}

	return CButton::PreTranslateMessage(pMsg);
}

void CBrowseCtrl::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	if (nIDEvent == ID_TMR_MOUSEMONITOR)
	{
		// monitors mouse enter/leave events
		if (m_bMouseIn)
		{
			POINT pt;
			::GetCursorPos(&pt);
			CRect rect = m_rcButton;
			ClientToScreen(&rect);
			if (!rect.PtInRect(pt))
			{
				KillTimer(ID_TMR_MOUSEMONITOR);
				m_bMouseIn = FALSE;
				OnMouseLeave();
			}
		}
	}
	else if (nIDEvent == ID_TMR_FOCUSMONITOR)
	{
		// monitors control focus events
		if (GetFocus() != &m_wndEdit)
		{
			if (m_bEditFocused)
			{
				m_bEditFocused = FALSE;
				OnKillEditFocus();
			}
		}
		else
		{
			if (!m_bEditFocused)
			{
				m_bEditFocused = TRUE;
				OnSetEditFocus();
			}
		}
	}
			
	CButton::OnTimer(nIDEvent);
}

void CBrowseCtrl::OnDestroy() 
{
	KillTimer(ID_TMR_MOUSEMONITOR);
	KillTimer(ID_TMR_FOCUSMONITOR);
	m_wndEdit.DestroyWindow();
	m_wndTooltip.DestroyWindow();
	CButton::OnDestroy();
}

void CBrowseCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default	
	CButton::OnMouseMove(nFlags, point);
	if (!m_bMouseIn && m_rcButton.PtInRect(point))
	{
		m_bMouseIn = TRUE;
		if (GetCapture() == this)
			m_bBtnPushed = TRUE;
		SetTimer(ID_TMR_MOUSEMONITOR, 1, NULL);
		OnMouseEnter();
	}
}

void CBrowseCtrl::OnMouseEnter()
{
	RedrawWindow(&m_rcButton);
}

void CBrowseCtrl::OnMouseLeave()
{
	m_bBtnPushed = FALSE;
	RedrawWindow();
}

void CBrowseCtrl::SetTooltipText(LPCTSTR lpszText)
{
	m_sTootipText = lpszText;
	if (::IsWindow(m_hWnd))
		m_wndTooltip.UpdateTipText(lpszText, this, TOOLTIPCTRL_ID);
}

void CBrowseCtrl::SetWindowText(LPCTSTR lpszString)
{
	SetButtonText(lpszString);
}

int CBrowseCtrl::GetWindowText(LPTSTR lpszStringBuf, int nMaxCount) const
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -