在 windows 7 或更高版本中:如何在 C++ 中使用 GDI+ 在监视器上显示由线连接的点?

In windows 7 or higher: How to display points connected by lines on a monitor, in C++ using GDI+?

我有以下内容:

程序开始运行ning:

INPUT:从控制台 window,在 windows 7(或更高版本)中,程序要求用户输入整数,代表点:每个点的 y 和 x(二维坐标).

输出:然后使用这些点的程序应该在 window.

中显示(在监视器上)点本身以及连接这些点的线

程序停止运行ning

所有这些都是用 C++ 编写的,使用代码块和 GDI+。 我的问题是我似乎无法使用 GID+ 将控制台的输入连接到输出,甚至可能吗?

我是 c++ 新手,尤其是图形方面的新手,以前没有编程经验。 在网上环顾四周,除了令人惊讶的低质量和关于该主题的稀缺信息外,GDI+ 是我得出的解决方案。 我想要最简单的解决方案。有什么想法吗?

#include <abrazol.h>

using namespace std;

struct koordinata {
 int x;
 int y;
};


int main(){

vector<koordinata> abrazol;

abrazol = koordinataszamol(); //Ignore this, it calculates with 
//the coordinate points, asks the user for the x and y values
//of the points, returns a struct type (koordinata) of vector.


HDC hd;
int a=0;

for (int i=0; i<abrazol.size()-1; i++){

    Drawpoint(hd,abrazol[i]);
    Drawpoint(hd,abrazol[i+1]);
    OnPaint(hd,abrazol[i],abrazol[i+1]);
    a++;

}

    OnPaint(hd,abrazol[a+1],abrazol[0]);

return 0;

}

abrazol.cpp (h)

#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#include <stdio.h>
#include <iostream>
#include <koordinataszamol.h>


#pragma comment (lib,"Gdiplus.lib")


using namespace Gdiplus;

VOID OnPaint(HDC hdc, koordinata pont1, koordinata pont2)
{
   Graphics graphics(hdc);
   Pen      pen(Color(255, 0, 0, 255));
   graphics.DrawLine(&pen, pont1.x, pont1.y, pont2.x, pont2.y);


}

VOID Drawpoint(HDC hdc, koordinata pont){

    Graphics graphics(hdc);
    Pen blackPen(Color(255, 0, 0, 0), 3);
    int width = 2;
    int height = 2;
    graphics.DrawRectangle(&blackPen, pont.x-1, pont.y-1, width, height);

}





LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
   HWND                hWnd;
   MSG                 msg;
   WNDCLASS            wndClass;
   GdiplusStartupInput gdiplusStartupInput;
   ULONG_PTR           gdiplusToken;

   // Initialize GDI+.
   GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

   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  = TEXT("GettingStarted");

   RegisterClass(&wndClass);

   hWnd = CreateWindow(
      TEXT("GettingStarted"),   // window class name
      TEXT("Getting Started"),  // window caption
      WS_OVERLAPPEDWINDOW,      // window style
      CW_USEDEFAULT,            // initial x position
      CW_USEDEFAULT,            // initial y position
      CW_USEDEFAULT,            // initial x size
      CW_USEDEFAULT,            // initial y size
      NULL,                     // parent window handle
      NULL,                     // window menu handle
      hInstance,                // program instance handle
      NULL);                    // creation parameters

   ShowWindow(hWnd, iCmdShow);
   UpdateWindow(hWnd);

   while(GetMessage(&msg, NULL, 0, 0))
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }

   GdiplusShutdown(gdiplusToken);
   return msg.wParam;
}  // WinMain

LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
  WPARAM wParam, LPARAM lParam)
{
   HDC          hdc;
   PAINTSTRUCT  ps;
   switch(message)
   {
   case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      koordinata pont1;
      koordinata pont2;
      OnPaint(hdc,pont1,pont2);
      EndPaint(hWnd, &ps);
      return 0;
   case WM_DESTROY:
      PostQuitMessage(0);
      return 0;
   default:
      return DefWindowProc(hWnd, message, wParam, lParam);
   }
} // WndProc

我怀疑我不能修改OnPaint函数的参数,那么我应该如何从运行次参数中绘制???

我怀疑您在这种情况下使用 GDI+ 有什么好处。仅使用 GDI 绘图非常简单。

至于如何在不更改 OnPaint 参数的情况下更改绘图的基本问题,它通常非常简单:您决定将数据存储在某个位置。输入数据后,您将其存储在那里。 OnPaint 从那里检索数据,并将其绘制到屏幕上。

在这种情况下,您可能希望将其设为类似于 std::vector<point>,其中 point 是一种包含 x 和 y 坐标的类型。

我大致按照你的描述快速破解了一个程序,让你输入一些点,然后在 window 中绘制它们(使用 window class 我撒谎了处理大部分 window 创建、初始化等)。这是一些代码:

#include <iostream>
#include <string>
#include <vector>
#include <windows.h>

struct point {
    int x;
    int y;

    point() = default;
    point(int x, int y) : x(x), y(y) { }

    friend std::istream &operator>>(std::istream &is, point &p) {
        return is >> p.x >> p.y;
    }
};

struct Window {
    virtual void OnPaint(HDC) = 0;

    Window(std::string const &name) : hInstance(GetModuleHandle(NULL)) {      
        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 = name.c_str();
        RegisterClass(&wndClass);

        hWnd = CreateWindow(
            TEXT(name.c_str()),  
            TEXT(name.c_str()),  
            WS_OVERLAPPEDWINDOW, 
            CW_USEDEFAULT,       
            CW_USEDEFAULT,       
            CW_USEDEFAULT,       
            CW_USEDEFAULT,       
            NULL,                
            NULL,                
            hInstance,           
            (PVOID)this);               
    }

    WPARAM operator()() {
        MSG msg;

        ShowWindow(hWnd, SW_SHOWNORMAL);
        UpdateWindow(hWnd);

        while (GetMessage(&msg, NULL, 0, 0)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        return msg.wParam;
    }

private:

    HINSTANCE hInstance;
    HWND hWnd;
    WNDCLASS wndClass;

    static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
        HDC          hdc;
        PAINTSTRUCT  ps;
        static Window *w;

        switch (message) {
            case WM_CREATE:
                w = static_cast<Window *>(((CREATESTRUCT *)lParam)->lpCreateParams);
                break;
            case WM_PAINT:
                hdc = BeginPaint(hWnd, &ps);
                w->OnPaint(hdc);
                EndPaint(hWnd, &ps);
                return 0;
            case WM_DESTROY:
                PostQuitMessage(0);
                return 0;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }

};

class disp_window : public Window {
    std::vector<point> points;
public:
    disp_window(std::string const &t) : Window(t) { }

    virtual void OnPaint(HDC hDC) {
        if (points.empty())
            return;
        MoveToEx(hDC, points[0].x, points[0].y, nullptr);
        for (int i = 1; i < points.size(); i++)
            LineTo(hDC, points[i].x, points[i].y);
    }

    std::vector<point> &data() { return points; }
};

int main() {
    disp_window w("Getting Started");

    std::cout << "Please enter some points: ";
    point p;
    while (std::cin >> p)
        w.data().push_back(p);

    w();
}

使用 Visual C++,您可以像这样在命令行上编译它:

cl simple_win.cpp user32.lib kernel32.lib gdi32.lib

使用 MinGW,命令行如下所示:

g++ -std=c++11 simple_win.cpp -luser32 -l gdi32 -lkernel32

当你 运行 它时,它会打印出提示,然后你输入点数,数字之间用空格分隔(或制表符或回车):

Please enter some points: 1 1
100 100
100 200
200 300
^Z

(control-Z 只是让它知道输入已经结束)。

然后弹出一个window像这样:

我可能应该补充一点,这并不是真正最有效的做事方式——只是我在几分钟内拼凑出来的东西。例如,如果您要有很多点,您可能想要查找 PolyLine 而不是使用 MoveTo/LineTo。我也懒得包含在每个点绘制正方形(或其他任何东西)的代码——尽管将其添加到 disp_window::OnPaint 应该是非常简单的。