📄 mditabctrl.h
字号:
#pragma once
/////////////////////////////////////////////////////////////////////////////
// MDITabCtrl.h : interface of the CMDITabCtrl class
//
// How to use:
// 1.Place CMDITabCtrl m_MDITab in MDI mainframe class.
// 2.Place CMDITabCtrl& m_MDITab in MDI child class.
// 3.Place PASS_MSG_MAP_MDICHILD_TO_MDITAB(m_MDITab) in the head of MDI child's message map
//
// Note:
// If you click system menu item which has short cut(Ctrl+F6 etc) on frame bar,
// it send WM_COMMAND and send WM_SYSCOMMAND.
// But if you TrackPopup system menu by yourself, only WM_COMMAND is sent.
//
// Why I choose not MDI child window but CMDITabctrl itself as popup menu owner:
// If you cancel popup menu with pressing ESC key or clicking outside
// (how do I know when canceled!?) and select menu on main frame bar,
// cause menu command sender can't be determine,
// I can't skip this message and WM_COMMAND is handled twice.
//
// Written by MB<mb2@geocities.co.jp> 2000.06.28
/////////////////////////////////////////////////////////////////////////////
#include "OleDragDropTabCtrl.h"
#include "HlinkDataObject.h"
namespace MTL
{
// Extended styles
#define MTB_EX_ADDLEFT 0x00000001L
#define MTB_EX_RIGHTCLICKCLOSE 0x00000002L
#define MTB_EX_DELAYED 0x00000004L
#define MTB_EX_MULTILINE 0x00000008L
#define MTB_EX_DOUBLECLICKCLOSE 0x00000010L
#define MTB_EX_XCLICKCLOSE 0x00000020L
#define MTB_EX_RIGHTCLICKREFRESH 0x00000040L
#define MTB_EX_DOUBLECLICKREFRESH 0x00000080L
#define MTB_EX_XCLICKREFRESH 0x00000100L
#define MTB_EX_RIGHTACTIVEONCLOSE 0x00000200L
#define MTB_EX_LEFTACTIVEONCLOSE 0x00000400L
#define MTB_EX_ADDRIGHTACTIVE 0x00000800L
#define MTB_EX_ADDLEFTACTIVE 0x00001000L
#define MTB_EX_WHEEL 0x00002000L
#define MTB_EX_FIXEDSIZE 0x00004000L
#define MTB_EX_ANCHORCOLOR 0x00008000L
//#undef WM_XBUTTONUP
//#define WM_XBUTTONUP 0x020C
class CMDITabCtrl :
public COleDragDropTabCtrl<CMDITabCtrl>
{
public:
DECLARE_WND_CLASS_EX(_T("Mtl_MDI_TabCtrl"), CS_DBLCLKS, COLOR_BTNFACE)
// Constants
// Data members
CWindow m_wndMDIChildProcessing; // while message processing
CMDIWindow m_wndMDIChildPopuping; // while menu popuping (m_bPopup is not enough)
DWORD m_dwExtendedStyle;
CString m_strInitial;
CMenu m_menuPopup;
HWND m_hWndMenuOwner;
bool m_bInsertHere;
int m_nInsertIndex;
int m_nMaxTabItemTextLength;
bool m_bRedrawLocked;
// Constructor
CMDITabCtrl()
: m_dwExtendedStyle(0), m_strInitial(_T("Loading...")),
m_hWndMenuOwner(NULL), m_bInsertHere(false), m_nInsertIndex(-1), m_nMaxTabItemTextLength(30),
m_bRedrawLocked(false)
{
}
BOOL LoadMenu(_U_STRINGorID menu)
{
return m_menuPopup.LoadMenu(menu);
}
void SetMenuOwner(HWND hWndOwner)
{
m_hWndMenuOwner = hWndOwner;
}
void SetMDITabLogFont(const LOGFONT& lf)
{
CFontHandle font;
MTLVERIFY(font.CreateFontIndirect(&lf));
if (font.m_hFont) {
if(m_font.m_hFont != NULL)
m_font.DeleteObject();
m_font.Attach(font.m_hFont);
SetFont(m_font);
Invalidate();
}
}
BOOL GetMDITabLogFont(LOGFONT& lf)
{
if (m_font.m_hFont) {
return m_font.GetLogFont(&lf);
}
return false;
}
int AddTabItem(HWND hWndMDIChild, LPCTSTR lpszText = NULL)
{
if (hWndMDIChild == NULL)
return -1;
// add tab item
int nPos;
int nCurSel = GetCurSel();
if (nCurSel == -1)
nPos = 0;
else if (m_dwExtendedStyle & MTB_EX_ADDLEFT)
nPos = 0;
else if (m_dwExtendedStyle & MTB_EX_ADDLEFTACTIVE)
nPos = nCurSel;
else if (m_dwExtendedStyle & MTB_EX_ADDRIGHTACTIVE)
nPos = nCurSel + 1;
else
nPos = GetItemCount();
BYTE fsState = TCISTATE_ENABLED;
if (m_bRedrawLocked || hWndMDIChild != m_wndMDIChildPopuping.MDIGetActive())
fsState |= TCISTATE_INACTIVE;
return InsertItem(nPos, CTabCtrlItem(lpszText, -1, (DWORD)hWndMDIChild, fsState));
}
// Attributes
int GetTabIndex(HWND hWndMDIChild)
{
if (hWndMDIChild == NULL)
return -1;
for (int i = 0; i < GetItemCount(); ++i) {
DWORD dwData;
GetItemUserData(i, dwData);
if ((HWND)dwData == hWndMDIChild)
return i;
}
return -1;
}
HWND GetTabHwnd(int nIndex)
{
if (nIndex < 0)
return NULL;
DWORD dwData;
GetItemUserData(nIndex, dwData);
return (HWND)dwData;
}
void RightTab()
{
int nIndex = GetCurSel();
int nCount = GetItemCount();
if (nCount < 2)
return;
int nNext = nIndex + 1 < nCount ? nIndex + 1 : 0;
SetCurSelEx(nNext);
}
void SetCurSelEx(int nIndex, bool bActivate = true)
{
SetCurSel(nIndex);
if (bActivate) {
HWND hWnd = GetTabHwnd(nIndex);
ATLASSERT(::IsWindow(hWnd));
m_wndMDIChildPopuping.MDIActivate(hWnd);
}
}
void LeftTab()
{
int nIndex = GetCurSel();
int nCount = GetItemCount();
if (nCount < 2)
return;
int nNext = nIndex - 1 < 0 ? nCount - 1 : nIndex - 1;
SetCurSelEx(nNext);
}
void _SendSelChange(int nIndex)
{
int idCtrl = ::GetDlgCtrlID(m_hWnd);
NMHDR nmh = { m_hWnd, idCtrl, TCN_SELCHANGE };
SendMessage(WM_NOTIFY, (WPARAM)idCtrl, (LPARAM)&nmh);
}
DWORD GetMDITabExtendedStyle() const
{
return m_dwExtendedStyle;
}
DWORD SetMDITabExtendedStyle(DWORD dwExtendedStyle)
{
DWORD dwPrevStyle = m_dwExtendedStyle;
m_dwExtendedStyle = dwExtendedStyle;
if (dwExtendedStyle & MTB_EX_MULTILINE)
ModifyTabCtrl2ExtendedStyle(0, TAB2_EX_MULTILINE);
else
ModifyTabCtrl2ExtendedStyle(TAB2_EX_MULTILINE, 0);
if (dwExtendedStyle & MTB_EX_FIXEDSIZE)
ModifyTabCtrl2ExtendedStyle(0, TAB2_EX_FIXEDSIZE);
else
ModifyTabCtrl2ExtendedStyle(TAB2_EX_FIXEDSIZE, 0);
if (dwExtendedStyle & MTB_EX_ANCHORCOLOR)
ModifyTabCtrl2ExtendedStyle(0, TAB2_EX_ANCHORCOLOR);
else
ModifyTabCtrl2ExtendedStyle(TAB2_EX_ANCHORCOLOR, 0);
return dwPrevStyle;
}
void SetInitialText(LPCTSTR lpszInitialText)
{
m_strInitial = lpszInitialText;
}
void SetMaxTabItemTextLength(int nLength)
{
if (m_nMaxTabItemTextLength == nLength)
return;
m_nMaxTabItemTextLength = nLength;
for (int i = 0; i < GetItemCount(); ++i) {
HWND hWnd = GetTabHwnd(i);
ATLASSERT(::IsWindow(hWnd));
TCHAR szText[MAX_PATH];
::GetWindowText(hWnd, szText, MAX_PATH);
_SetTabText(i, szText);
}
}
int GetMaxTabItemTextLength()
{
return m_nMaxTabItemTextLength;
}
// Operations
void SetMDIClient(HWND hWndMDIClient)
{
ATLASSERT(::IsWindow(hWndMDIClient));
ATLASSERT(m_wndMDIChildPopuping.m_hWndMDIClient == NULL);
m_wndMDIChildPopuping.m_hWndMDIClient = hWndMDIClient;
}
// Message map and handlers
BEGIN_MSG_MAP(CMDITabCtrl)
MSG_WM_RBUTTONUP(OnRButtonUp)
MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
MESSAGE_HANDLER(WM_MBUTTONUP, OnXButtonUp)
REFLECTED_NOTIFY_CODE_HANDLER_EX(TCN_SELCHANGE, OnTcnSelChange)
MSG_WM_COMMAND(OnCommand)
MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
CHAIN_MSG_MAP(COleDragDropTabCtrl<CMDITabCtrl>)
ALT_MSG_MAP(1)// MDI child windows messages
m_wndMDIChildProcessing = hWnd;
MSG_WM_MDIACTIVATE(OnMDIActivate)
MSG_WM_SETTEXT(OnSetText)
m_wndMDIChildProcessing = NULL;
END_MSG_MAP()
LRESULT OnXButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
SetMsgHandled(FALSE);
POINT point = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if (m_dwExtendedStyle & MTB_EX_XCLICKCLOSE) {
int nIndex = HitTest(point);
if (nIndex != -1) {
HWND hWndChild = GetTabHwnd(nIndex);
::PostMessage(hWndChild, WM_CLOSE, 0, 0);
}
}
else if (m_dwExtendedStyle & MTB_EX_XCLICKREFRESH) {
int nIndex = HitTest(point);
if (nIndex != -1) {
HWND hWndChild = GetTabHwnd(nIndex);
::PostMessage(hWndChild, WM_COMMAND, (WPARAM)ID_VIEW_REFRESH, 0);
}
}
return 0;
}
void OnLButtonDblClk(UINT nFlags, CPoint point)
{
SetMsgHandled(FALSE);
if (m_dwExtendedStyle & MTB_EX_DOUBLECLICKCLOSE) {
int nIndex = HitTest(point);
if (nIndex != -1) {
HWND hWndChild = GetTabHwnd(nIndex);
::PostMessage(hWndChild, WM_CLOSE, 0, 0);
}
}
else if (m_dwExtendedStyle & MTB_EX_DOUBLECLICKREFRESH) {
int nIndex = HitTest(point);
if (nIndex != -1) {
HWND hWndChild = GetTabHwnd(nIndex);
::PostMessage(hWndChild, WM_COMMAND, (WPARAM)ID_VIEW_REFRESH, 0);
}
}
}
void OnRButtonUp(UINT nFlags, CPoint point)
{// Overrides
ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnRButtonUp\n"));
int nIndex = HitTest(point);
if (nIndex != -1) {
HWND hWndChild = GetTabHwnd(nIndex);
ATLASSERT(hWndChild != NULL);
if (m_dwExtendedStyle & MTB_EX_RIGHTCLICKCLOSE) {
::PostMessage(hWndChild, WM_CLOSE, 0, 0);
}
else if (m_dwExtendedStyle & MTB_EX_RIGHTCLICKREFRESH) {
::PostMessage(hWndChild, WM_COMMAND, (WPARAM)ID_VIEW_REFRESH, 0);
}
else if (m_menuPopup.m_hMenu) {
ClientToScreen(&point);
CMenuHandle menu = m_menuPopup.GetSubMenu(0);
MTLVERIFY(menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
point.x, point.y, m_hWndMenuOwner != NULL ? m_hWndMenuOwner : hWndChild));
}
else {// system menu (default)
CMenuHandle menuSys = ::GetSystemMenu(hWndChild, FALSE);
ClientToScreen(&point);
m_wndMDIChildPopuping = hWndChild;
_UpdateMenu(menuSys);
menuSys.TrackPopupMenu(TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
point.x, point.y, m_hWnd);// owner is me!!
}
}
SetMsgHandled(FALSE);
}
LRESULT OnTcnSelChange(LPNMHDR lpnhmdr)
{
// Watch OnLButtonDown, this handler will not be called by windows.
// The flat style tab has a wastefull animation.
ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnTcnSelChange : %d\n"), GetCurSel());
int nIndex = GetCurSel();
ATLASSERT(nIndex != -1);
HWND hWndActive = GetTabHwnd(nIndex);
m_wndMDIChildPopuping.MDIActivate(hWndActive);
return 0;
}
LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
ATLASSERT(::IsWindow(m_wndMDIChildPopuping.m_hWndMDIClient));
// for help message line
return ::SendMessage(::GetParent(m_wndMDIChildPopuping.m_hWndMDIClient), WM_MENUSELECT, wParam, lParam);
}
void OnCommand(UINT wNotifyCode, int wID, HWND hwndCtl)
{
ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnCommand - MDI child window:%x\n"), m_wndMDIChildPopuping.m_hWnd);
if (m_wndMDIChildPopuping.m_hWnd == NULL) {// this is not my command message
SetMsgHandled(FALSE);
return;
}
ATLASSERT(m_wndMDIChildPopuping.IsWindow());
CMDIWindow wnd = m_wndMDIChildPopuping;
m_wndMDIChildPopuping = NULL;// It must be reset cause SendMessage(WM_SYSCOMMAND) make one more WM_COMMAND.
if (wID != SC_CLOSE && wID != SC_NEXTWINDOW)
wnd.BringWindowToTop();
// Note: If you send SC_NEXTWINDOW to inactive child window,
// order is broken. Tell me why.
if (wID == SC_NEXTWINDOW)
wnd.MDINext(NULL);// I think NULL is natural.
else if (wID == SC_MAXIMIZE)
wnd.ShowWindow(SW_MAXIMIZE);// without this, frame window maximized. why?
// else if (wID == SC_CLOSE)
// wnd.PostMessage(WM_CLOSE); // without this, debug assertion occurs?
else
wnd.SendMessage(WM_SYSCOMMAND, (WPARAM)wID);
}
void OnMDIChildCreate(HWND hWnd)
{
ATLTRACE2(atlTraceUser, 4, _T("CChildFrame::OnMDIChildCreate\n"));
if (m_bInsertHere) {
BYTE fsState = TCISTATE_ENABLED;
if (m_bRedrawLocked || hWnd != m_wndMDIChildPopuping.MDIGetActive())
fsState |= TCISTATE_INACTIVE;
InsertItem(m_nInsertIndex, CTabCtrlItem(m_strInitial, -1, (DWORD)hWnd, fsState));
return;
}
ATLASSERT(GetTabIndex(hWnd) == -1);
AddTabItem(hWnd, m_strInitial);
ATLTRACE2(atlTraceUser, 4, _T(" new child window found, add tab\n"));
return;
}
void OnMDIActivate(HWND hWndChildDeact, HWND hWndChildAct)
{
ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnMDIActivate\n"));
SetMsgHandled(FALSE);
if (hWndChildAct == NULL)
return;
int nIndex = GetTabIndex(hWndChildAct);
ATLASSERT(nIndex != -1);
if (!m_bRedrawLocked) {
SetItemActive(nIndex);
UpdateWindow();
}
SetCurSelEx(nIndex, false);
}
LRESULT OnSetText(LPCTSTR lpszText)
{
ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnSetText\n"));
SetMsgHandled(FALSE);
// for new text
int nIndex = GetTabIndex(m_wndMDIChildProcessing);
if (nIndex != -1)
_SetTabText(nIndex, lpszText);
return FALSE;
}
void OnMDIChildDestroy(HWND hWnd)
{
ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnDestroy\n"));
int nIndex = GetTabIndex(hWnd);
if (nIndex != -1) {
DeleteItem(nIndex);
}
}
// Implementation
bool _SetTabText(int nIndex, LPCTSTR lpszTab)
{
CString strTab(lpszTab);
strTab = MtlCompactString(strTab, m_nMaxTabItemTextLength);
return SetItemText(nIndex, strTab);
}
CString _GetTabText(int nIndex)
{
CString str;
GetItemText(nIndex, str);
}
void _UpdateMenu(CMenuHandle& menuSys)
{// Emulation is needed cause MDI child window won't update its menu information until clicked.
ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::_UpdateMenu\n"));
ATLASSERT(::IsMenu(menuSys.m_hMenu));
// no effect
// m_wndMDIChildPopuping.SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE |
// SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
menuSys.EnableMenuItem(SC_RESTORE, MF_BYCOMMAND|MF_ENABLED);
menuSys.EnableMenuItem(SC_MOVE, MF_BYCOMMAND|MF_ENABLED);
menuSys.EnableMenuItem(SC_SIZE, MF_BYCOMMAND|MF_ENABLED);
menuSys.EnableMenuItem(SC_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
menuSys.EnableMenuItem(SC_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
CWindowPlacement wndpl;
m_wndMDIChildPopuping.GetWindowPlacement(&wndpl);
switch(wndpl.showCmd) {
case SW_SHOWNORMAL:
ATLTRACE2(atlTraceUser, 4, _T(" SW_SHOWNORMAL\n"));
menuSys.EnableMenuItem(SC_RESTORE, MF_BYCOMMAND|MF_GRAYED);
::SetMenuDefaultItem(menuSys, SC_CLOSE, FALSE);
break;
case SW_SHOWMAXIMIZED:
ATLTRACE2(atlTraceUser, 4, _T(" SW_SHOWMAXIMIZED\n"));
menuSys.EnableMenuItem(SC_MOVE, MF_BYCOMMAND|MF_GRAYED);
menuSys.EnableMenuItem(SC_SIZE, MF_BYCOMMAND|MF_GRAYED);
menuSys.EnableMenuItem(SC_MAXIMIZE, MF_BYCOMMAND|MF_GRAYED);
::SetMenuDefaultItem(menuSys, SC_CLOSE, FALSE);
break;
case SW_SHOWMINIMIZED:
ATLTRACE2(atlTraceUser, 4, _T(" SW_SHOWMINIMIZED\n"));
menuSys.EnableMenuItem(SC_SIZE, MF_BYCOMMAND|MF_GRAYED);
menuSys.EnableMenuItem(SC_MINIMIZE, MF_BYCOMMAND|MF_GRAYED);
::SetMenuDefaultItem(menuSys, SC_RESTORE, FALSE);
break;
default:
ATLASSERT(FALSE);
break;
}
if (m_wndMDIChildPopuping.m_hWnd != m_wndMDIChildPopuping.MDIGetActive()) {// it's not active
menuSys.EnableMenuItem(SC_MOVE, MF_BYCOMMAND|MF_GRAYED);
menuSys.EnableMenuItem(SC_SIZE, MF_BYCOMMAND|MF_GRAYED);
}
}
BOOL LoadConnectingAndDownloadingImageList(UINT nImageBmpID,
int cx, int cy, COLORREF clrMask, UINT nFlags = ILC_COLOR8)
{
if(m_imgs.m_hImageList == NULL)
{
m_imgs.Create(cx, cy, nFlags | ILC_MASK, 2, 1);
ATLASSERT(m_imgs.m_hImageList != NULL);
if(m_imgs.m_hImageList == NULL)
return FALSE;
}
CBitmap bmp;
bmp.LoadBitmap(nImageBmpID);
ATLASSERT(bmp.m_hBitmap != NULL);
if(bmp.m_hBitmap == NULL)
return FALSE;
if(m_imgs.Add(bmp, clrMask) == -1)
return FALSE;
return TRUE;
}
void SetConnecting(HWND hWnd)
{
int nItem = GetTabIndex(hWnd);
if (nItem == -1)
return;
ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrl::SetConnecting\n"));
_SetImageListIndex(nItem, 0);
}
void SetDownloading(HWND hWnd)
{
int nItem = GetTabIndex(hWnd);
if (nItem == -1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -