「IOCSコール」のグラフィックス機能を調べるために
プログラムを作ろうと考えています。そのため、まず Windows のコンソールからウィンドウに描画するプログラムを ChatGPT で作ってもらいました。
- Windows でコンソールアプリからウィンドウを作成して、コンソールからのコマンドでウィンドウに描画を行う C++ のサンプルを作ってください
- 以下のコマンドが使えるようにしてください(color は色番号またはRGBで指定するとします):
- clear color (全体を塗りつぶす)
- drawline x1 y1 x2 y2 color (線を描画する)
- drawstring s x y (文字列 s を描画する)
- drawrectangle x y width height color (四角形を描画する)
- drawellipse x y width height color (楕円を描画する)
- drawroundedrectangle x y width height radiusx radiusy color (角が丸い四角形を描画する)
- fillrectangle x y width height color (四角形を塗りつぶす)
- fillellipse x y width height color (楕円を塗りつぶす)
- fillroundedrectangle x y width height radiusx radiusy color (角が丸い四角形を塗りつぶす)
と入力すると、以下のようなサンプルを作ってくれました。
#include <windows.h> #include <thread> #include <iostream> #include <string> #include <queue> #include <sstream> #include <vector> #include <mutex> #define WM_USER_DRAW (WM_USER + 1) enum class DrawType { Clear, Line, String, Rect, Ellipse, RoundRect, FillRect, FillEllipse, FillRoundRect }; struct DrawCommand { DrawType type; COLORREF color; int x1, y1, x2, y2, w, h, rx, ry; std::wstring text; }; std::queue<DrawCommand> g_drawQueue; std::mutex g_queueMutex; HWND g_hWnd = nullptr; // 文字列を分割 std::vector<std::string> split(const std::string& str) { std::istringstream iss(str); std::vector<std::string> result; std::string s; while (iss >> s) result.push_back(s); return result; } // 色を解釈(整数 or R,G,B) COLORREF parseColor(const std::string& s) { if (s.find(',') != std::string::npos) { int r, g, b; sscanf_s(s.c_str(), "%d,%d,%d", &r, &g, &b); return RGB(r, g, b); } else { int c = std::stoi(s); return PALETTEINDEX(c); } } void enqueue(const DrawCommand& cmd) { std::lock_guard<std::mutex> lock(g_queueMutex); g_drawQueue.push(cmd); InvalidateRect(g_hWnd, nullptr, FALSE); } // ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); std::lock_guard<std::mutex> lock(g_queueMutex); while (!g_drawQueue.empty()) { const DrawCommand& cmd = g_drawQueue.front(); HPEN hPen = CreatePen(PS_SOLID, 1, cmd.color); HBRUSH hBrush = CreateSolidBrush(cmd.color); SelectObject(hdc, hPen); SelectObject(hdc, hBrush); switch (cmd.type) { case DrawType::Clear: FillRect(hdc, &ps.rcPaint, hBrush); break; case DrawType::Line: MoveToEx(hdc, cmd.x1, cmd.y1, nullptr); LineTo(hdc, cmd.x2, cmd.y2); break; case DrawType::String: TextOutW(hdc, cmd.x1, cmd.y1, cmd.text.c_str(), (int)cmd.text.length()); break; case DrawType::Rect: Rectangle(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h); break; case DrawType::Ellipse: Ellipse(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h); break; case DrawType::RoundRect: RoundRect(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h, cmd.rx, cmd.ry); break; case DrawType::FillRect: Rectangle(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h); break; case DrawType::FillEllipse: Ellipse(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h); break; case DrawType::FillRoundRect: RoundRect(hdc, cmd.x1, cmd.y1, cmd.x1 + cmd.w, cmd.y1 + cmd.h, cmd.rx, cmd.ry); break; } DeleteObject(hPen); DeleteObject(hBrush); g_drawQueue.pop(); } EndPaint(hwnd, &ps); return 0; } case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } // ウィンドウスレッド void WindowThread() { const wchar_t CLASS_NAME[] = L"MyDrawWindowClass"; WNDCLASS wc = {}; wc.lpfnWndProc = WndProc; wc.hInstance = GetModuleHandle(nullptr); wc.lpszClassName = CLASS_NAME; RegisterClass(&wc); g_hWnd = CreateWindowEx(0, CLASS_NAME, L"Drawing Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, nullptr, nullptr, wc.hInstance, nullptr); ShowWindow(g_hWnd, SW_SHOW); MSG msg; while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } // メイン関数 int main() { std::thread winThread(WindowThread); std::string line; std::cout << "Enter draw commands (type 'exit' to quit):\n"; while (std::getline(std::cin, line)) { if (line == "exit") { PostMessage(g_hWnd, WM_CLOSE, 0, 0); break; } auto tokens = split(line); if (tokens.empty()) continue; DrawCommand cmd = {}; try { if (tokens[0] == "clear" && tokens.size() == 2) { cmd.type = DrawType::Clear; cmd.color = parseColor(tokens[1]); } else if (tokens[0] == "drawline" && tokens.size() == 6) { cmd.type = DrawType::Line; cmd.x1 = std::stoi(tokens[1]); cmd.y1 = std::stoi(tokens[2]); cmd.x2 = std::stoi(tokens[3]); cmd.y2 = std::stoi(tokens[4]); cmd.color = parseColor(tokens[5]); } else if (tokens[0] == "drawstring" && tokens.size() >= 4) { cmd.type = DrawType::String; cmd.text = std::wstring(tokens[1].begin(), tokens[1].end()); cmd.x1 = std::stoi(tokens[2]); cmd.y1 = std::stoi(tokens[3]); cmd.color = RGB(0, 0, 0); // 固定色(必要に応じて拡張) } else if (tokens[0] == "drawrectangle" && tokens.size() == 6) { cmd.type = DrawType::Rect; cmd.x1 = std::stoi(tokens[1]); cmd.y1 = std::stoi(tokens[2]); cmd.w = std::stoi(tokens[3]); cmd.h = std::stoi(tokens[4]); cmd.color = parseColor(tokens[5]); } else if (tokens[0] == "drawellipse" && tokens.size() == 6) { cmd.type = DrawType::Ellipse; cmd.x1 = std::stoi(tokens[1]); cmd.y1 = std::stoi(tokens[2]); cmd.w = std::stoi(tokens[3]); cmd.h = std::stoi(tokens[4]); cmd.color = parseColor(tokens[5]); } else if (tokens[0] == "drawroundedrectangle" && tokens.size() == 8) { cmd.type = DrawType::RoundRect; cmd.x1 = std::stoi(tokens[1]); cmd.y1 = std::stoi(tokens[2]); cmd.w = std::stoi(tokens[3]); cmd.h = std::stoi(tokens[4]); cmd.rx = std::stoi(tokens[5]); cmd.ry = std::stoi(tokens[6]); cmd.color = parseColor(tokens[7]); } else if (tokens[0] == "fillrectangle" && tokens.size() == 6) { cmd.type = DrawType::FillRect; cmd.x1 = std::stoi(tokens[1]); cmd.y1 = std::stoi(tokens[2]); cmd.w = std::stoi(tokens[3]); cmd.h = std::stoi(tokens[4]); cmd.color = parseColor(tokens[5]); } else if (tokens[0] == "fillellipse" && tokens.size() == 6) { cmd.type = DrawType::FillEllipse; cmd.x1 = std::stoi(tokens[1]); cmd.y1 = std::stoi(tokens[2]); cmd.w = std::stoi(tokens[3]); cmd.h = std::stoi(tokens[4]); cmd.color = parseColor(tokens[5]); } else if (tokens[0] == "fillroundedrectangle" && tokens.size() == 8) { cmd.type = DrawType::FillRoundRect; cmd.x1 = std::stoi(tokens[1]); cmd.y1 = std::stoi(tokens[2]); cmd.w = std::stoi(tokens[3]); cmd.h = std::stoi(tokens[4]); cmd.rx = std::stoi(tokens[5]); cmd.ry = std::stoi(tokens[6]); cmd.color = parseColor(tokens[7]); } else { std::cout << "Unknown or malformed command.\n"; continue; } enqueue(cmd); } catch (...) { std::cout << "Error parsing command.\n"; } } winThread.join(); return 0; }




