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

📄 paintcap.cpp

📁 我们的网管程序的后台软件,主要是网络方面的内容.
💻 CPP
字号:
////////////////////////////////////////////////////////////////
// 1997 Microsoft Systems Journal. 
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Modify 2003.03.19 WHD
//

#include "StdAfx.h"
#include "..\nms.h"
#include "PaintCap.h"

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

////////////////
// Class used to get the caption rectangle of a window in window coords.
// This is the area of the title bar inside the window frame, including
// the icon and min/max/close buttons.
// 
class CCaptionRect : public CRect {
public:
	CCaptionRect(const CWnd& wnd); // use reference to deny NULL ptr
};

IMPLEMENT_DYNAMIC(CCaptionPainter, CSubclassWnd);

CCaptionPainter::CCaptionPainter()
{
	Invalidate();
}

CCaptionPainter::~CCaptionPainter()
{
}

//////////////////
// Install caption handler. nPaintMsg is message I will send too frame
// when its caption needs painting.
//
BOOL CCaptionPainter::Install(CDialog* pFrameWnd,UINT nPaintMsg,BOOL bMod)
{
	ASSERT_KINDOF(CDialog, pFrameWnd);
	m_nPaintMsg = nPaintMsg;
	m_bModified=bMod;
	return HookWindow(pFrameWnd);
}

//////////////////
// Message handler handles caption-related messages
//
LRESULT CCaptionPainter::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
{
	switch (msg) {
	case WM_NCPAINT:
		OnNcPaint(HRGN(wp));
		return 0;
	case WM_NCACTIVATE:
		return OnNcActivate(wp);
	case WM_SETTEXT:
		OnSetText((LPCTSTR)lp);
		return 0;
	case WM_SYSCOLORCHANGE:
	case WM_SETTINGCHANGE:
		Invalidate();
		m_pWndHooked->SendMessage(m_nPaintMsg, 0, 0L);
	}
	// I don't handle it: pass along
	return CSubclassWnd::WindowProc(msg, wp, lp);
}

/////////////////
// Window Send WM_NCPAINT 
// when its frame must be painted. 
//

void CCaptionPainter::OnNcPaint(HRGN hRgn)
{
	ASSERT_VALID(m_pWndHooked);
	CWnd& wnd = *m_pWndHooked;

	// 得到标题栏Rect
	CCaptionRect rc(wnd);
	CRect rcWin;

	wnd.GetWindowRect(&rcWin);
	rc += rcWin.TopLeft();

	// 重绘区域不包含标题栏(不用重画标题栏)
	if ((WORD)hRgn > 1 && !::RectInRegion(hRgn, &rc)) 
	{
		Default();					// just do default thing
		return;						// and quit
	}

	// 标题栏的部分区域需要重画
	// 首先找出除标题栏外应该重画的系统区域(Frame)

	HRGN hRgnCaption = ::CreateRectRgnIndirect(&rc);
	HRGN hRgnNew     = ::CreateRectRgnIndirect(&rc);
	if ((WORD)hRgn > 1) 
	{
		::CombineRgn(hRgnNew, hRgn, hRgnCaption, RGN_DIFF);
	}
	else
	{
		HRGN hRgnAll = ::CreateRectRgnIndirect(&rcWin);
		CombineRgn(hRgnNew, hRgnAll, hRgnCaption, RGN_DIFF);
		DeleteObject(hRgnAll);
	}

	// Ok , 让系统去重画 除标题栏外应该重画的系统区域
	//
	MSG& msg = AfxGetThreadState()->m_lastSentMsg;
	WPARAM savewp = msg.wParam;	
	msg.wParam = (WPARAM)hRgnNew;
	Default();
	DeleteObject(hRgnCaption);
	DeleteObject(hRgnNew);
	msg.wParam = savewp;

	// 现在重画自己的标题栏
	PaintCaption();
}

//////////////////
// Handle WM_NCACTIVATE for main window
//
BOOL CCaptionPainter::OnNcActivate(BOOL bActive)
{
	ASSERT_VALID(m_pWndHooked);

	if (bActive==m_bActive)
	{
		// 不用重绘
		return TRUE;
	}

	// In case this is a MDI app, manually activate/paint active MDI child
	// window, because Windows won't do it if parent frame is invisible.
	// Must do this BEFORE calling Default, or it will not work.
	//
	/*
	CDialog* pActiveFrame = frame.GetActiveFrame();
	if (pActiveFrame!=&frame) {
		pActiveFrame->SendMessage(WM_NCACTIVATE,bActive);
		pActiveFrame->SendMessage(WM_NCPAINT);
	}
*/
	// Turn WS_VISIBLE off before calling DefWindowProc,
	// so DefWindowProc won't paint and thereby cause flicker.
	//
	DWORD dwStyle = m_pWndHooked->GetStyle();
	if (dwStyle & WS_VISIBLE)
		::SetWindowLong(m_pWndHooked->GetSafeHwnd() , GWL_STYLE, (dwStyle & ~ WS_VISIBLE));

	MSG& msg = AfxGetThreadState()->m_lastSentMsg;
	msg.wParam = bActive;
	Default();
	if (dwStyle & WS_VISIBLE)
		::SetWindowLong(m_pWndHooked->GetSafeHwnd(), GWL_STYLE, dwStyle);

	// 重绘
	m_bActive = bActive;					// update state
	m_pWndHooked->SendMessage(WM_NCPAINT);	// paint non-client area (frame too)
	return TRUE;							// done OK
}

//////////////////
// Handle WM_SETTEXT for main window
//
void CCaptionPainter::OnSetText(LPCTSTR lpText)
{
	return ;
	ASSERT_VALID(m_pWndHooked);
	CWnd& wnd = *m_pWndHooked;

	// Turn WS_VISIBLE style off before calling Windows to
	// set the text, then turn it back on again after.
	//
	DWORD dwStyle = wnd.GetStyle();
	if (dwStyle & WS_VISIBLE)
		SetWindowLong(wnd.m_hWnd, GWL_STYLE, dwStyle & ~ WS_VISIBLE);
	Default();
	if (dwStyle & WS_VISIBLE)
		SetWindowLong(wnd.m_hWnd, GWL_STYLE, dwStyle);

	wnd.SendMessage(WM_NCPAINT);		// paint non-client (frame)
	Invalidate();							// force new bitmap
	//PaintCaption();
}

//////////////////
// 重画标题栏

void CCaptionPainter::PaintCaption()
{
	ASSERT(m_pWndHooked);
	CWnd& wnd = *m_pWndHooked;

	// 窗口最小化,当然不用重绘
	if (wnd.IsIconic())
	{
		return ;
	}

	CWindowDC dcWin(&wnd);
	CDC dc;
	dc.CreateCompatibleDC(&dcWin);
	CCaptionRect rc(wnd);

	// 选中拥有焦点/没有焦点时位图

	CBitmap& bm = m_bmCaption[m_bActive!=0];
	BOOL bPaintIt = FALSE;
	if (!(HBITMAP)bm)
	{
		bm.CreateCompatibleBitmap(&dcWin, rc.Width(), rc.Height());
		//bm.LoadBitmap(IDB_BITMAP1);
		bPaintIt = TRUE;
	}
	CBitmap* pOldBitmap = dc.SelectObject(&bm);

	if (bPaintIt)
	{
		// 标题栏位图尚未作图
		PAINTCAP pc;
		pc.m_pDC = &dc;
		pc.m_szCaption = rc.Size();
	    pc.m_bActive=m_bActive;
	
		if(m_nPaintMsg)
		{
			wnd.SendMessage(m_nPaintMsg , m_bActive, (LPARAM)&pc);
		}
		else
			DrawNormalCaption(pc);
	}

	// 将内存位图拷贝

	dcWin.BitBlt(rc.left,rc.top , rc.Width() , rc.Height() , &dc,0,0,SRCCOPY);
	dc.SelectObject(pOldBitmap);
}

void CCaptionPainter::DrawNormalCaption(const PAINTCAP& pc)
{
	ASSERT(m_pWndHooked);
	CWnd& wnd = *m_pWndHooked;

	UINT uFlags = DC_TEXT|DC_ICON;

	if(pc.m_bActive)
		uFlags|=DC_ACTIVE;

	// 利用系统函数画标题栏

	CRect rc(CPoint(0,0) , pc.m_szCaption);
	::DrawCaption(wnd,*pc.m_pDC,&rc,uFlags);

	DrawButtons(pc);
}
////////////////
// Draw caption icon. Returns width of icon.
//
int CCaptionPainter::DrawIcon(const PAINTCAP& pc)
{
	return 1;
	ASSERT(m_pWndHooked);
	CWnd& wnd = *m_pWndHooked;

	// Within the basic button rectangle, Windows 95 uses a 1 or 2 pixel border
	// Icon has 2 pixel border on left, 1 pixel on top/bottom, 0 right
	//
	int cxIcon = GetSystemMetrics(SM_CXSIZE);
	CRect rc(0, 0, cxIcon, GetSystemMetrics(SM_CYSIZE));
	rc.DeflateRect(0,1);
	rc.left += 2;
	DrawIconEx(pc.m_pDC->m_hDC, rc.left, rc.top,
		pApp->LoadIcon(IDR_MAINFRAME),
		rc.Width(), rc.Height(), 0, NULL, DI_NORMAL);
	
	return cxIcon;
}

////////////////
// 最大化、最小化、关闭按钮

int CCaptionPainter::DrawButtons(const PAINTCAP& pc)
{
	return 1;
	ASSERT(m_pWndHooked);
	CWnd& wnd = *m_pWndHooked;

	DWORD dwStyle = wnd.GetStyle();


	if (!(dwStyle & WS_CAPTION))
	{
		return 0;
	}

	ASSERT(pc.m_pDC);
	CDC& dc = *pc.m_pDC;

	int cxIcon = GetSystemMetrics(SM_CXSIZE);
	int cyIcon = GetSystemMetrics(SM_CYSIZE);

	// Draw caption buttons. These are all drawn inside a rectangle
	// of dimensions SM_CXSIZE by SM_CYSIZE
	CRect rc(0, 0, cxIcon, cyIcon);
	rc += CPoint(pc.m_szCaption.cx-cxIcon, 0);	// move right

	// Close box has a 2 pixel border on all sides but left, which is zero
	rc.DeflateRect(0,2);
	rc.right -= 2;
	dc.DrawFrameControl(&rc, DFC_CAPTION, DFCS_CAPTIONCLOSE);

	// Max/restore button is like close box; just shift rectangle left
	// Also does help button, if any.
	//BOOL bMaxBox = dwStyle & WS_MAXIMIZEBOX;
	//if (bMaxBox || (wnd.GetExStyle() & WS_EX_CONTEXTHELP)) {
		rc -= CPoint(cxIcon, 0);
		dc.DrawFrameControl(&rc, DFC_CAPTION,
			//bMaxBox ? (wnd.IsZoomed() ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX) :
				//DFCS_CAPTIONHELP);
			(wnd.IsZoomed() ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX));
	//}

	// Minimize button has 2 pixel border on all sides but right.
	if (dwStyle & WS_MINIMIZEBOX) {
		rc -= CPoint(cxIcon,0);
		dc.DrawFrameControl(&rc, DFC_CAPTION, DFCS_CAPTIONMIN);
	}

	// 返回值作为其他重画操作坐标

	return pc.m_szCaption.cx - rc.left - 2;
}

//////////////////
// CCaptionRect Constructor computes caption rectangle in window coords.
// 得到wnd的标题栏CRect

CCaptionRect::CCaptionRect(const CWnd& wnd)
{
	// Get size of frame around window
	DWORD dwStyle = wnd.GetStyle();
	CSize szFrame = (dwStyle & WS_THICKFRAME) ?
		CSize(GetSystemMetrics(SM_CXSIZEFRAME),
			   GetSystemMetrics(SM_CYSIZEFRAME)) :
		CSize(GetSystemMetrics(SM_CXFIXEDFRAME),
				GetSystemMetrics(SM_CYFIXEDFRAME));

	int cxIcon = GetSystemMetrics(SM_CXSIZE); // width of caption icon/button

	// Compute rectangle
	wnd.GetWindowRect(this);		// window rect in screen coords
	*this -= CPoint(left, top);	// shift origin to (0,0)
	left  += szFrame.cx;				// frame
	right -= szFrame.cx;				// frame
	top   += szFrame.cy;				// top = end of frame
	bottom = top + GetSystemMetrics(SM_CYCAPTION)  // height of caption
		- GetSystemMetrics(SM_CYBORDER);				  // minus gray shadow border
}

//////////////////
// Helper function to compute the luminosity for an RGB color.
// Measures how bright the color is. I use this so I can draw the caption
// text using the user's chosen color, unless it's too dark. See MSDN for
// definition of luminosity and how to compute it.
//
int CCaptionPainter::GetLuminosity(COLORREF color)
{
#define HLSMAX 240	// This is what Display Properties uses
#define RGBMAX 255	// max r/g/b value is 255
	int r = GetRValue(color);
	int g = GetGValue(color);
	int b = GetBValue(color);
	int rgbMax = max( max(r,g), b);
	int rgbMin = min( min(r,g), b);
	return (((rgbMax+rgbMin) * HLSMAX) + RGBMAX ) / (2*RGBMAX);
}

#define COLOR_WHITE RGB(255,255,255)
#define COLOR_BLACK RGB(0,0,0)
#define NCOLORSHADES 64		// this many shades in gradient

//////////////////
// Helper to paint rectangle with a color.
//
void CCaptionPainter::PaintRect(CDC& dc, int x, int y, int w, int h, COLORREF color)
{
	CBrush brush(color);
	CBrush* pOldBrush = dc.SelectObject(&brush);
	dc.PatBlt(x, y, w, h, PATCOPY);
	dc.SelectObject(pOldBrush);
}

//////////////////
//

void CCaptionPainter::PaintMyCaption(WPARAM bActive, LPARAM lParam, CString m_strTitle)
{
	if (lParam == 0) 
	{
		// lParam = 0 means system setting change: invalidate fonts.
		m_fontCaption.DeleteObject();
		return;
	}

	const PAINTCAP& pc = *((PAINTCAP*)lParam);
	ASSERT(pc.m_pDC);
	CDC& dc = *pc.m_pDC;

	int cxCap = pc.m_szCaption.cx;
	int cyCap = pc.m_szCaption.cy;

	COLORREF clrFrom;	// the beginning color
	COLORREF clrTo;		// the ending color

	// These are the default colors in Windows(R) 98
	// Modify them to suit your needs.
	if (bActive)
	{
		// Active caption
		clrFrom	= GetSysColor(COLOR_ACTIVECAPTION);
		clrTo	= RGB(0,127,255);
	}
	else
	{
		// Inactive caption
		clrFrom	= GetSysColor(COLOR_INACTIVECAPTION);
		clrTo	= MY_SYS_COLOR;
	}

	// Get the intensity values for the ending color
	int r1 = GetRValue(clrTo); // red
	int g1 = GetGValue(clrTo); // green
	int b1 = GetBValue(clrTo); // blue
	
	// Get the intensity values for the begining color
	int r2 = GetRValue(clrFrom); // red
	int g2 = GetGValue(clrFrom); // green
	int b2 = GetBValue(clrFrom); // blue

	int x = 5*cxCap/6;					// start 5/6 of the way right
	int w = x;							// width of area to shade
	int xDelta= max(w/NCOLORSHADES,1);	// width of one shade band

	// Paint Color
	// Paint far right 1/6 of caption the background color
	PaintRect(dc, x, 0, cxCap-x, cyCap, clrTo);

	int r, g, b;
	while (x > xDelta) {
		x -= xDelta;
		if (r1 > r2)
			r = r1 - (r1-r2)*(w-x)/w;
		else
			r = r1 + (r2-r1)*(w-x)/w;

		if (g1 > g2)
			g = g1 - (g1-g2)*(w-x)/w;
		else
			g = g1 + (g2-g1)*(w-x)/w;

		if (b1 > b2)
			b = b1 - (b1-b2)*(w-x)/w;
		else
			b = b1 + (b2-b1)*(w-x)/w;

		// Paint bands right to left
		PaintRect(dc, x, 0, xDelta, cyCap, RGB(r, g, b));
	}

	// Paint what's left of the caption with the beginning color
	PaintRect(dc, 0, 0, x, cyCap, clrFrom);

	// 图标、按钮

	int cxIcon  = DrawIcon(pc);
	int cxButns = DrawButtons(pc);

	// 改变字体(标题栏显示的字体)

	if (!m_fontCaption.m_hObject)
	{
		CreateFonts();
	}

	CString s("NMS-【网管】");

	CRect rc(CPoint(0,0), pc.m_szCaption); // text rectangle
	rc.left  += cxIcon+2;		// start after icon
	rc.right -= cxButns;		// don't draw past buttons
	dc.SetBkMode(TRANSPARENT);	// draw on top of our shading

	// This is a trial and error value that sets the point
	// where the caption background is too light/dark in
	// order to display the text with white/black.
	// 根据背景选择字体的颜色

	#define	LUMINOSITY_MARK 120

	if (GetLuminosity(clrFrom) > LUMINOSITY_MARK)
		dc.SetTextColor(COLOR_BLACK);
	else
		dc.SetTextColor(COLOR_WHITE);

	CFont* pOldFont = dc.SelectObject(&m_fontCaption);
	dc.DrawText(s, &rc, DT_CENTER|DT_VCENTER |DT_SINGLELINE);//DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS);

	// Restore DC
	dc.SelectObject(pOldFont);
}

//////////////////
// Helper function to build the fonts I need.
//
void CCaptionPainter::CreateFonts()
{
	// Get current system caption font, just to get its size
	//
	NONCLIENTMETRICS ncm;
	ncm.cbSize = sizeof(ncm);
	VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0));

	ncm.lfCaptionFont.lfHeight -= 2;
	
	m_fontCaption.CreateFontIndirect(&ncm.lfCaptionFont);
}

// Private MFC function only sets the title if it's different
//
extern void AFXAPI AfxSetWindowText(HWND, LPCTSTR);

⌨️ 快捷键说明

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