我向OnPaint()添加了代码,它在Windows 10笔记本电脑上可以正确绘制,但是该绘制未在另一台计算机上显示(Windows 8)。我是绘画的新手,我可能做错了什么-也许使用了invalidate和updatewindow。无论如何,这是我的代码:
我在对话窗口上绘画; OnPaint()的代码主要由Visual Studio创建-我只是在末尾添加了DrawValveImage()。另外,here是显示DrawValveImage()绘制的图片。我认为您无需查看DrawValveImage()的所有代码即可解决该问题;我认为我的错误是我对DrawValveImage()的调用的放置。也许OnPaint()不是自定义绘画的正确选择。
void CCleaningAndScreeningDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
DrawValveImage();
}
void CCleaningAndScreeningDlg::DrawValveImage()
{
//my own drawing
CClientDC* pDC = new CClientDC(this);
pDC->SelectStockObject(NULL_BRUSH);
COLORREF blueBorder = RGB(67, 99, 155);
COLORREF blueFill = RGB(218, 227, 243);
int x1 = 1050;
int y1 = 50;
int width = 300;
int x2 = x1 + width;
int y2 = y1 + width;
CPen pen;
CBrush brush;
pen.CreatePen(PS_SOLID, 5, blueBorder);
brush.CreateSolidBrush(blueFill);
// select brush and pen
pDC->SelectObject(&pen);
pDC->SelectObject(&brush);
if (valveImageDrawn == FALSE)
pDC->Ellipse(x1, y1, x2, y2);
DeleteObject(brush);
DeleteObject(pen);
DeleteObject(&brush);
DeleteObject(&pen);
int heightWidth = width;
int smallHeightWidth = heightWidth / 7;
int radiusFromOriginSmallCircle = heightWidth / 2.75;
for (int circleIndex = 0; circleIndex < 10; circleIndex++) {
POINT centerSmallCircle = FindPointOnCircle(POINT{ heightWidth / 2, heightWidth / 2 }, radiusFromOriginSmallCircle, (circleIndex * 360 / 10) - 90);
int smallCircleX = centerSmallCircle.x - smallHeightWidth / 2 + x1;
int smallCircleY = centerSmallCircle.y - smallHeightWidth / 2 + y1;
rectangle smallCircleRect = { smallCircleX, smallCircleY, smallCircleX + smallHeightWidth, smallCircleY + smallHeightWidth };
rectsSmallCircles[circleIndex] = smallCircleRect;
bool greenFilled = false;
if (valvePosition - 1 == circleIndex) {
CPen pen;
CBrush brush;
COLORREF greenFill = RGB(181, 230, 29);
pen.CreatePen(PS_SOLID, 5, blueBorder);
brush.CreateSolidBrush(greenFill);
pDC->SelectObject(&pen);
pDC->SelectObject(&brush);
pDC->Ellipse(smallCircleRect.x1, smallCircleRect.y1, smallCircleRect.x2, smallCircleRect.y2);
DeleteObject(brush);
DeleteObject(pen);
DeleteObject(&brush);
DeleteObject(&pen);
greenFilled = true; //if mouse clicked and green color is painted on the valve image
}
else {
CPen pen;
CBrush brush;
pen.CreatePen(PS_SOLID, 5, blueBorder);
brush.CreateSolidBrush(blueFill);
pDC->SelectObject(&pen);
pDC->SelectObject(&brush);
pDC->Ellipse(smallCircleRect.x1, smallCircleRect.y1, smallCircleRect.x2, smallCircleRect.y2);
DeleteObject(brush);
DeleteObject(pen);
DeleteObject(&brush);
DeleteObject(&pen);
}
CString circleText;
int CircleNumber = circleIndex + 1;
circleText.Format(_T("%d"), CircleNumber);
CRect testRect = { smallCircleRect.x1,
smallCircleRect.y1, smallCircleRect.x2, smallCircleRect.y2 };
pDC->SetBkMode(TRANSPARENT);
CClientDC dc(this);
CFont font;
VERIFY(font.CreateFont(
30, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_BOLD, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("Arial"))); // lpszFacename
CFont* def_font = pDC->SelectObject(&font);
pDC->DrawText(circleText, testRect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
pDC->SelectObject(def_font);
font.DeleteObject();
}
//redraw the combobox infront of the valve-image
UpdateData(TRUE);
comboPorts.Invalidate();
comboPorts.UpdateWindow();
valveImageDrawn = true;
}
答案 0 :(得分:3)
OnPaint()
是进行自定义绘画的正确方法。覆盖OnPaint()
时,您应该不调用基类的OnPaint()
方法。您有责任自己绘制窗口的全部内容(子窗口除外)。
您只需要此代码:
void CCleaningAndScreeningDlg::OnPaint()
{
CPaintDC dc(this); // constructor of CPaintDC calls ::BeginPaint()
DrawValveImage( dc ); // pass device context to the drawing function
// Destructor of CPaintDC automatically calls ::EndPaint()!
}
您可以看到我已经向DrawValveImage
添加了一个参数。声明看起来像这样:
void DrawValveImage( CDC& dc );
确保在绘图功能中仅使用dc
参数进行绘图。
这是错误:
CClientDC* pDC = new CClientDC(this);
您不应创建任何其他设备上下文。
另一个错误的示例:
pDC->SelectObject(&pen); pDC->SelectObject(&brush); if (valveImageDrawn == FALSE) pDC->Ellipse(x1, y1, x2, y2); DeleteObject(brush); DeleteObject(pen); DeleteObject(&brush); DeleteObject(&pen);
首先,在删除所选对象之前,不要还原设备上下文的原始状态。当仍在设备上下文中选择对象时,无法正确删除该对象。要解决此问题,请存储返回值SelectObject()
和SelectStockObject()
,这是指向设备上下文中先前选择的对象的指针(如果未选择,则有一个默认对象)。在删除对象之前,请调用SelectObject()
,并传递存储的指针。
第二,为什么要删除两次对象?让对象在离开当前范围时自动销毁自身,或者调用DeleteObject()
member 函数(非常需要)。
更正的代码:
auto pOldPen = dc.SelectObject(&pen);
auto pOldBrush = dc.SelectObject(&brush);
if (valveImageDrawn == FALSE)
dc.Ellipse(x1, y1, x2, y2);
if(pOldPen)
dc.SelectObject(pOldPen);
if(pOldBrush)
dc.SelectObject(pOldBrush );
// No need for DeleteObject(), the destructor of each object will delete it at the
// end of the current scope (before the function returns). But if you actually need it
// (say you want to reuse the variable), it would look like this:
// pen.DeleteObject();
// brush.DeleteObject();
此代码是不必要的:
//redraw the combobox infront of the valve-image UpdateData(TRUE); comboPorts.Invalidate(); comboPorts.UpdateWindow();
只需设置对话框窗口的WS_CLIPCHILDREN
样式(使用对话框编辑器)即可防止绘画代码在组合框上绘制。