Win32 GDI 如何画圆?

4

我正在尝试绘制一个圆,目前使用的是Ellipse()函数。

我有起始鼠标坐标 - x1和y1以及结束坐标x2和y2。正如您所看到的,我强制y2(temp_shape.bottom) = y1 +(x2-x1)。这并没有按预期工作。我知道计算完全错误,但有什么正确的想法吗?

以下是代码。

case WM_PAINT:
        {

            hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code here...
            RECT rect;
            GetClientRect(hWnd, &rect);

            HDC backbuffDC = CreateCompatibleDC(hdc);

            HBITMAP backbuffer = CreateCompatibleBitmap( hdc, rect.right, rect.bottom);

            int savedDC = SaveDC(backbuffDC);
            SelectObject( backbuffDC, backbuffer );
            HBRUSH hBrush = CreateSolidBrush(RGB(255,255,255));
            FillRect(backbuffDC,&rect,hBrush);
            DeleteObject(hBrush);



            //Brush and Pen colours
            SelectObject(backbuffDC, GetStockObject(DC_BRUSH));
            SetDCBrushColor(backbuffDC, RGB(255,0,0));
            SelectObject(backbuffDC, GetStockObject(DC_PEN));
            SetDCPenColor(backbuffDC, RGB(0,0,0));



            //Shape Coordinates
            temp_shape.left=x1;
            temp_shape.top=y1;
            temp_shape.right=x2;
            temp_shape.bottom=y2;



            //Draw Old Shapes
            //Rectangles
            for ( int i = 0; i < current_rect_count; i++ )
            {
                Rectangle(backbuffDC, rect_list[i].left, rect_list[i].top, rect_list[i].right, rect_list[i].bottom);
            }
            //Ellipses
            for ( int i = 0; i < current_ellipse_count; i++ )
            {
                Ellipse(backbuffDC, ellipse_list[i].left, ellipse_list[i].top, ellipse_list[i].right, ellipse_list[i].bottom);
            }

            if(mouse_down)
            {
                if(drawCircle)
                {

                    temp_shape.right=y1+(x2-x1);

                    Ellipse(backbuffDC, temp_shape.left, temp_shape.top, temp_shape.right, temp_shape.bottom);
                }

                if(drawRect)
                {
                    Rectangle(backbuffDC, temp_shape.left, temp_shape.top, temp_shape.right, temp_shape.bottom);
                }

                if(drawEllipse)
                {
                    Ellipse(backbuffDC, temp_shape.left, temp_shape.top, temp_shape.right, temp_shape.bottom);
                }
            }

            BitBlt(hdc,0,0,rect.right,rect.bottom,backbuffDC,0,0,SRCCOPY);
            RestoreDC(backbuffDC,savedDC);

            DeleteObject(backbuffer);
            DeleteDC(backbuffDC);
            EndPaint(hWnd, &ps);
        }
        break;

1
你能详细说明一下“不按预期工作”的问题吗? - chris
它没有画出一个正确的圆形。 - user1788175
@user1788175:它画了什么? - AnT stands with Russia
@AndreyT 一个椭圆形。编辑 - 在Remy的回答之后现在绘制一个圆,但功能有限。(见下文) - user1788175
3个回答

2

如果你希望Ellipse()画出一个完美的圆形,你需要给它一个完美正方形的坐标,而不是长方形的坐标。

假设x1,y1是拖动的起始坐标,x2,y2是当前鼠标的坐标,则可以尝试以下代码:

//Shape Coordinates
temp_shape.left = min(x1, x2);
temp_shape.top = min(y1, y2);
temp_shape.right = max(x1, x2);
temp_shape.bottom = max(y1, y2);

...

if (drawCircle)
{
    int length = min(abs(x2-x1), abs(y2-y1));

    if (x2 < x1)
        temp_shape.left = temp_shape.right - length;
    else
        temp_shape.right = temp_shape.left + length;

    if (y2 < y1)
        temp_shape.top = temp_shape.bottom - length;
    else
        temp_shape.bottom = temp_shape.top + length;

    Ellipse(backbuffDC, temp_shape.left, temp_shape.top, temp_shape.right, temp_shape.bottom);
}

谢谢,这个可以用,但是如果鼠标从左下到右上或者从右上到左下拖动就不行了。这和正负有关系吗? - user1788175
您需要跟踪拖动的起始坐标,以便确定相对于temp_shape哪个角落需要调整绘制坐标。 - Remy Lebeau
我已经添加了一个性能更好的答案。谢谢Remy。 - user1788175

2
我已经想出了更好的计算方法。以下是粘贴的内容,供其他需要的人使用。
if(drawSquare)
                {

                    int xdiff = abs(x2-x1);
                    int ydiff=abs(y2-y1);

                    if(xdiff>ydiff)
                    {
                        if(y2>y1)
                            temp_shape.bottom=y1+xdiff;
                        else
                            temp_shape.bottom=y1-xdiff;
                    }
                    else
                    {
                        if(x2>x1)
                            temp_shape.right=x1+ydiff;
                        else
                            temp_shape.right=x1-ydiff;
                    }


                    Rectangle(backbuffDC, temp_shape.left, temp_shape.top, temp_shape.right, temp_shape.bottom);
                }

-2

你的代码不必要地复杂,有临时DC和后备缓冲区,并且在每个WM_PAINT中重新创建GDI画笔?但这并不是重点。问题是:你为什么要这样做:

temp_shape.right=y1+(x2-x1);  //basing horizontal coordinate on vertical?

这个框架堆叠在哪个上面?.NET,那为什么不使用内置的双缓冲?

谢谢,抱歉这个问题有些复杂。我不允许使用内置的双缓冲。我想在那里需要进行一些计算才能得到一个合适的圆形,我正在计算这个过程中。这是其中的一个尝试。 - user1788175

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接