WTL 一个绘制 MDI 客户区的类
使用相当简单:
- 在工程内创建一个资源 ID 为 IDB_BK_LOG 的位图
- 在 mdi 的主框架窗口类内部创建变量.
CMdiClientDraw m_wndMdiClinetX;
- 然后在 OnCreate 函数内子类化 MDI Client.
m_wndMdiClinetX.SubclassWindow(m_hWndMDIClient);
完成.
以下是类的源码
下载: atlmdiclient.h
- #ifndef __TB_MDI_CLIENT_H__
- #define __TB_MDI_CLIENT_H__ 1
- //
- // based on "Automatic Tab Bar for MDI Frameworks"
- // http://www.codeproject.com/KB/docview/mditab.aspx
- //
- #pragma once
- #ifndef __ATLMISC_H__
- #error tbmdiclient.h requires atlmisc.h to be included first
- #endif
- #ifndef IDB_BK_LOG
- #define IDB_BK_LOG 300
- #endif
- #define szLogoString _T("Tiny Browser, wonderful world")
- template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits>
- class ATL_NO_VTABLE CMdiClientDrawT
- : public CWindowImpl< T, TBase, TWinTraits>
- {
- public:
- typedef CWindowImpl<TBase, TWinTraits> baseClass;
- typedef enum DispType
- {
- DISPTILE,
- DISPCENTER,
- DISPSTRETCH
- } DispType;
- CSize m_sizeClient;
- DECLARE_WND_CLASS( _T("CMdiClientDrawT") )
- CMdiClientDrawT() : m_sizeClient(0, 0)
- {
- // Do defaults settings
- Defaults();
- // Load the logo font
- /*
- {
- BOOL bSuccess = FALSE;
- LOGFONT* plf = NULL;
- UINT dwSize = sizeof(LOGFONT);
- bSuccess = pApp->GetProfileBinary(szSection, szLogoFont, (BYTE**)&plf, &dwSize);
- if (bSuccess)
- {
- m_fontLogo.DeleteObject();
- m_fontLogo.CreateFontIndirect(plf);
- }
- delete plf;
- }
- //*/
- m_strLogo = szLogoString;
- m_bBkBitmap = TRUE;
- m_crLogoColor = RGB(0xff, 0xff, 0xff);
- m_crBkColor = RGB(0x80, 0x80, 0x80);
- SetBkColor(m_crBkColor);
- m_enuDispType = (DispType)DISPCENTER;
- SetDispType(m_enuDispType);
- // SetBitmap(MAKEINTRESOURCE(IDB_BK_LOG));
- SetBitmap(IDB_BK_LOG);
- }
- BEGIN_MSG_MAP(thisClass)
- MESSAGE_HANDLER(WM_PAINT, OnPaint)
- MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
- MESSAGE_HANDLER(WM_SIZE, OnSize)
- END_MSG_MAP()
- LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- T* pThis = static_cast<T *> (this);
- CPaintDC dc(pThis->m_hWnd);
- CRect rc;
- pThis->GetClientRect(rc);
- BOOL bDoBitBlt = TRUE;
- if (!(HBITMAP)m_bkBitmap)
- dc.FillRect(rc, m_bkBrush);
- if ((HBITMAP)m_bkBitmap)
- {
- CDCHandle pDC;
- CDC memDC;
- CBitmap bmp;
- BOOL bUseMemDC =(GetDispType() != DISPTILE) ? TRUE : FALSE;
- if (bUseMemDC)
- {
- if (GetDispType() != DISPSTRETCH)
- bmp.CreateCompatibleBitmap(dc, rc.right, rc.bottom);
- else
- bmp.CreateCompatibleBitmap(dc, m_sizImage.cx, m_sizImage.cy);
- memDC.CreateCompatibleDC(dc);
- memDC.SelectBitmap(bmp);
- pDC = memDC;
- }
- else
- pDC = dc;
- switch (GetDispType())
- {
- case DISPTILE:
- {
- CPoint point;
- for (point.y = 0; point.y < rc.Height(); point.y += m_sizImage.cy)
- for (point.x = 0; point.x < rc.Width(); point.x += m_sizImage.cx)
- pDC.DrawState(point, m_sizImage, m_bkBitmap, DST_BITMAP | DSS_NORMAL);
- }
- break;
- case DISPCENTER:
- {
- pDC.FillRect(rc, m_bkBrush);
- CPoint point((rc.Width() - m_sizImage.cx) / 2,
- (rc.Height() - m_sizImage.cy) / 2);
- pDC.DrawState(point, m_sizImage, m_bkBitmap, DST_BITMAP | DSS_NORMAL);
- }
- break;
- case DISPSTRETCH:
- {
- memDC.DrawState(CPoint(0, 0), m_sizImage, m_bkBitmap, DST_BITMAP | DSS_NORMAL);
- dc.SetStretchBltMode(COLORONCOLOR);
- dc.StretchBlt(0, 0, rc.right, rc.bottom, memDC,
- 0, 0, m_sizImage.cx, m_sizImage.cy, SRCCOPY);
- bDoBitBlt = FALSE;
- }
- break;
- }
- // Now is the time to draw the logo text at the bottom
- if (!bDoBitBlt) // If not using memory DC, then grab a DC here
- pDC = dc;
- PaintLogo(pDC);
- if ((bUseMemDC == TRUE) && bDoBitBlt)
- dc.BitBlt(0, 0, rc.right, rc.bottom, pDC, 0, 0, SRCCOPY);
- }
- else
- {
- CDCHandle pDC;
- pDC = dc;
- PaintLogo(pDC);
- }
- return 0;
- }
- LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- T* pThis = static_cast<T *> (this);
- return pThis->OnMDIClientEraseBkgnd(uMsg, wParam, lParam, bHandled);
- }
- LRESULT OnMDIClientEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- BOOL bMaximized = FALSE;
- HWND hWndActive = (HWND)::SendMessage(m_hWnd, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);
- if (bMaximized) {
- return TRUE;// no need to erase it
- }
- bHandled = FALSE;
- return FALSE;
- }
- LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- T* pThis = static_cast<T *> (this);
- return pThis->OnMDIClientSize(uMsg, wParam, lParam, bHandled);
- }
- LRESULT OnMDIClientSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- T* pThis = static_cast<T *> (this);
- BOOL bMaximized = FALSE;
- HWND hWndActive = (HWND)::SendMessage(m_hWnd, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);
- if (bMaximized)
- {
- // NOTE. If you do the following, you can avoid the flicker on resizing.
- // I can't understand why it is effective...
- //
- // But still you can get a glimpse of other mdi child window's frames.
- // I guess it's MDI's bug, but I can't get the way MFC fixed.
- CWindow wndActive(hWndActive);
- CWindow wndView = wndActive.GetWindow(GW_CHILD);
- ATLASSERT(wndView.IsWindow());
- wndActive.ModifyStyle(0, WS_CLIPCHILDREN);// add WS_CLIPCHILDREN
- wndView.ModifyStyle(0, WS_CLIPCHILDREN);
- LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
- UpdateWindow();
- wndActive.ModifyStyle(WS_CLIPCHILDREN, 0);
- wndView.ModifyStyle(WS_CLIPCHILDREN, 0);
- return lRet;
- }
- pThis->DefWindowProc(uMsg, wParam, lParam);
- int cx = LOWORD(lParam);
- int cy = HIWORD(lParam);
- // if the app is just starting up, save the window
- // dimensions and get out
- if ((m_sizeClient.cx == 0) &&(m_sizeClient.cy == 0))
- {
- m_sizeClient.cx = cx;
- m_sizeClient.cy = cy;
- return 0;
- }
- // if the size hasn't changed, break and pass to default
- if ((m_sizeClient.cx == cx) &&(m_sizeClient.cy == cy)) {
- return 0;
- }
- // window size has changed so save new dimensions and force
- // entire background to redraw, including icon backgrounds
- m_sizeClient.cx = cx;
- m_sizeClient.cy = cy;
- pThis->RedrawWindow(NULL, NULL,
- RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW /*| RDW_ALLCHILDREN */);
- return 0;
- }
- // Set background color
- void SetBkColor(COLORREF crBkValue)
- {
- T* pThis = static_cast<T *> (this);
- m_crBkColor = crBkValue;
- if (FALSE == m_bkBrush.IsNull()) {
- m_bkBrush.DeleteObject();
- }
- m_bkBrush.CreateSolidBrush(m_crBkColor);
- if (pThis->IsWindow())
- pThis->Invalidate();
- }
- COLORREF GetBkColor() const
- {
- return m_crBkColor;
- }
- // Set Logo Text color
- void SetLogoColor(COLORREF crValue)
- {
- m_crLogoColor = crValue;
- if (IsWindow())
- Invalidate();
- }
- COLORREF GetLogoColor() const
- {
- return m_crLogoColor;
- }
- void SetDispType(DispType enuDispType)
- {
- T* pThis = static_cast<T *> (this);
- m_enuDispType = enuDispType;
- if (pThis->IsWindow()) {
- pThis->Invalidate();
- }
- }
- DispType GetDispType() const
- {
- return m_enuDispType;
- }
- // Load background bitmap from given file
- BOOL SetBitmap(LPCTSTR lpszFileName, UINT uFlags = LR_LOADMAP3DCOLORS)
- {
- T* pThis = static_cast<T *> (this);
- if ( (((DWORD)lpszFileName) >> 16) != 0 ) {
- uFlags |= LR_LOADFROMFILE;
- }
- HANDLE hBitmap = ::LoadImage(_Module.GetResourceInstance(), lpszFileName,
- IMAGE_BITMAP, 0, 0, uFlags );
- if (!hBitmap) // There were some problems during loading the image
- return FALSE;
- if (FALSE == m_bkBitmap.IsNull()) {
- m_bkBitmap.DeleteObject();
- }
- m_bkBitmap.Attach((HBITMAP)hBitmap);
- if (pThis->IsWindow()) {
- pThis->Invalidate();
- }
- m_strFileName.Empty();
- if (uFlags & LR_LOADFROMFILE) {
- m_strFileName = lpszFileName;
- }
- BITMAP bi;
- m_bkBitmap.GetBitmap(&bi);
- m_sizImage.cx = bi.bmWidth;
- m_sizImage.cy = bi.bmHeight;
- return TRUE;
- }
- // Load background bitmap from resource.
- BOOL SetBitmap(UINT nBmpID, COLORMAP* pClrMap = NULL, int nCount = 0)
- {
- T* pThis = static_cast<T *> (this);
- if (FALSE == m_bkBitmap.IsNull()) {
- m_bkBitmap.DeleteObject();
- }
- if (pClrMap == NULL)
- {
- if (m_bkBitmap.LoadBitmap(nBmpID) == FALSE) {
- return FALSE;
- }
- }
- else
- {
- if (m_bkBitmap.LoadMappedBitmap(nBmpID, 0, pClrMap, nCount) == FALSE) {
- return FALSE;
- }
- }
- BITMAP bi = { 0 };
- m_bkBitmap.GetBitmap(&bi);
- m_sizImage.cx = bi.bmWidth;
- m_sizImage.cy = bi.bmHeight;
- if (pThis->IsWindow())
- pThis->Invalidate();
- return TRUE;
- }
- // Load background bitmap from resource.
- BOOL SetDefBitmap(UINT nBmpID, COLORMAP* pClrMap = NULL, int nCount = 0)
- {
- T* pThis = static_cast<T *> (this);
- if (FALSE == m_bkDefBitmap.IsNull()) {
- m_bkDefBitmap.DeleteObject();
- }
- if (pClrMap == NULL)
- {
- if (m_bkDefBitmap.LoadBitmap(nBmpID) == FALSE)
- return FALSE;
- }
- else
- {
- if (m_bkDefBitmap.LoadMappedBitmap(nBmpID, 0, pClrMap, nCount) == FALSE)
- return FALSE;
- }
- BITMAP bi = { 0 };
- m_bkDefBitmap.GetBitmap(&bi);
- m_sizDefImage.cx = bi.bmWidth;
- m_sizDefImage.cy = bi.bmHeight;
- if (pThis->IsWindow()) {
- pThis->Invalidate();
- }
- return TRUE;
- }
- // Set the logo text font...
- void SetLogoFont(HFONT pLogoFont)
- {
- T* pThis = static_cast<T *> (this);
- ATLASSERT(pLogoFont);
- if (FALSE == m_fontLogo.IsNull()) {
- m_fontLogo.DeleteObject();
- }
- LOGFONT lFont = { 0 };
- CFontHandle fnt(pLogoFont);
- fnt->GetLogFont(&lFont);
- m_fontLogo.CreateFontIndirect(&lFont);
- pThis->SetFont(m_fontLogo);
- if (pThis->IsWindow())
- pThis->Invalidate();
- }
- void SetLogoFont(int nLogoWeight = FW_SEMIBOLD, BOOL bLogoItalic = FALSE,
- BOOL bLogoUnderline = FALSE)
- {
- T* pThis = static_cast<T *> (this);
- // Free any memory currently used by the fonts.
- if (FALSE == m_fontLogo.IsNull()) {
- m_fontLogo.DeleteObject();
- }
- // Get the current font
- LOGFONT lFont = { 0 };
- CFontHandle pFont = pThis->GetFont();
- if (FALSE == pFont.IsNull()) {
- pFont.GetLogFont(&lFont);
- } else {
- NONCLIENTMETRICS ncm = { 0 };
- ncm.cbSize = sizeof(NONCLIENTMETRICS);
- ATLVERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
- sizeof(NONCLIENTMETRICS), &ncm, 0));
- lFont = ncm.lfMessageFont;
- }
- // Create the Logo font
- lFont.lfWeight = static_cast<LONG>(nLogoWeight);
- lFont.lfItalic = static_cast<BYTE>(bLogoItalic);
- lFont.lfUnderline = static_cast<BYTE>(bLogoUnderline);
- m_fontLogo.CreateFontIndirect(&lFont);
- pThis->SetFont(m_fontLogo);
- if (pThis->IsWindow()) {
- pThis->Invalidate();
- }
- }
- HFONT GetLogoFont()
- {
- return m_fontLogo;
- }
- CString GetLogoText(void)
- {
- return m_strLogo;
- }
- void SetLogoText(const CString & str)
- {
- m_strLogo = str;
- }
- // Return the current image size.
- const CSize& GetImageSize() const
- {
- return m_sizImage;
- }
- // Return the filename of the bitmap
- const CString & GetFileName() const
- {
- return m_strFileName;
- }
- protected:
- COLORREF m_crBkColor; // Background color
- COLORREF m_crLogoColor; // Right logo text color
- CBitmap m_bkBitmap; // background bitmap
- CBitmap m_bkDefBitmap; // Default background bitmap
- CBrush m_bkBrush; // Brush used for background painting
- CString m_strFileName; // Filename of any bitmap loaded from a file
- CSize m_sizImage; // Bitmap image size
- CSize m_sizDefImage; // Default Bitmap image size
- DispType m_enuDispType; // Current display type
- CFont m_fontLogo; // Font for drawing the logo text
- CString m_strLogo;
- BOOL m_bBkBitmap;
- // Generated message map functions
- protected:
- void PaintLogo(CDCHandle pDC)
- {
- T* pThis = static_cast<T *> (this);
- CRect rcDataBox;
- TEXTMETRIC tm = { 0 };
- pDC.SetBkMode(OPAQUE);
- CFontHandle oldFont = pDC.SelectFont( m_fontLogo );
- CRect st(0, 0, 0, 0);
- CSize sz;
- pDC.GetTextExtent(m_strLogo, m_strLogo.GetLength(), &sz);
- // GetTextExtent calculates the size of the displayed logo
- // which depends on the device context....
- pDC.GetTextMetrics(&tm);
- // Calculate the box size by subtracting the text width and height from the
- // window size. Also subtract 20% of the average character size to keep the
- // logo from printing into the borders...
- pThis->GetClientRect(&rcDataBox);
- rcDataBox.left = rcDataBox.right - sz.cx - tm.tmAveCharWidth / 2;
- rcDataBox.top = rcDataBox.bottom - sz.cy - st.bottom - tm.tmHeight / 5;
- CRect rcSave = rcDataBox;
- pDC.SetBkMode(TRANSPARENT);
- rcSave = rcDataBox;
- // shift logo box right, and print black...
- rcDataBox.left += tm.tmAveCharWidth / 5;
- COLORREF oldColor = pDC.SetTextColor(RGB(0, 0, 0));
- pDC.DrawText(m_strLogo, m_strLogo.GetLength(), &rcDataBox,
- DT_VCENTER | DT_SINGLELINE | DT_CENTER);
- rcDataBox = rcSave;
- // shift logo box left and print white
- rcDataBox.left -= tm.tmAveCharWidth / 5;
- pDC.SetTextColor(RGB(255, 255, 255));
- pDC.DrawText(m_strLogo, m_strLogo.GetLength(), &rcDataBox,
- DT_VCENTER | DT_SINGLELINE | DT_CENTER);
- // Restore original location and print in the button face color
- rcDataBox = rcSave;
- pDC.SetTextColor(m_crLogoColor);
- pDC.DrawText(m_strLogo, m_strLogo.GetLength(), &rcDataBox,
- DT_VCENTER | DT_SINGLELINE | DT_CENTER);
- // restore the original properties and release resources...
- pDC.SelectFont(oldFont);
- pDC.SetTextColor(oldColor);
- pDC.SetBkMode(OPAQUE);
- }
- void Defaults(BOOL bBkBitmap = TRUE, BOOL bDelBkBitmap = TRUE)
- {
- T* pThis = static_cast<T *> (this);
- // m_bBkBitmap = bBkBitmap;
- m_crBkColor = GetSysColor(COLOR_APPWORKSPACE);
- m_crLogoColor = GetSysColor(COLOR_BTNFACE);
- m_enuDispType = DISPCENTER;
- m_strFileName.Empty();
- // Create the default font, Times New Roman is most common
- CWindowDC wndDC(::GetDesktopWindow());
- int nFontSize = -MulDiv(18, wndDC.GetDeviceCaps(LOGPIXELSY), 72);
- if (FALSE == m_fontLogo.IsNull()) {
- m_fontLogo.DeleteObject();
- }
- m_fontLogo.CreateFont(nFontSize,
- 0, 0, 0,
- FW_BOLD,
- FALSE, FALSE, FALSE,
- ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
- FIXED_PITCH | FF_ROMAN,
- // _T("微软雅黑"));
- _T("Times New Roman"));
- if (pThis->IsWindow()) {
- pThis->SetFont(m_fontLogo);
- }
- SetBkColor(m_crBkColor);
- if (bDelBkBitmap)
- {
- if (FALSE == m_bkBitmap.IsNull()) {
- m_bkBitmap.DeleteObject();
- }
- m_sizImage.cx = m_sizImage.cy = 0;
- if (bBkBitmap && (HBITMAP)m_bkDefBitmap)
- {
- m_sizImage = m_sizDefImage;
- // m_bkBitmap& = CBitmap::FromHandle((HBITMAP)m_bkDefBitmap);
- // BITMAP* bmpDef = new BITMAP;
- // m_bkDefBitmap.GetBitmap(bmpDef);
- // VERIFY(m_bkBitmap.CreateBitmapIndirect(bmpDef));
- // delete bmpDef;
- }
- }
- if (pThis->IsWindow()) {
- pThis->Invalidate();
- }
- }
- };
- class CMdiClientDraw : public CMdiClientDrawT<CMdiClientDraw>
- {
- public:
- DECLARE_WND_CLASS(_T("CMdiClientDraw"));
- };
- #endif // __TB_MDI_CLIENT_H__

近期评论