MFC第二十五天 位图加载与显示的方法,StretchBit位图拉伸、开发三态按钮类CBitmapButton的方法(WM_MOUSELEAVE鼠标悬停与离开判断)

文章目录

  • 位图加载与显示的方法
    • CBitmap简介
    • 位图加载
    • 位图显示
    • MFC下的位图显示流程
    • 加载位图 Win32下
    • 加载位图 MFC下
    • StretchBit位图拉伸
    • StretchBit位图 填满全屏
  • 三态按钮类CBitmapButton的方法
    • CMainDlg.h
    • CMainDlg.cpp
    • CButtonXq.h
    • CButtonXq.cpp

位图加载与显示的方法

CBitmap简介

//CPen,CBrush,CFont,CBitmap,CRgn,CPallette的共同基类。
typedef void * HGDIOBJ;

class CGdiObject : public CObject
{

public:

// Attributes
	HGDIOBJ m_hObject;                  // 用来存储:HPEN HBRUSH HFONT HBITMAP ...
	operator HGDIOBJ() const;
	HGDIOBJ GetSafeHandle() const;

	static CGdiObject* PASCAL FromHandle(HGDIOBJ hObject);
	static void PASCAL DeleteTempMap();
	BOOL Attach(HGDIOBJ hObject);
	HGDIOBJ Detach();

// Constructors
	CGdiObject(); // must Create a derived class object
	BOOL DeleteObject();//内部就是API DeleteObject

	UINT GetObjectType() const;
	BOOL CreateStockObject(int nIndex);//内部是:m_hObject=GetStockObject;

};
class CBitmap : public CGdiObject
{
	DECLARE_DYNAMIC(CBitmap)

public:
	static CBitmap* PASCAL FromHandle(HBITMAP hBitmap);//生成外壳类

// Constructors
	CBitmap();

	BOOL LoadBitmap(LPCTSTR lpszResourceName);
	BOOL LoadBitmap(UINT nIDResource);//加载位图
	BOOL LoadOEMBitmap(UINT nIDBitmap); // for OBM_/OCR_/OIC_
	BOOL LoadMappedBitmap(UINT nIDBitmap, UINT nFlags = 0,
		LPCOLORMAP lpColorMap = NULL, int nMapSize = 0);
	BOOL CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitcount,
			const void* lpBits);
	BOOL CreateBitmapIndirect(LPBITMAP lpBitmap);//根据详细信息创建位图
	BOOL CreateCompatibleBitmap(CDC* pDC, int nWidth, int nHeight);//创建兼容位图
	BOOL CreateDiscardableBitmap(CDC* pDC, int nWidth, int nHeight);

// Attributes
	operator HBITMAP() const;
	int GetBitmap(BITMAP* pBitMap);

// Operations
	DWORD SetBitmapBits(DWORD dwCount, const void* lpBits);
	DWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits) const;
	CSize SetBitmapDimension(int nWidth, int nHeight);
	CSize GetBitmapDimension() const;

// Implementation
public:
	virtual ~CBitmap();
#ifdef _DEBUG
	virtual void Dump(CDumpContext& dc) const;
#endif
};

位图加载

a)WIN32-API从资源中加载位图:

HBITMAP LoadBitmap(  HINSTANCE hInstance,   LPCTSTR lpBitmapName);

b)获取位图信息:

BITMAP bm;
GetObject(g_hBitmap, sizeof(bm), &bm);

c)获取位图像素:

LONG GetBitmapBits(
  HBITMAP hBitmap,  // 位图句柄
  LONG    cbBuffer, // 缓冲区大小(以字节为单位)
  LPVOID  lpvBits   // 指向缓冲区的指针
);

d)设置位图像素:

LONG SetBitmapBits(
  HBITMAP hbmp,
  DWORD cBytes,
  CONST VOID *lpBits
);

位图显示

Win32下
a)创建内存DC:

HDC mdc = CreateCompatibleDC(hdc);  //如果代入NULL代表:GetDC(NULL)桌面关联的DC

b)内存DC选择位图:

SelectObject(mdc, g_hBitmap);

c)对窗口DC输出:

BitBlt(hdc, 0, 0, 604, 603, mdc, 0, 0, SRCCOPY);

d)删除内存DC

DeleteDC(mdc);

MFC下的位图显示流程

CPaintDC dc(this); // 窗口DC
CDC mdc;
BITMAP bm;
m_bitmap.GetBitmap(&bm);
mdc.CreateCompatibleDC(&dc);
mdc.SelectObject(&m_bitmap);
dc.BitBlt(190, 120, bm.bmWidth/2, bm.bmHeight/2, &mdc,
										 bm.bmWidth / 2, bm.bmHeight / 2, SRCCOPY);

加载位图 Win32下

#include
#include
#include
#include "resource.h"
HBITMAP g_hBitmap;
void OnPaint(HWND hDlg, HDC hdc)
{
	HDC mdc = CreateCompatibleDC(hdc);
	SelectObject(mdc, g_hBitmap);					//把图片选择在内存里
	BitBlt(hdc, 0, 0, 604, 603, mdc, 0, 0, SRCCOPY);  //对窗口dc进行输出
	DeleteDC(mdc);
}
POINT offset{ 65535,65535 };
INT_PTR CALLBACK theProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_INITDIALOG:
	{
		BITMAP bm;
		GetObject(g_hBitmap, sizeof(bm), &bm);
		MoveWindow(hDlg, 100, 100, bm.bmWidth, bm.bmHeight,FALSE);
	}
	return TRUE;
	case WM_LBUTTONUP:
	{
		offset = { 65535,65535 };
		ReleaseCapture();

		return TRUE;	
	}
	case WM_LBUTTONDOWN:
	{
		POINTS pt = MAKEPOINTS(lParam);
		offset = { pt.x,pt.y };
		ClientToScreen(hDlg, &offset);
		SetCapture(hDlg);
		SetWindowLongPtr(hDlg, GWL_STYLE, GetWindowLongPtr(hDlg, GWL_STYLE) & ~WS_CAPTION);
		return TRUE;
	}

	case WM_MOUSEMOVE:
	{
		if (offset.x!=65535)
		{
			RECT rc; 
			GetWindowRect(hDlg, &rc);
			int offsetX = offset.x -rc.left;
			int offsetY = offset.y -rc.top;
			
			POINTS ptMove = MAKEPOINTS(lParam);
			SetWindowPos(hDlg, NULL, ptMove.x - offsetX, ptMove.y - offsetY, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
		}
	 
	}
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hDlg, &ps);  //hdc 理解为绘图句柄  绑定什么 就绘图什么

		OnPaint(hDlg,hdc);
		EndPaint(hDlg, &ps);  //成对使用
	}
	return TRUE;
	 
	break;
	case WM_COMMAND:
	{
		if (LOWORD(wParam) == IDCANCEL)
			EndDialog(hDlg, IDCANCEL);
	}
	break;
	}
	return FALSE;//return 0代表系统默认要执行的 return 1代表执行系统以外的
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	g_hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_LOGO) );

	DialogBox(hInstance, MAKEINTRESOURCE(IDD_GDI_DLG), NULL, theProc);
	return 0;
}

加载位图 MFC下

CBitmapDlg .h

class CBitmapDlg : public CDialogEx
{
// 构造
	CBitmap m_bitmap;
}

CBitmapDlg .cpp

BOOL CBitmapDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	m_bitmap.LoadBitmap(IDB_BITMAP);
 
	BITMAP bm;
	m_bitmap.GetBitmap(&bm);
	MoveWindow(0, 0, bm.bmWidth, bm.bmHeight, FALSE); 
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
void CBitmapDlg::OnPaint()
{ 
	CPaintDC dc(this); // 用于绘制的设备上下文

	CRect rect;
	GetClientRect(rect);
	CDC mdc; //创建内存dc
	mdc.CreateCompatibleDC(&dc);
	mdc.SelectObject(&m_bitmap);
	dc.BitBlt(0, 0, rect.Width(), rect.Height(), &mdc, 0, 0, SRCCOPY);
}
LRESULT CBitmapDlg::OnNcHitTest(CPoint point)
{
	return	HTCAPTION;  //用户拖动客户区
	return CDialogEx::OnNcHitTest(point);
}

MFC第二十五天 位图加载与显示的方法,StretchBit位图拉伸、开发三态按钮类CBitmapButton的方法(WM_MOUSELEAVE鼠标悬停与离开判断)_第1张图片

StretchBit位图拉伸

CStrechDlg.h

class CStrechDlg : public CDialogEx
{
// 构造
	CDC m_dc; 
	CSize m_size{}; //用来记录位图的大小(宽高)
}

CStrechDlg.cpp

BOOL CStrechDlg::OnInitDialog(){
	CDialogEx::OnInitDialog();
	CBitmap m_bmp;
	m_bmp.LoadBitmap(IDB_STRECH);

	BITMAP bm;
	m_bmp.GetBitmap(&bm);
	m_size.SetSize(bm.bmWidth, bm.bmWidth);  //记录了大小 高宽

	m_dc.CreateCompatibleDC(NULL);
	m_dc.SelectObject(&m_bmp);
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
void CStrechDlg::OnPaint(){	 
	CPaintDC dc(this); // 用于绘制的设备上下文
	dc.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dc, 0, 0, SRCCOPY);
	dc.SetStretchBltMode(STRETCH_HALFTONE);//图片在放大或缩小时可能会失真 使用这个函数可以恢复

	dc.StretchBlt(m_size.cx,0, m_size.cx*2, m_size.cy,&m_dc,0,0,m_size.cx,m_size.cy, SRCCOPY); 
	//(左右)x坐标放大了两倍 脸蛋拉宽了  y(上下)
	dc.StretchBlt(0,m_size.cy,m_size.cx/2,m_size.cy/2,&m_dc,0,0,m_size.cx,m_size.cy, SRCCOPY);
	dc.StretchBlt(m_size.cx / 2, m_size.cy, m_size.cx / 2, m_size.cy / 2, &m_dc, m_size.cx, 0, -m_size.cx, m_size.cy, SRCCOPY); 
	//对图像进行旋转  逆时针旋转一周  让x方向翻转
	dc.StretchBlt(0, m_size.cy*3/2, m_size.cx / 2, m_size.cy / 2, &m_dc, 0,m_size.cy, m_size.cx, -m_size.cy, SRCCOPY);
	//对图像进行旋转  逆时针旋转一周  让y方向翻转
}

StretchBit位图 填满全屏

class CMainDlg : public CDialogEx
{
// 构造
	CBitmap m_bitmap;
}
BOOL CMainDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	int cx = GetSystemMetrics(SM_CXSCREEN); //设置全屏
	int cy = GetSystemMetrics(SM_CYSCREEN);
	m_bitmap.LoadBitmap(IDB_HOUSE);

	SetWindowPos(NULL, 0, 0, cx, cy, SWP_NOZORDER);
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
void CMainDlg::OnPaint(){
	CPaintDC dc(this); // 用于绘制的设备上下文
	BITMAP bm;
	m_bitmap.GetBitmap(&bm);
	CDC mdc;
	mdc.CreateCompatibleDC(&dc); 
	mdc.SelectObject(&m_bitmap);
	dc.BitBlt(190, 120, bm.bmWidth/2, bm.bmHeight/2, &mdc , 0, bm.bmHeight/2, SRCCOPY);
	//前2个参数代表屏幕坐标到窗口的位置 3,4代表位图的宽高 5代表来源dc,6,7代表来源起始位置
	CRect rect;
	GetClientRect(rect);
	dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &mdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); //全屏拉伸
	//在目标的位置 用客户区的高宽		8,9代表来源高宽			目标的高宽是大屏幕
} 

三态按钮类CBitmapButton的方法

CMainDlg.h

#pragma once
#include "CButtonXq.h"
class CMainDlg : public CDialogEx{
	CButtonXq m_btn;
	enum{IDC_TEST_BTN =0x1234};
public:
	CMainDlg(CWnd* pParent = nullptr);	// 标准构造函数
protected:
	HICON m_hIcon;
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	afx_msg void OnClickedTest();
	DECLARE_MESSAGE_MAP()
};

CMainDlg.cpp

BEGIN_MESSAGE_MAP(CMainDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_TEST_BTN,OnClickedTest) //BN button Notify
END_MESSAGE_MAP()

BOOL CMainDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	m_btn.Create(WS_VISIBLE | WS_CHILD, {}, this, IDC_TEST_BTN);
	m_btn.LoadBitmaps(IDB_NORMAL, IDB_SELECT, IDB_TRACK);
	m_btn.  SetWindowPos(NULL,200,50,0,0,SWP_NOSIZE|SWP_NOZORDER);
	//保持原大小的移动 SWP_NOSIZE,0,0	SWP_NOZORDER NULL
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
void CMainDlg::OnPaint()
{
	CPaintDC dc(this); // 用于绘制的设备上下文
	CBitmap bmp;
	bmp.LoadOEMBitmap(OBM_ZOOM);
	CDC mdc;
	BITMAP bm;
	bmp.GetBitmap(&bm);
	mdc.CreateCompatibleDC(&mdc);
	mdc.SelectObject(&bmp);
	dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight,&mdc, 0, 0, SRCCOPY);
}
void CMainDlg::OnClickedTest()
{
	AfxMessageBox(_T("测试三态按钮成功"));
}

CButtonXq.h

class CButtonXq : public CWnd{
	DECLARE_DYNAMIC(CButtonXq)
	CDC m_dc[4]; //4种状态
	enum { BT_NORMAL = 0,BT_SELECT=1,BT_TRACK =2,BT_DISABLE=3 };
	BOOL m_bTrack{}, m_bSelect{}, m_bLeave{};
public:
	CButtonXq();
	virtual ~CButtonXq();

	BOOL LoadBitmaps(UINT nNormal, UINT nSelSel = -1, UINT nTrack = -1, UINT nDisable = -1);
	BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
	{
		return CWnd::Create(NULL, NULL, dwStyle | WS_CHILD, rect, pParentWnd, nID);
	}
public:
	afx_msg void OnPaint();
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
//	afx_msg void OnMouseHover(UINT nFlags, CPoint point);
//	afx_msg void OnMouseLeave();
};

CButtonXq.cpp

BOOL CButtonXq::LoadBitmaps(UINT nNormal, UINT nSelSel, UINT nTrack, UINT nDisable)
{
	CDC* pDC = m_dc;
	CBitmap bmp;
	if (!bmp.LoadBitmap(nNormal))
		return FALSE;
	BITMAP bm;
	bmp.GetBitmap(&bm);
	SetWindowPos(NULL, 0, 0, bm.bmWidth, bm.bmHeight, SWP_NOMOVE | SWP_NOZORDER);
	pDC->CreateCompatibleDC(NULL);
	pDC->SelectObject(&bmp);
	int i = 0;
	UINT nIDs[] = { nNormal,nSelSel,nTrack,nDisable };
	while (++i<_countof(nIDs))
	{
		UINT nID = nIDs[i];
		++pDC;
		if (nID!=-1)
		{
			CBitmap bmp;
			if (bmp.LoadBitmap(nIDs[i]))
			{
				pDC->CreateCompatibleDC(NULL);
				pDC->SelectObject(&bmp);
			}
		}
	}
    return TRUE;
}
void CButtonXq::OnPaint(){
	CPaintDC dc(this); // device context for painting
	CRect rect;
	GetClientRect(rect);
	CDC* pDC = m_dc;
	if (m_bSelect)
	{
		if (m_bLeave)
			pDC = m_dc + 2;
		else
			pDC = m_dc + 1;
	}
	else if (m_bTrack)
		pDC = m_dc + 2;
	dc.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
}
BOOL CButtonXq::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{	
	return CWnd::OnSetCursor(pWnd, nHitTest, message);
}

void CButtonXq::OnLButtonDown(UINT nFlags, CPoint point)
{ 
	if (!m_bSelect)
	{
		m_bSelect = TRUE;
		Invalidate(FALSE);
	}
	CWnd::OnLButtonDown(nFlags, point);
}
void CButtonXq::OnLButtonUp(UINT nFlags, CPoint point){
	ReleaseCapture();
	if (m_bSelect){
		m_bSelect = FALSE;
		Invalidate(FALSE);
		CRect rect;
		GetClientRect(rect); //在它的范围内弹起的 发送commad的消息
		if (rect.PtInRect(point))
			GetParent()->PostMessage(WM_COMMAND, GetDlgCtrlID(), (LPARAM)GetSafeHwnd());
			//(UINT message, WPARAM wParam, LPARAM lParam)发送的消息 控件ID 控件句柄
		else
			m_bTrack = FALSE;	}
	Invalidate(FALSE);
	CWnd::OnLButtonUp(nFlags, point);
}
/*
使用OnMouseHover
TRACKMOUSEEVENT tme;
tme.dwHoverTime = 16;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.hwndTrack = GetSafeHwnd(); //窗口句柄
TrackMouseEvent(&tme);
*/
void CButtonXq::OnMouseMove(UINT nFlags, CPoint point)  //鼠标响应事件
{
	if (!m_bTrack)  //切换算法
	{
		SetCapture();//不使用capture的话 ,你不知道这个点什么时候跑出去了
		m_bTrack = TRUE;
		Invalidate(FALSE);
	}
	else //离开的时候
	{
		CRect rect;
		GetClientRect(rect);
		if (!rect.PtInRect(point)) //微细观察 你长按住 拖出边界后松开 颜色应当恢复
		{
			if (m_bSelect)
			{
				if(!m_bLeave)
				{
					m_bLeave = TRUE;
					Invalidate(FALSE);
				}		
			}
			else
			{
				ReleaseCapture();  //不ReleaseCapture会锁死光标
				m_bTrack = FALSE;
				Invalidate(FALSE);
			}
		}
		else
		{
			if (m_bSelect)
			{
				if (m_bLeave)
				{
					m_bLeave = FALSE;
					Invalidate(FALSE);
				}
			}
		}
	}
	TRACE("OnMouseMove:	x=%d y =%d\n", point.x, point.y);
	CWnd::OnMouseMove(nFlags, point);
}

//void CButtonXq::OnMouseHover(UINT nFlags, CPoint point) //鼠标悬停
//{
//	if (!m_bTrack)  //切换算法
//	{
//		m_bTrack = TRUE;
//		Invalidate(FALSE);
//	} 
//	CWnd::OnMouseHover(nFlags, point);
//}

//void CButtonXq::OnMouseLeave() //鼠标离开
//{
//	if (m_bTrack)
//	{
//		m_bTrack = FALSE;
//		Invalidate(FALSE);
//	}
//	CWnd::OnMouseLeave();
//}

鼠标离开判断的方法:

a)WM_MOUSELEAVE消息:需要TrackMouseEvent来追踪。
void CButtonLx::OnMouseMove(UINT nFlags, CPoint point)
{
    TRACKMOUSEEVENT tme;
    tme.dwHoverTime = 16;
    tme.cbSize = sizeof(TRACKMOUSEEVENT);
    tme.dwFlags = TME_HOVER| TME_LEAVE;
    tme.hwndTrack = GetSafeHwnd(); // 窗口句柄
    TrackMouseEvent(&tme);
  
    CWnd::OnMouseMove(nFlags, point);
}
b)SetCapture和ReleaseCapture:设置捕捉。

你可能感兴趣的:(MFC开发,mfc,c++)