【问题标题】:Drawing rectangle in c++ using functions使用函数在 C++ 中绘制矩形
【发布时间】:2015-03-08 09:57:13
【问题描述】:

我在 C++ 中创建绘图矩形函数时遇到问题。我已经准备好c++文件,当我必须完成绘图功能时。

我需要添加功能,在鼠标单击时它将创建矩形,当我完成移动鼠标并释放时,它应该是矩形。接下来应该再次创建它并更改位置。

我完全不知道该怎么做。有任何想法吗 ?代码如下所示:

MsgHandlers.cpp(所有事情都在这里发生):

#include "MsgHandlers.h"
#include "Utils.h"
#include <time.h>
#include <math.h>



int ClientWidth, ClientHeight;
BOOL EraseBkgnd = TRUE;
bool IgnoreTimer = false;
RECT Rect;



void OnCreate(HWND hwnd)
{
    SetTimer(hwnd, 1, 25, NULL);
}



void OnSize(HWND hwnd, int width, int height, WPARAM wParam)
{
    ClientWidth = width;
    ClientHeight = height;

Rect.left = width/4;
Rect.right=Rect.left + width/2;
Rect.top = height/4;
Rect.bottom= Rect.top + height/2;
}





void OnTimer(HWND hwnd, WPARAM timerID)
{


if(IgnoreTimer) return;
Rect.left+=RandRange(-10, 10);
Rect.right +=RandRange(-10,10);
Rect.top +=RandRange(-10,10);
Rect.bottom +=RandRange(-10,10);

InvalidateRect(hwnd, NULL, EraseBkgnd);


}



void OnPaint(HWND hwnd, HDC hdc)
{


  Rectangle(hdc,Rect.left,Rect.top,Rect.right,Rect.bottom);


}



void OnKeyDown(HWND hwnd, WPARAM keyCode)
{
    switch (keyCode)
    {
    case VK_LEFT:
        break;
    case VK_UP:
        break;
    case VK_RIGHT:
        break;
    case VK_DOWN:
        break;
    case 0x43: // C
        break;
    case 0x45: // E
        EraseBkgnd ^= 0x00000001;
        break;
    case 0x52: // R
        break;
    case 0x49: //  I
    IgnoreTimer = !IgnoreTimer;
    case 0x53: // S
        break;
    }
    //InvalidateRect(hwnd, NULL, EraseBkgnd);
}



void OnMouseMove(HWND hwnd, int x, int y, WPARAM wParam)
{

}



void OnLButtonDown(HWND hwnd, int x, int y, WPARAM wParam)
{

}



void OnLButtonUp(HWND hwnd, int x, int y, WPARAM wParam)
{

}



void OnDestroy(HWND hwnd)
{
    KillTimer(hwnd, 1);
}

我还放了这个 C++ 项目中的其他文件:

主要:

#include <windows.h>
#include "MsgHandlers.h"


/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "CodeBlocksWindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG message;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               "Progr.",       /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               1024,                 /* The programs width */
               768,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* No menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage(&message, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&message);
        /* Send message to WindowProcedure */
        DispatchMessage(&message);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return message.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;


    switch (message)                  /* handle the messages */
    {
    case WM_CREATE:
        OnCreate(hwnd);
        break;
    case WM_SIZE:
        OnSize(hwnd, short(lParam & 0x0000FFFF), short(lParam >> 16), wParam);
        break;
    case WM_TIMER:
        OnTimer(hwnd, wParam);
        break;
    case WM_KEYDOWN:
        OnKeyDown(hwnd, wParam);
        break;
    case WM_LBUTTONDOWN:
        OnLButtonDown(hwnd, short(lParam & 0x0000FFFF), short(lParam >> 16), wParam);
        break;
    case WM_MOUSEMOVE:
        OnMouseMove(hwnd, short(lParam & 0x0000FFFF), short(lParam >> 16), wParam);
        break;
    case WM_LBUTTONUP:
        OnLButtonUp(hwnd, short(lParam & 0x0000FFFF), short(lParam >> 16), wParam);
        break;
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        OnPaint(hwnd, hdc);
        EndPaint(hwnd, &ps);
        break;
    case WM_DESTROY:
        OnDestroy(hwnd);
        PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
        break;
    default:                      /* for messages that we don't deal with */
        return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

Utils.cpp:

#include "Utils.h"
#include <math.h>

//random <min, max>
int RandRange(int min, int max)
{
    return min + rand() % (1 + max - min);
}

//Return -1 for negative argument; 
//return +1 for positive argument or 0

int Sign(int arg)
{
    return arg < 0 ? -1 : 1;
}

double Deg2Rad(double aDegrees)
{
    return aDegrees * PI / 180.0;
}

double Rad2Deg(double aRadians)
{
    return aRadians * 180 / PI;
}

float DirectionFromSpeedXY(int aSpeedX, int aSpeedY)
{
    if(aSpeedX==0 && aSpeedY==0)
        return 0;
    else
        return atan2(aSpeedX, -aSpeedY);
}

float SpeedFromSpeedXY(int aSpeedX, int aSpeedY)
{
    return sqrt(aSpeedX*aSpeedX + aSpeedY*aSpeedY);// * Sign(aSpeedX*aSpeedY);
}

void SpeedXYFromSpeedDirection(float aSpeed, float aDirection, int *aSpeedX, int *aSpeedY)
{
    aSpeed = abs(aSpeed);
    *aSpeedX = aSpeed * sin(aDirection);
    *aSpeedY = -aSpeed * cos(aDirection);
}

void CorrectRect(RECT *aRect)
{
    int temp;

    if(aRect->right < aRect->left)
    {
        temp = aRect->right;
        aRect->right = aRect->left;
        aRect->left = temp;
    }

    if(aRect->bottom < aRect->top)
    {
        temp = aRect->bottom;
        aRect->bottom = aRect->top;
        aRect->top = temp;
    }
}

【问题讨论】:

  • 您为什么拒绝编辑?您的代码中没有标准的 c++。如果不是原始 WinAPI,您实际使用的是什么图形框架?
  • 是的,你是对的它是 WinAPI。

标签: c++ function winapi drawing rectangles


【解决方案1】:

如前所述,您提供的代码不是标准的。 要完成您描述的任务,必须执行一些步骤。

如何画一个(简单的)矩形:

// x and y are the x- and y-locations of the mouse cursor upon release
void drawRectangle(HWND hwnd, const int x, const int y)
{
    // obtain a handle to the device context
    HDC hdc = GetDC(hwnd);

    // RECT_WIDTH and RECT_HEIGHT are elsewhere defined
    // draw rectangle
    Rectangle(hdc, x - RECT_WIDTH / 2, y - RECT_HEIGHT / 2, x + RECT_WIDTH / 2, y + RECT_HEIGHT / 2);

    // release the DC
    ReleaseDC(hwnd, hdc);
}

要捕获鼠标按钮释放,您需要处理 WM_LBUTTONUP 消息。 在窗口的窗口过程中:

LRESULT __stdcall wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int x;
    static int y;

    HDC hdc;
    PAINTSTRUCT ps;

    case WM_LBUTTONUP:
    {
        x = LOWORD(lParam); // grab the x-position
        y = HIWORD(lParam); // grab the y-position

        // invalidate the entire client area
        // this will cause the window's client area to be "cleared"
        // using the window class background brush upon BeginPaint call
        // in WM_PAINT
        InvalidateRect(hwnd, NULL, true);
        return 0;
    }

    case WM_PAINT:
    {
        hdc = BeginPaint(hwnd, &ps);

        // draw the rectangle
        drawRectangle(hwnd, x, y);

        EndPaint(hwnd, &ps);
        return 0;
    }

    // other case handlers like WM_DESTROY
}

显然,还有其他事情需要考虑,但这应该可以帮助您入门。

【讨论】:

  • drawRectangle 的第一个参数理想情况下应该是设备上下文。这允许重用渲染代码进行打印,或者如果您希望渲染到增强的元文件中(请参阅CreateEnhMetaFile)。
  • 是的,在这种情况下会更好。但是,我只是想展示一个“完整”的绘图功能。
  • 每个情况下传递设备上下文会更好。我不明白做正确的事情有什么不那么complete。您已经有一个设备上下文 - 适当的剪辑 - 来自您对 BeginPaint 的调用。
  • 你不必从 WM_PAINT 中绘制,我只是在这个例子中做了。
  • 如果您决定避开系统,并在WM_PAINT 之外执行渲染,则必须设置一个剪辑区域。您的代码中缺少此内容。即使您确实找到了从应用程序中的随机点进行渲染的正当理由,是什么阻止您在那里检索设备上下文并将其传递给drawRectangle?您将如何处理未来添加drawWombat 方法的需求?
猜你喜欢
  • 1970-01-01
  • 2018-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-26
  • 2020-04-07
  • 1970-01-01
  • 2014-01-13
相关资源
最近更新 更多