在 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
应该是非常简单的。
我有以下内容:
程序开始运行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
应该是非常简单的。