//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);
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);
#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;
}
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);
}
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方向翻转
}
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代表来源高宽 目标的高宽是大屏幕
}
#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()
};
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("测试三态按钮成功"));
}
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();
};
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:设置捕捉。