#include "framework.
h"
#include "De2.h"
#include <vector>
#include <commdlg.h>
#define MAX_LOADSTRING 100
HINSTANCE hInst;
WCHAR szTitle[MAX_LOADSTRING];
WCHAR szWindowClass[MAX_LOADSTRING];
// Danh sách lưu các điểm vẽ
std::vector<POINT> points;
COLORREF drawColor = RGB(0, 0, 0); // Màu mặc định là đen
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_DE2, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
if (!InitInstance(hInstance, nCmdShow)) return FALSE;
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DE2));
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex = { sizeof(WNDCLASSEX) };
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; // Enable double-clicks
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DE2));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_DE2);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance;
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
nullptr, nullptr, hInstance, nullptr);
if (!hWnd) return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
// Hàm chọn màu
void ChooseDrawingColor(HWND hWnd) {
CHOOSECOLOR cc = { sizeof(CHOOSECOLOR) };
static COLORREF acrCustClr[16];
cc.hwndOwner = hWnd;
cc.lpCustColors = acrCustClr;
cc.rgbResult = drawColor;
cc.Flags = CC_FULLOPEN | CC_RGBINIT;
if (ChooseColor(&cc)) {
drawColor = cc.rgbResult;
InvalidateRect(hWnd, NULL, TRUE);
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static std::vector<POINT> polylinePoints;
static bool drawPolyline = false;
switch (message)
{
case WM_LBUTTONDOWN: {
POINT pt = { LOWORD(lParam), HIWORD(lParam) };
points.push_back(pt);
// Vẽ điểm ngay tại vị trí nhấn chuột
HDC hdc = GetDC(hWnd);
SetPixel(hdc, pt.x, pt.y, drawColor);
// Vẽ thêm các pixel xung quanh để điểm trông rõ hơn
SetPixel(hdc, pt.x + 1, pt.y, drawColor);
SetPixel(hdc, pt.x - 1, pt.y, drawColor);
SetPixel(hdc, pt.x, pt.y + 1, drawColor);
SetPixel(hdc, pt.x, pt.y - 1, drawColor);
ReleaseDC(hWnd, hdc);
InvalidateRect(hWnd, NULL, FALSE);
break;
}
case WM_MOUSEMOVE: {
if (wParam & MK_LBUTTON) {
POINT pt = { LOWORD(lParam), HIWORD(lParam) };
points.push_back(pt);
InvalidateRect(hWnd, NULL, FALSE);
}
break;
}
case WM_LBUTTONUP: {
// Khi nhả chuột trái thì ngắt nét vẽ
points.push_back({ -1, -1 });
break;
}
case WM_LBUTTONDBLCLK: {
polylinePoints.clear();
// Lấy tất cả các điểm hợp lệ (không phải {-1, -1}) theo thứ tự nhấn
for (const auto& pt : points) {
if (pt.x != -1 && pt.y != -1) {
polylinePoints.push_back(pt);
}
}
if (polylinePoints.size() >= 2) {
drawPolyline = true;
InvalidateRect(hWnd, NULL, FALSE);
}
break;
}
case WM_RBUTTONDOWN: {
// Xóa miền thao tác
points.clear();
polylinePoints.clear();
drawPolyline = false;
InvalidateRect(hWnd, NULL, TRUE); // Xóa toàn bộ cửa sổ
break;
}
case WM_COMMAND: {
int wmId = LOWORD(wParam);
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case ID_FORMAT_COLOR:
ChooseDrawingColor(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HPEN hPen = CreatePen(PS_SOLID, 2, drawColor);
HGDIOBJ oldPen = SelectObject(hdc, hPen);
// Vẽ các đoạn và điểm người dùng đã vẽ
for (size_t i = 0; i < points.size(); ++i) {
if (points[i].x != -1 && points[i].y != -1) {
// Vẽ điểm
SetPixel(hdc, points[i].x, points[i].y, drawColor);
SetPixel(hdc, points[i].x + 1, points[i].y, drawColor);
SetPixel(hdc, points[i].x - 1, points[i].y, drawColor);
SetPixel(hdc, points[i].x, points[i].y + 1, drawColor);
SetPixel(hdc, points[i].x, points[i].y - 1, drawColor);
// Vẽ đường nếu không phải điểm cuối hoặc điểm ngắt
if (i < points.size() - 1 && points[i + 1].x != -1 && points[i +
1].y != -1) {
MoveToEx(hdc, points[i].x, points[i].y, NULL);
LineTo(hdc, points[i + 1].x, points[i + 1].y);
}
}
}
// Vẽ đường gấp khúc khi được double-click
if (drawPolyline && polylinePoints.size() >= 2) {
MoveToEx(hdc, polylinePoints[0].x, polylinePoints[0].y, NULL);
for (size_t i = 1; i < polylinePoints.size(); ++i) {
LineTo(hdc, polylinePoints[i].x, polylinePoints[i].y);
}
drawPolyline = false; // Vẽ xong thì tắt
}
SelectObject(hdc, oldPen);
DeleteObject(hPen);
EndPaint(hWnd, &ps);
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG: return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}