我对用GDI绘制图形有点陌生..。
我做了一个油漆程序,它工作的很好,只是它引起了许多恼人的屏幕闪烁。我承认我的油漆代码并没有真正优化(缺乏时间),但它也不应该是超级低效的,所以我很困惑。
我所做的基本上是在init上创建一个兼容的DC,然后创建一个兼容的位图。然后,我选择它到兼容的DC,并绘制到兼容的DC。然后我使用BitBlit()将其复制到hDC窗口..。
有人能告诉我屏幕撕裂的可能原因吗?编辑:顺便说一下,屏幕闪烁只发生在路径的绘制过程中(在路径被绘制到hMemDC之前,它会被绘制到窗口的hDC )。
代码示例:(编辑:如果您需要看到更多您认为相关的代码,请批注,我将编辑)
路径:DrawTo(HDC)
bool Path::DrawTo(HDC hDC)
{
if(hDC == NULL || m_PointVector.size() <= 0) {
return false;
}
switch (m_Tool) {
case Tool_Pen:
{
Point2D p = m_PointVector.at(0);
if(m_PointVector.size() > 1) {
HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
MoveToEx(hDC, p.x, p.y, nullptr);
for(UINT i = 1; i < m_PointVector.size(); ++i) {
p = m_PointVector.at(i);
LineTo(hDC,p.x,p.y);
}
SelectObject(hDC,oldPen);
break;
} //else
SetPixel(hDC,p.x-1,p.y,m_Col);
SetPixel(hDC,p.x,p.y,m_Col);
SetPixel(hDC,p.x+1,p.y,m_Col);
SetPixel(hDC,p.x,p.y-1,m_Col);
SetPixel(hDC,p.x,p.y+1,m_Col);
break;
}
case Tool_Line:
{
if(m_PointVector.size() > 1) {
Point2D p = m_PointVector.at(0);
HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
MoveToEx(hDC, p.x, p.y, nullptr);
for(UINT i = 1; i < m_PointVector.size(); ++i) {
p = m_PointVector.at(i);
LineTo(hDC,p.x,p.y);
}
SelectObject(hDC,oldPen);
}
break;
}
case Tool_Ellipse:
{
if(m_PointVector.size() > 1) {
HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
SelectObject(hDC,m_hBrush);
Point2D p1 = m_PointVector.at(0);
Point2D p2 = m_PointVector.at(1);
if(p1.x > p2.x) {
int iTemp = p1.x;
p1.x = p2.x;
p2.x = iTemp;
}
if(p1.y > p2.y) {
int iTemp = p1.y;
p1.y = p2.y;
p2.y = iTemp;
}
Ellipse(hDC,p1.x,p1.y,p2.x,p2.y);
SelectObject(hDC,oldPen);
}
break;
}
case Tool_Rectangle:
{
if(m_PointVector.size() > 1) {
HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
SelectObject(hDC,m_hBrush);
Point2D p1 = m_PointVector.at(0);
Point2D p2 = m_PointVector.at(1);
if(p1.x > p2.x) {
int iTemp = p1.x;
p1.x = p2.x;
p2.x = iTemp;
}
if(p1.y > p2.y) {
int iTemp = p1.y;
p1.y = p2.y;
p2.y = iTemp;
}
Rectangle(hDC,p1.x,p1.y,p2.x,p2.y);
SelectObject(hDC,oldPen);
}
break;
}
case Tool_LineTrack:
{
HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
SelectObject(hDC,m_hBrush);
int vSize = (int)m_PointVector.size();
Point2D p = m_PointVector.at(0);
if (vSize <= 1) {
Ellipse(hDC,p.x-10,p.y-10,p.x+10,p.y+10);
}
else {
//draw LineTrack
Point2D pTemp = m_PointVector.at(1);
MoveToEx(hDC,p.x,p.y,nullptr);
for (int i = 1; i < vSize; ++i) {
p = m_PointVector.at(i);
pTemp = m_PointVector.at(i-1);
LineTo(hDC,p.x,p.y);
Ellipse(hDC,pTemp.x-10,pTemp.y-10,pTemp.x+10,pTemp.y+10);
}
Ellipse(hDC,p.x-10,p.y-10,p.x+10,p.y+10);
}
SelectObject(hDC,oldPen);
break;
}
}
return true;
}WndProc(HWND,UINT,WPARAM,LPARAM)
LRESULT MyApp::WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
if(iMsg == WM_CREATE)
{
CREATESTRUCT *pCS = (CREATESTRUCT*)lParam;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)pCS->lpCreateParams);
}
else
{
//retrieve the stored "this" pointer
MyApp* pApp = (MyApp*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch (iMsg)
{
case WM_PAINT:
{
pApp->Paint();
return 0;
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
int wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_NEW:
{
////
return 0;
}
return 0;
case IDM_LOAD:
{
//////
return 0;
}
case IDM_SAVE:
{
//////
return 0;
}
case IDM_SAVEAS:
{
//////
return 0;
}
case IDM_COLOURMAIN:
{
COLORREF col;
if(MyWin32Funcs::OnColorPick(col)) {
pApp->m_pPath->SetColor1(col);
}
return 0;
}
case IDM_COLOURSECONDARY:
{
COLORREF col;
if(MyWin32Funcs::OnColorPick(col)) {
pApp->m_pPath->SetColor2(col);
}
return 0;
}
case IDM_PEN:
{
pApp->m_pPath->SetTool(Tool_Pen);
return 0;
}
case IDM_LINE:
{
pApp->m_pPath->SetTool(Tool_Line);
return 0;
}
case IDM_ELLIPSE:
{
pApp->m_pPath->SetTool(Tool_Ellipse);
return 0;
}
case IDM_RECTANGLE:
{
pApp->m_pPath->SetTool(Tool_Rectangle);
return 0;
}
case IDM_LINETRACK:
{
pApp->m_pPath->SetTool(Tool_LineTrack);
return 0;
}
default:
{
//////
return 0;
}
}
}
case WM_LBUTTONUP:
{
//////
Point2D p;
p.x = LOWORD(lParam);
p.y = HIWORD(lParam);
switch(pApp->m_pPath->GetTool()) {
case Tool_Pen:
{
pApp->m_bPaintToBitmap = true;
InvalidateRect(pApp->m_hWnd,NULL,true);
break;
}
case Tool_Ellipse:
{
pApp->m_bPaintToBitmap = true;
InvalidateRect(pApp->m_hWnd,NULL,true);
break;
}
case Tool_Rectangle:
{
pApp->m_bPaintToBitmap = true;
InvalidateRect(pApp->m_hWnd,NULL,true);
break;
}
case Tool_Line:
{
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
case Tool_LineTrack:
{
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
}
return 0;
}
case WM_RBUTTONUP:
{
//////
int x = LOWORD(lParam);
int y = HIWORD(lParam);
switch(pApp->m_pPath->GetTool()) {
case Tool_Line:
{
pApp->m_bPaintToBitmap = true;
InvalidateRect(pApp->m_hWnd,NULL,true);
break;
}
case Tool_LineTrack:
{
pApp->m_bPaintToBitmap = true;
InvalidateRect(pApp->m_hWnd,NULL,true);
break;
}
}
return 0;
}
case WM_LBUTTONDOWN:
{
Point2D p;
p.x = LOWORD(lParam);
p.y = HIWORD(lParam);
switch(pApp->m_pPath->GetTool()) {
case Tool_Pen:
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
}
case WM_MOUSEMOVE:
{
Point2D p;
p.x = LOWORD(lParam);
p.y = HIWORD(lParam);
if (wParam & MK_LBUTTON) {
switch(pApp->m_pPath->GetTool()) {
case Tool_Pen:
{
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
case Tool_Ellipse:
{
if( pApp->m_pPath->GetLen() >= 1) {
pApp->m_pPath->SetPointAt(1,p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
}
else {
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
}
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
case Tool_Rectangle:
{
if( pApp->m_pPath->GetLen() >= 1) {
pApp->m_pPath->SetPointAt(1,p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
}
else {
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
}
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
}
}
return 0;
}
case WM_CLOSE:
{
//////
return 0;
}
}
PostQuitMessage(0);
return 0;
}
}
}
return DefWindowProc (hWnd, iMsg, wParam, lParam) ;
}MyApp::Paint()
void MyApp::Paint()
{
BeginPaint(m_hWnd,&m_PaintStruct);
if (m_bPaintToBitmap) {
Point2D p;
p.x = BMPXOFFSET;
p.y = BMPYOFFSET;
m_pPath->Offset(p);
m_pPath->DrawTo(m_pBitmapPainter->GetMemDC());
m_pPath->ClrPath();
m_pBitmapPainter->Paint(); //this is where BitBlt() occurs
m_bPaintToBitmap = false;
if(m_pBitmapPainter->IsAdjusted() == false) {
m_pBitmapPainter->SetbAdjusted(true);
}
}
else {
m_pBitmapPainter->Paint(); //this is where BitBlt() occurs
m_pPath->DrawTo(m_hDC);
}
EndPaint(m_hWnd,&m_PaintStruct);
}任何帮助都将不胜感激。
发布于 2011-10-03 14:17:43
我觉得你看到的是闪烁而不是撕裂。为了最小化闪烁,您的WM_PAINT应该精确地写入窗口DC一次。通常,这个操作是一个BitBlt。
HDC hdc = BeginPaint(m_hwnd, &m_PaintStruct);
... paint to bitmap ...
BitBlt(hdc, ...); // blt from bitmap to screen
EndPaint(m_hwnd, &m_PaintStruct);如果您在多个步骤中绘制到窗口DC,则打开该窗口以进行闪烁。
您对问题的描述与代码不匹配。在您的描述中,您说您正在从兼容的DC闪到窗口hDC。但是在您的代码中,BitBlt后面是一个m_pPath->DrawTo(m_hDC)。如果在DrawTo期间发生刷新,则屏幕将使用部分绘制的视图刷新,从而导致闪烁。
发布于 2011-10-03 10:59:18
如果要绘制整个工作区,则重写WM_ERASEBKGND,然后只返回TRUE。这将减少闪烁。
正如其他人指出的那样,请使用WM_PAINT提供的WM_PAINT,因为它可能包含剪辑区域,以及其他可能优化屏幕更新的内容。
编辑如果您没有绘制整个工作区,可以在您知道WM_PAINT处理程序不会绘制的区域执行背景绘图。
发布于 2011-10-03 10:26:00
BeginPaint给你你应该画的HDC。你是在忽视它。
https://stackoverflow.com/questions/7633672
复制相似问题