GDI双缓冲绘图

33 篇文章 14 订阅
31 篇文章 1 订阅

一、简介

在进行复杂图形绘制时,若直接在屏幕DC上进行绘制,则会出现明显的闪烁。闪烁产生的原因是当绘制的图形较为复杂时,图形绘制过程中就被刷新到屏幕上,导致结果断断续续地显示出来。双缓冲绘图的原理是在另开辟一块内存用于绘制,当所有绘制工作完成后将内存数据一次性拷贝到屏幕上。

双缓冲绘图步骤:

创建兼容DC(CreateCompatibleDC)

创建兼容位图(CreateCompatibleBitmap)

将兼容位图选入兼容DC(SelectObject)

在兼容DC中进行绘制工作

将兼容DC中的像素拷贝至屏幕DC(BitBlt)

从兼容DC中换出兼容位图(SelectObject)

删除兼容位图(DeleteObject)

删除兼容DC(DeleteObject)

二、实现:

演示程序绘制了从窗口中心发射的300条射线,为了凸显双缓冲的效果,特意在绘制每条线段时添加延时操作(sleep)。可以发现,若直接在屏幕DC上绘制,能够明显感觉到每条线段的绘制过程,而采用双缓冲则无此现象。

直接绘制代码:

void CtestBFDlg::OnBnClickedDirectDraw()
{
	// TODO: 在此添加控件通知处理程序代码
	CPen newPen;
	CPen *pOldPen;
	CBrush newBrush;
	CBrush *pOldBrush;
	CRect zcRect;
	CDC *pDc;
	CPoint cenpoint;
	CPoint point;

	pDc = Picture.GetDC();
	Picture.GetClientRect(&zcRect);
	newPen.CreatePen(PS_SOLID,1,RGB(0,255,0));//画笔
	pOldPen = pDc->SelectObject(&newPen); 
	newBrush.CreateSolidBrush(RGB(255,255,255));//画刷
	pOldBrush=pDc->SelectObject(&newBrush);

	//绘制工作(直接在屏幕DC上作图)
	pDc->FillRect(zcRect,&newBrush);
	float radius=200;
	float degree=0;
	float x,y;
	float cenx,ceny;
	cenx=zcRect.Width()/2.0;
	ceny=zcRect.Height()/2.0;
	cenpoint.x=cenx;
	cenpoint.y=ceny;
	for(int i=0;i<300;i++)
	{
		pDc->MoveTo(cenpoint);
		degree=2*PI/300*i;
		point.x=radius*cos(degree)+cenx;
		point.y=radius*sin(degree)+ceny;
		Sleep(1);        //刻意延时以凸显效果
		pDc->LineTo(point);
	}
	pDc->SelectObject(pOldPen);
	pDc->SelectObject(pOldBrush);
	newBrush.DeleteObject();
	newPen.DeleteObject();
	ReleaseDC(pDc);
}
双缓冲绘制代码:

void CtestBFDlg::OnBnClickedDFDraw()
{
	// TODO: 在此添加控件通知处理程序代码
	CPen newPen;
	CPen *pOldPen;
	CBrush newBrush;
	CBrush *pOldBrush;
	CRect zcRect;
	CDC *pDc;
	CPoint cenpoint;
	CPoint point;
	pDc = Picture.GetDC();
	Picture.GetClientRect(&zcRect);	
	
	CDC dc;
	dc.CreateCompatibleDC(pDc);//创建兼容DC
	CBitmap memBmp;
	memBmp.CreateCompatibleBitmap(pDc, zcRect.Width(), zcRect.Height());//创建兼容位图
	CBitmap* OldBmp = dc.SelectObject(&memBmp);//将位图选入DC

	newPen.CreatePen(PS_SOLID,1,RGB(255,0,0));
	pOldPen = dc.SelectObject(&newPen); 
	newBrush.CreateSolidBrush(RGB(255,255,255));
	pOldBrush=dc.SelectObject(&newBrush);

	//绘制工作(在兼容DC中作图)
	//****************************************************************
	dc.FillRect(zcRect,&newBrush);	
	float radius=200;
	float degree=0;
	float x,y;
	float cenx,ceny;
	cenx=zcRect.Width()/2.0;
	ceny=zcRect.Height()/2.0;
	cenpoint.x=cenx;
	cenpoint.y=ceny;
	for(int i=0;i<300;i++)
	{
		dc.MoveTo(cenpoint);
		degree=2*PI/300*i;
		point.x=radius*cos(degree)+cenx;
		point.y=radius*sin(degree)+ceny;
		Sleep(1);       //此处刻意延时以凸显效果
		dc.LineTo(point);
	}
	//****************************************************************
	pDc->BitBlt(0,0,zcRect.Width(),zcRect.Height(),&dc,0,0,SRCCOPY);//将兼容DC中位图拷贝至屏幕DC
	dc.SelectObject(pOldPen);
	dc.SelectObject(pOldBrush);
	dc.SelectObject(OldBmp);
	newBrush.DeleteObject();
	newPen.DeleteObject();
	memBmp.DeleteObject();
	dc.DeleteDC();
	ReleaseDC(pDc);
}


 

界面:

源码下载


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
GDI+是Windows操作系统中的一个图形处理API,它提供了一系列用于绘制图形和处理图像的函数和类。双缓冲是一种绘图技术,用于解决绘图过程中的闪烁问题。在使用GDI+进行绘图时,可以通过双缓冲技术来减少或消除绘图过程中的闪烁现象。 下面是一个使用GDI+双缓冲的示例代码: ```c++ #include <windows.h> #include <gdiplus.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("DoubleBuffer"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("Double Buffering Demo"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static int cxClient, cyClient; HDC hdc; PAINTSTRUCT ps; Gdiplus::Graphics* graphics; Gdiplus::Bitmap* bitmap; Gdiplus::Graphics* memGraphics; Gdiplus::Bitmap* memBitmap; switch (message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); // 创建一个与窗口大小相同的内存位图 bitmap = new Gdiplus::Bitmap(cxClient, cyClient); graphics = Gdiplus::Graphics::FromImage(bitmap); // 创建一个与内存位图相同大小的内存绘图对象 memBitmap = new Gdiplus::Bitmap(cxClient, cyClient); memGraphics = Gdiplus::Graphics::FromImage(memBitmap); // 在内存绘图对象上进行绘制操作 // ... // 将内存绘图对象的内容绘制到窗口的设备上下文中 graphics->DrawImage(memBitmap, 0, 0); // 释放资源 delete graphics; delete bitmap; delete memGraphics; delete memBitmap; EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } ``` 在上面的示例代码中,我们创建了一个窗口,并在窗口的`WM_PAINT`消息处理函数中使用了双缓冲技术。具体来说,我们创建了一个与窗口大小相同的内存位图,并在内存位图上进行绘制操作。然后,将内存位图的内容绘制到窗口的设备上下文中,从而实现了双缓冲绘图

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

聚沙塔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值