📄 atlctrlsext.h
字号:
#define TVN_ITEMCHECKED TVN_LAST + 1
class CCheckTreeViewCtrl : public CWindowImpl< CCheckTreeViewCtrl, CTreeViewCtrl >
{
public:
typedef CWindowImpl< CCheckTreeViewCtrl, CTreeViewCtrl > parentClass;
NMTREEVIEW m_nmtv;
// Operations
BOOL SubclassWindow(HWND hWnd)
{
BOOL bRet = parentClass::SubclassWindow(hWnd);
if( bRet ) ModifyStyle(0, TVS_CHECKBOXES);
return bRet;
}
BOOL DeleteAllItems()
{
BOOL bRes = CTreeViewCtrl::DeleteAllItems();
// There's a bug in Windows that seems to remove this style
// whenever the items are deleted.
ModifyStyle(TVS_CHECKBOXES, 0);
ModifyStyle(0, TVS_CHECKBOXES);
return bRes;
}
// Message map and handlers
BEGIN_MSG_MAP(CCheckTreeViewCtrl)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
REFLECTED_NOTIFY_CODE_HANDLER(NM_CLICK, OnClick)
END_MSG_MAP()
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
// First let ListView control initialize everything
LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
ModifyStyle(0, TVS_CHECKBOXES);
return lRet;
}
LRESULT OnClick(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
{
// Send TVN_ITEMCHECKED notifications to parent when check
// state changes.
// MS Kbase Q261289 explains how this is done.
TVHITTESTINFO ht = { 0 };
DWORD dwpos = ::GetMessagePos();
ht.pt.x = GET_X_LPARAM(dwpos);
ht.pt.y = GET_Y_LPARAM(dwpos);
::MapWindowPoints(HWND_DESKTOP, m_hWnd, &ht.pt, 1);
HitTest(&ht);
if( TVHT_ONITEMSTATEICON &ht.flags ) {
::ZeroMemory(&m_nmtv, sizeof(m_nmtv));
m_nmtv.hdr = *pnmh;
m_nmtv.hdr.code = TVN_ITEMCHECKED;
m_nmtv.itemNew.hItem = ht.hItem;
m_nmtv.itemNew.mask = TVIF_STATE | TVIF_PARAM;
GetItem(&m_nmtv.itemNew);
m_nmtv.ptDrag = ht.pt;
// BUG: Tehcnically we could receive two clicks before the first
// message was dispatched since we're using PostMessage() here.
// But it beats other alternatives...
::PostMessage(GetParent(), WM_NOTIFY, idCtrl, (LPARAM) &m_nmtv);
}
bHandled = FALSE;
return 0;
}
};
/////////////////////////////////////////////////////////////////////////////
// Customizable toolbar
// Simple implementation of ToolBar customization support.
// It handles only one ToolBar in total!
// Let the parent window derive from the class; chain it in the message map.
// Call InitToolbar() after creating the ToolBar control.
template< class T >
class CCustomizableToolBarCommands
{
public:
typedef CCustomizableToolBarCommands<T> thisClass;
CSimpleArray<TBBUTTON> m_aButtons;
// Operations
BOOL InitToolBar(HWND hWndToolBar, UINT nResource, BOOL bInitialSeparator = FALSE)
{
ATLASSERT(::IsWindow(hWndToolBar));
// The ToolBar is adjustable!
CToolBarCtrl tb = hWndToolBar;
ATLASSERT(tb.GetStyle() & CCS_ADJUSTABLE); // Need this style to properly function on XP!
tb.ModifyStyle(0, CCS_ADJUSTABLE);
// Gather information about toolbar buttons by building the toolbar.
// Needed so we can reset it later on.
// This code is almost identical to the CFrameWindowImplBase::CreateSimpleToolBarCtrl
// code, but it also needs to build it the exact same way...
HINSTANCE hInst = _Module.GetResourceInstance();
HRSRC hRsrc = ::FindResource(hInst, (LPCTSTR) nResource, RT_TOOLBAR);
if (hRsrc == NULL) return FALSE;
HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc);
if( hGlobal == NULL ) return FALSE;
struct _AtlToolBarData
{
WORD wVersion;
WORD wWidth;
WORD wHeight;
WORD wItemCount;
//WORD aItems[wItemCount]
WORD* items() { return (WORD*)(this+1); }
};
_AtlToolBarData* pData = (_AtlToolBarData*) ::LockResource(hGlobal);
if( pData == NULL ) return FALSE;
ATLASSERT(pData->wVersion==1);
WORD* pItems = pData->items();
// Set initial separator (half width)
if( bInitialSeparator ) {
TBBUTTON bt;
bt.iBitmap = 4;
bt.idCommand = 0;
bt.fsState = 0;
bt.fsStyle = TBSTYLE_SEP;
bt.dwData = 0;
bt.iString = 0;
m_aButtons.Add(bt);
}
// Scan other buttons
int nBmp = 0;
for( int i=0, j= bInitialSeparator ? 1 : 0; i<pData->wItemCount; i++, j++ ) {
if( pItems[i] != 0 ) {
TBBUTTON bt;
bt.iBitmap = nBmp++;
bt.idCommand = pItems[i];
bt.fsState = TBSTATE_ENABLED;
bt.fsStyle = TBSTYLE_BUTTON;
bt.dwData = 0;
bt.iString = 0;
m_aButtons.Add(bt);
}
else {
TBBUTTON bt;
bt.iBitmap = 8;
bt.idCommand = 0;
bt.fsState = 0;
bt.fsStyle = TBSTYLE_SEP;
bt.dwData = 0;
bt.iString = 0;
m_aButtons.Add(bt);
}
}
return TRUE;
}
// Message map and handler
BEGIN_MSG_MAP( thisClass )
NOTIFY_CODE_HANDLER(TBN_BEGINADJUST, OnTbBeginAdjust)
NOTIFY_CODE_HANDLER(TBN_ENDADJUST, OnTbEndAdjust)
NOTIFY_CODE_HANDLER(TBN_RESET, OnTbReset)
NOTIFY_CODE_HANDLER(TBN_TOOLBARCHANGE, OnTbToolBarChange)
NOTIFY_CODE_HANDLER(TBN_QUERYINSERT, OnTbQueryInsert)
NOTIFY_CODE_HANDLER(TBN_QUERYDELETE, OnTbQueryDelete)
NOTIFY_CODE_HANDLER(TBN_GETBUTTONINFO, OnTbGetButtonInfo)
END_MSG_MAP()
LRESULT OnTbBeginAdjust(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& bHandled)
{
ATLASSERT(m_aButtons.GetSize()>0); // Remember to call InitToolBar()!
bHandled = FALSE;
return 0;
}
LRESULT OnTbEndAdjust(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& bHandled)
{
bHandled = FALSE;
return TRUE;
}
LRESULT OnTbToolBarChange(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& bHandled)
{
bHandled = FALSE;
return 0;
}
LRESULT OnTbReset(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
{
LPTBNOTIFY lpTbNotify = (LPTBNOTIFY) pnmh;
// Restore the old button-set
CToolBarCtrl tb = lpTbNotify->hdr.hwndFrom;
while( tb.GetButtonCount() > 0 ) tb.DeleteButton(0);
tb.AddButtons(m_aButtons.GetSize(), m_aButtons.GetData());
return TRUE;
}
LRESULT OnTbQueryInsert(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
{
// Allow all buttons!
return TRUE;
}
LRESULT OnTbQueryDelete(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
{
// All buttons can be deleted!
return TRUE;
}
LRESULT OnTbGetButtonInfo(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
{
LPTBNOTIFY lpTbNotify = (LPTBNOTIFY) pnmh;
CToolBarCtrl tb = lpTbNotify->hdr.hwndFrom;
// The toolbar requests information about buttons that we don't know of...
if( lpTbNotify->iItem >= m_aButtons.GetSize() ) return FALSE;
// Locate tooltip text and copy second half of it.
// This is the same code as CFrameWindowImplBase uses, despite how
// dangerous it may look...
TCHAR szBuff[256] = { 0 };
LPCTSTR pstr = szBuff;
#if (_ATL_VER < 0x0700)
int nRet = ::LoadString(_Module.GetResourceInstance(), m_aButtons[lpTbNotify->iItem].idCommand, szBuff, 255);
#else
int nRet = ATL::AtlLoadString(m_aButtons[lpTbNotify->iItem].idCommand, szBuff, 255);
#endif
for( int i = 0; i < nRet; i++ ) {
if( szBuff[i] == _T('\n') ) {
pstr = szBuff + i + 1;
break;
}
}
lpTbNotify->tbButton = m_aButtons[lpTbNotify->iItem];
::lstrcpyn(lpTbNotify->pszText, pstr, lpTbNotify->cchText);
lpTbNotify->cchText = ::lstrlen(pstr);
return TRUE;
}
};
/////////////////////////////////////////////////////////////////////////////
// ActiveX helpers
#ifdef __ATLHOST_H__
// Load HTML into MSHTML ActiveX control
inline BOOL AtlLoadHTML(IUnknown* pUnkControl, LPCSTR pstrHTML)
{
ATLASSERT(!::IsBadStringPtrA(pstrHTML,-1));
HANDLE hHTMLText = ::GlobalAlloc( GPTR, (::lstrlenA(pstrHTML) + 1) * sizeof(CHAR) );
if( hHTMLText == NULL ) return FALSE;
::lstrcpyA( (CHAR*) hHTMLText, pstrHTML );
IStream* pStream = NULL;
HRESULT Hr = ::CreateStreamOnHGlobal(hHTMLText, TRUE, &pStream);
if( SUCCEEDED(Hr) ) {
IPersistStreamInit* pPersistStreamInit = NULL;
Hr = pUnkControl->QueryInterface(IID_IPersistStreamInit, (LPVOID*) &pPersistStreamInit);
if( SUCCEEDED(Hr) ) {
Hr = pPersistStreamInit->InitNew();
if( SUCCEEDED(Hr) ) Hr = pPersistStreamInit->Load(pStream);
pPersistStreamInit->Release();
}
pStream->Release();
}
return SUCCEEDED(Hr);
};
#endif // __ATLHOST_H__
}; // namespace WTL
#endif // __ATLCTRLSEXT_H__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -