参考:https://blog.csdn.net/pudongdong/article/details/69396600
之前写过win32动态显示图片的博客(程序线程检测图片变动自动刷新,而非按按钮再刷新的情况),这次用到了mfc。原理是一样的。
OnInitDialog函数初始化
BOOL CXxxDlg::OnInitDialog() { CDialog::OnInitDialog(); if (m_bmp.m_hObject != NULL) m_bmp.DeleteObject(); /*载入图片*/ HBITMAP hbmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),L"initPic.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE); if (hbmp == NULL) return FALSE; /*取得加载的BMP的信息*/ m_bmp.Attach(hbmp); DIBSECTION ds; BITMAPINFOHEADER &bminfo = ds.dsBmih; m_bmp.GetObject(sizeof(ds), &ds); int cx = bminfo.biWidth; int cy = bminfo.biHeight; /*得到了图像的宽度和高度后,对图像大小进行适应,即调整控件的大小,让它正好显示一张图片*/ CRect rect; GetDlgItem(IDC_PIC_ZONE)->GetWindowRect(&rect); ScreenToClient(&rect); /*调整大小*/ GetDlgItem(IDC_PIC_ZONE)->MoveWindow(rect.left, rect.top, cx, cy, true); return TRUE; }
OnPaint具体画图。
IDC_PIC_ZONE为picture control控件。
void CXxxDlg::OnPaint() { if (m_bmp.m_hObject != NULL) m_bmp.DeleteObject(); /*重新载入图片,因为可能刷新*/ HBITMAP hbmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(), L"initPic.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE); if (hbmp == NULL) return; /*取得加载的BMP的信息*/ m_bmp.Attach(hbmp); DIBSECTION ds; BITMAPINFOHEADER &bminfo = ds.dsBmih; m_bmp.GetObject(sizeof(ds), &ds); /*若用此句,得到的是对话框的DC,图片将被绘制在对话框上*/ //CPaintDC dc(this); /*用此句,得到picture控件的DC,图像将被绘制在控件上 */ CPaintDC dc(GetDlgItem(IDC_PIC_ZONE)); /*若用此两句,得到的是屏幕的DC,图片将被绘制在屏幕上*/ // CDC dc; // dc.m_hDC=::GetDC(NULL); CRect rcclient; GetDlgItem(IDC_PIC_ZONE)->GetClientRect(&rcclient); CDC memdc; memdc.CreateCompatibleDC(&dc); CBitmap bitmap; bitmap.CreateCompatibleBitmap(&dc, rcclient.Width(), rcclient.Height()); memdc.SelectObject(&bitmap); CWnd::DefWindowProc(WM_PAINT, (WPARAM)memdc.m_hDC, 0); CDC maskdc; maskdc.CreateCompatibleDC(&dc); CBitmap maskbitmap; maskbitmap.CreateBitmap(rcclient.Width(), rcclient.Height(), 1, 1, NULL); maskdc.SelectObject(&maskbitmap); maskdc.BitBlt(0, 0, rcclient.Width(), rcclient.Height(), &memdc, rcclient.left, rcclient.top, SRCCOPY); CBrush brush; brush.CreatePatternBrush(&m_bmp); dc.FillRect(rcclient, &brush); dc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &memdc, rcclient.left, rcclient.top, SRCPAINT); brush.DeleteObject(); }
这个程序功能是在设备上按手指后,界面自动刷新指静脉的图片
所以界面的刷新要自己写代码刷新(刷新区域在RECT里设置,不要刷新面积太大,否则整个界面都闪烁):
void CXxDlg::refreshImg() { RECT rect; //idcPicZone.GetWindowRect(&rect); SetRect(&rect, 10, 10, 520, 230); InvalidateRect( &rect, true); UpdateWindow(); }
注意,要想程序运行到OnPaint方法,需要在BEGIN_MESSAGE_MAP注册ON_WM_PAINT()
效果:
上面程序那样写。是由特定需求决定的:程序检测图片更新后自动刷新图片,而非按了什么按钮产生事件响应。另外,还进行了位图的转化
由于不触发事件,需要自己手动刷新界面
实际上,如果是按按钮就刷新界面的话,写法就简单了:
void CXxDlg::_setPic() { CImage image; CWnd* pWnd = GetDlgItem(IDC_SKIN_SHOW); CDC* pDC = pWnd->GetDC(); HDC hDC = pDC->m_hDC; CRect rect_frame; pWnd->GetClientRect(&rect_frame); image.Load(L"xxx\xxx.png"); ::SetStretchBltMode(hDC, HALFTONE); ::SetBrushOrgEx(hDC, 0, 0, NULL); image.Draw(hDC, rect_frame); ReleaseDC(pDC); image.Destroy(); }
在事件响应函数里加入这样代码就可以刷新图片了(图片是load的路径)
因为有事件响应,界面自动刷新
不过有个问题,如果是想打开程序后,初始界面显示一张图片的话,把上面的代码写在OnInitDialog()函数里是没用效果的
必须要把上面的代码写在OnPaint()里:
void CXxDlg::OnPaint() { /*默认显示第一张预览图*/ ……………………………… __super::OnPaint(); }
注意要写__super::OnPaint();
否则整个界面就只画这一张图了