VC++简单画图:Win32 GDI原生绘图最小可行路径
简介这是一份面向C初学者与Windows图形编程入门者的VC绘图实践项目聚焦GDI基础绘图能力训练帮助开发者掌握直线、圆形、正方形等基本图形的鼠标交互式绘制、颜色/线宽/填充控制以及BMP图像的保存与加载功能。资源包共24个文件涵盖7个头文件如mspainDlg.h、CanvasWnd.h、ShapeLayer.h定义界面逻辑与图形图层、5个源文件cpp实现GDI绘图核心逻辑与消息响应、1个Visual Studio解决方案.sln及配套工程配置.vcxproj、.filters、.manifest、资源文件.rc、.ico、.rc2和可执行程序bin/mspain.exe完整呈现MFC框架下轻量级绘图软件的工程结构。压缩包大小为1.35MB格式为RAR结构清晰、模块职责分明便于逐层理解窗口管理、设备上下文操作、图形状态维护与文件I/O实现。目前已有329人学习下载适合用于课程设计参考、MFC实战练习或GDI绘图原理教学演示。1. VC简单画图不是学MFC古董而是掌握Windows图形底层的最小可行路径“VC简单画图”这个标题常被初学者当成“用Visual C写个窗口画几条线”的入门练习但实际踩过坑的人才知道它本质是Windows GDI编程的微型入口——不依赖MFC封装、不绕道Qt或Direct2D直面HDC、WM_PAINT、BeginPaint/EndPaint这一套三十年未变的图形契约。某高校嵌入式方向课程曾用它带学生理解“为什么Win32窗口要手动处理重绘”某工业控制界面Demo也靠它在无UI框架环境下快速验证传感器数据可视化逻辑。它解决的不是“怎么画得美”而是“怎么让像素在指定时刻、指定位置、按指定规则稳定出现”。适合三类人刚脱离控制台想摸Windows原生API的C新手需要轻量级图形调试能力的嵌入式/驱动开发者以及想反向理解现代UI框架底层调度逻辑的进阶者。别被“简单”二字骗了——GDI里没有自动内存管理没有事件绑定语法糖一个忘记ReleaseDC就能让程序在多屏环境下静默卡死。下面我们就从零搭起这个“最简但最真实”的画图环境。2. 用纯Win32 API搭建画图窗口不碰MFC、不装第三方库的最小可运行骨架2.1 创建标准Win32窗口并注册自定义绘图消息循环VC简单画图的第一步永远不是调用LineTo()而是让系统知道“这个窗口需要自己画”。这意味着必须显式处理WM_PAINT消息并在其中获取设备上下文HDC。以下是最小化代码骨架已剔除所有MFC宏和ATL辅助// main.cpp - 编译时需链接 user32.lib 和 gdi32.lib #include windows.h LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { const char CLASS_NAME[] SimpleDrawClass; WNDCLASS wc {}; wc.lpfnWndProc WndProc; wc.hInstance hInstance; wc.lpszClassName CLASS_NAME; wc.hCursor LoadCursor(NULL, IDC_ARROW); wc.hbrBackground (HBRUSH)(COLOR_WINDOW1); RegisterClass(wc); HWND hwnd CreateWindowEx( 0, // 扩展样式 CLASS_NAME, // 窗口类名 VC简单画图 - 原生GDI示例, // 窗口标题 WS_OVERLAPPEDWINDOW, // 样式 CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, // 位置与尺寸 NULL, NULL, hInstance, NULL); if (hwnd NULL) { return 0; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); MSG msg {}; while (GetMessage(msg, NULL, 0, 0)) { TranslateMessage(msg); DispatchMessage(msg); } return (int) msg.wParam; }提示这段代码不依赖任何.rc资源文件或MFC向导生成的框架WinMain是Win32 GUI程序真正的入口点。WS_OVERLAPPEDWINDOW确保窗口有标题栏、边框和系统菜单避免因样式缺失导致WM_PAINT无法触发。2.2 在WM_PAINT中实现双缓冲绘图告别闪烁的硬核写法直接在BeginPaint()返回的HDC上绘图会导致严重闪烁——因为每次重绘都直接刷到屏幕而窗口大小变化、AltTab切换等操作会频繁触发WM_PAINT。VC简单画图必须引入双缓冲Double Buffering其核心是先在内存位图HBITMAP上绘制再一次性BitBlt到屏幕。这是GDI时代对抗闪烁的唯一可靠方案LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static HDC hdcMem NULL; static HBITMAP hbmMem NULL; static int cxClient 0, cyClient 0; switch (msg) { case WM_SIZE: { cxClient LOWORD(lParam); cyClient HIWORD(lParam); // 释放旧缓冲区 if (hdcMem) DeleteDC(hdcMem); if (hbmMem) DeleteObject(hbmMem); // 创建新内存DC和位图 hdcMem CreateCompatibleDC(NULL); hbmMem CreateCompatibleBitmap(GetDC(hwnd), cxClient, cyClient); SelectObject(hdcMem, hbmMem); break; } case WM_PAINT: { PAINTSTRUCT ps; HDC hdc BeginPaint(hwnd, ps); // 清空内存DC背景关键否则残留旧内容 RECT rect {0, 0, cxClient, cyClient}; FillRect(hdcMem, rect, (HBRUSH)(COLOR_WINDOW1)); // 在内存DC上绘图此处为示例画坐标轴和折线 HPEN hPen CreatePen(PS_SOLID, 2, RGB(0, 0, 255)); SelectObject(hdcMem, hPen); MoveToEx(hdcMem, 50, 50, NULL); LineTo(hdcMem, 50, cyClient-50); // Y轴 LineTo(hdcMem, cxClient-50, cyClient-50); // X轴 DeleteObject(hPen); // 一次性拷贝到屏幕 BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY); EndPaint(hwnd, ps); break; } case WM_DESTROY: if (hdcMem) DeleteDC(hdcMem); if (hbmMem) DeleteObject(hbmMem); PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; }参数说明CreateCompatibleDC(NULL)创建与屏幕兼容的内存DC避免颜色失真CreateCompatibleBitmap()位图尺寸必须与客户区一致否则BitBlt会拉伸或裁剪FillRect()必须在每次WM_PAINT开头执行否则内存位图残留上次绘图内容SRCCOPY是BitBlt最关键的光栅操作码表示“源像素直接覆盖目标”不可替换为SRCAND等混合模式。这段代码实现了VC简单画图的“呼吸感”——窗口缩放时线条平滑重绘AltTab切回后内容完整这才是生产级GDI绘图的起点。3. 实现交互式画图鼠标轨迹捕获与实时橡皮筋效果3.1 捕获鼠标按下、移动、释放事件并记录坐标序列VC简单画图若仅静态绘图就失去了“画图”二字的灵魂。真正的交互始于WM_LBUTTONDOWN、WM_MOUSEMOVE和WM_LBUTTONUP三个消息。关键在于必须调用SetCapture()锁定鼠标输入否则当鼠标快速移出窗口时WM_MOUSEMOVE会丢失导致画线断开// 全局变量实际项目中应封装进窗口类或结构体 static bool bDrawing false; static POINT ptStart {0}, ptEnd {0}; static std::vectorPOINT linePoints; // 存储折线点集 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_LBUTTONDOWN: if (wParam MK_LBUTTON) { bDrawing true; ptStart.x GET_X_LPARAM(lParam); ptStart.y GET_Y_LPARAM(lParam); SetCapture(hwnd); // 锁定鼠标输入 } break; case WM_MOUSEMOVE: if (bDrawing (wParam MK_LBUTTON)) { ptEnd.x GET_X_LPARAM(lParam); ptEnd.y GET_Y_LPARAM(lParam); InvalidateRect(hwnd, NULL, FALSE); // 触发重绘实现橡皮筋 } break; case WM_LBUTTONUP: if (bDrawing) { bDrawing false; ReleaseCapture(); // 释放鼠标捕获 linePoints.push_back(ptStart); linePoints.push_back(ptEnd); ptStart ptEnd {0}; // 重置 InvalidateRect(hwnd, NULL, TRUE); // 强制全窗口重绘 } break; // ... 其他消息处理 } return DefWindowProc(hwnd, msg, wParam, lParam); }逻辑说明GET_X_LPARAM/GET_Y_LPARAM是从lParam中安全提取坐标的宏比强制类型转换更健壮InvalidateRect(hwnd, NULL, FALSE)中的FALSE参数表示“不擦除背景”避免重绘时闪烁linePoints使用std::vector存储点序列为后续支持多段线、撤销功能预留扩展点SetCapture()和ReleaseCapture()必须成对出现否则窗口将永久劫持鼠标影响系统其他操作。3.2 在WM_PAINT中渲染动态橡皮筋线与历史折线橡皮筋Rubber Band效果的本质是在鼠标拖拽过程中实时绘制一条从起点到当前鼠标的临时线。这要求WM_PAINT能区分“历史固定图形”和“当前动态线”。我们通过在WM_PAINT中增加条件分支实现case WM_PAINT: { PAINTSTRUCT ps; HDC hdc BeginPaint(hwnd, ps); // 绘制内存缓冲区同前 if (hdcMem hbmMem) { FillRect(hdcMem, rect, (HBRUSH)(COLOR_WINDOW1)); // 1. 绘制历史折线linePoints中所有点 if (!linePoints.empty()) { HPEN hPen CreatePen(PS_SOLID, 2, RGB(255, 0, 0)); SelectObject(hdcMem, hPen); Polyline(hdcMem, linePoints.data(), (DWORD)linePoints.size()); DeleteObject(hPen); } // 2. 绘制橡皮筋线仅当正在拖拽时 if (bDrawing) { HPEN hPenDash CreatePen(PS_DASH, 1, RGB(0, 128, 0)); SelectObject(hdcMem, hPenDash); MoveToEx(hdcMem, ptStart.x, ptStart.y, NULL); LineTo(hdcMem, ptEnd.x, ptEnd.y); DeleteObject(hPenDash); } } BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY); EndPaint(hwnd, ps); break; }参数说明PS_DASH样式画笔用于橡皮筋线视觉上明确区分于固定图形Polyline()一次性绘制多段线比循环调用LineTo()效率更高且无连接点偏移linePoints.data()直接传递std::vector内部数组指针避免额外拷贝橡皮筋线不存入linePoints仅在WM_PAINT中临时绘制保证逻辑清晰。此时运行程序点击拖拽即可看到绿色虚线随鼠标移动松手后变为红色实线——VC简单画图已具备基础交互能力。4. 避坑指南VC简单画图中90%新手栽倒的5个硬核陷阱4.1 现象窗口最大化后绘图区域错位线条只出现在左上角四分之一区域原因WM_SIZE消息中未正确更新cxClient/cyClient或CreateCompatibleBitmap()传入了错误尺寸如用了GetSystemMetrics(SM_CXSCREEN)代替客户区宽高。GDI绘图坐标系以客户区左上角为原点若位图尺寸小于客户区BitBlt会自动缩放导致变形。解决严格在WM_SIZE中用LOWORD(lParam)和HIWORD(lParam)获取客户区尺寸并立即重建内存位图。添加断点验证cxClient/cyClient值是否与窗口实际像素一致。4.2 现象鼠标快速拖拽时橡皮筋线断裂出现多段不连续虚线原因未调用SetCapture()导致WM_MOUSEMOVE消息在鼠标移出窗口时停止发送或InvalidateRect()调用过于频繁引发重绘队列堆积WM_PAINT来不及处理所有中间状态。解决必须在WM_LBUTTONDOWN中调用SetCapture(hwnd)并在WM_LBUTTONUP中调用ReleaseCapture()将InvalidateRect()改为InvalidateRect(hwnd, NULL, FALSE)禁用背景擦除以降低重绘开销。4.3 现象程序退出时崩溃报错0xC0000005: Access violation原因WM_DESTROY中未释放hdcMem和hbmMem或在WM_PAINT中重复DeleteObject()已删除的GDI对象。GDI对象句柄是全局资源泄漏后系统句柄数耗尽会导致后续CreateCompatibleDC失败。解决在WM_DESTROY中严格配对释放且确保hdcMem/hbmMem为非NULL才调用DeleteDC/DeleteObject所有Create*函数后立即检查返回值如if (!hbmMem) return;。4.4 现象在高DPI显示器上图形模糊、文字锯齿坐标计算完全错乱原因Win32默认以96 DPI100%缩放为基准未声明DPI感知。Windows会自动对窗口进行位图缩放导致GDI绘图坐标被错误映射。解决在main.cpp顶部添加DPI感知声明并在WinMain开头调用SetProcessDpiAwarenessContext#include shellscalingapi.h #pragma comment(lib, shcore.lib) int WINAPI WinMain(...) { SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); // ... 后续代码 }同时在WM_PAINT中用GetDpiForWindow(hwnd)获取当前DPI并对坐标做缩放补偿如pt.x * dpi / 96。4.5 现象画直线时端点偏移1像素多段线连接处出现明显缺口原因GDI默认启用“端点对齐”Endpoint Alignment在奇数像素宽度画笔下线条中心落在像素边界而非中心导致视觉偏移。解决在绘图前调用SetGraphicsMode(hdcMem, GM_ADVANCED)启用高级图形模式再用SetWorldTransform()设置单位矩阵消除累积误差或统一使用偶数宽度画笔如CreatePen(PS_SOLID, 2, ...)避免奇数宽度引发的半像素偏移。5. 进阶技巧用GDI扩展VC简单画图的矢量能力与抗锯齿5.1 无缝集成GDI在纯Win32窗口中启用抗锯齿文本与贝塞尔曲线VC简单画图若止步于GDI会受限于位图缩放失真和无原生抗锯齿。GDI作为GDI的超集无需MFC即可直接注入Win32窗口且保持同一消息循环。关键步骤初始化GDI、在WM_PAINT中用Graphics对象替代HDC、最后清理资源。// 全局变量 static Gdiplus::GdiplusStartupInput gdiplusStartupInput; static ULONG_PTR gdiplusToken; static Gdiplus::Graphics* pGraphics nullptr; // WinMain开头初始化GDI Gdiplus::GdiplusStartup(gdiplusToken, gdiplusStartupInput, NULL); // WndProc中WM_PAINT处理替换原GDI绘图部分 case WM_PAINT: { PAINTSTRUCT ps; HDC hdc BeginPaint(hwnd, ps); if (!pGraphics) { pGraphics Gdiplus::Graphics::FromHDC(hdc); pGraphics-SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); // 抗锯齿 pGraphics-SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic); } // 使用GDI绘制示例抗锯齿贝塞尔曲线 Gdiplus::Point points[] { Gdiplus::Point(100, 100), Gdiplus::Point(200, 50), Gdiplus::Point(300, 150), Gdiplus::Point(400, 100) }; Gdiplus::Pen pen(Gdiplus::Color(255, 0, 0, 255), 2.0f); pGraphics-DrawBezier(pen, points[0], points[1], points[2], points[3]); // 绘制抗锯齿文本 Gdiplus::Font font(LMicrosoft YaHei, 12.0f); Gdiplus::SolidBrush brush(Gdiplus::Color(0, 0, 0)); pGraphics-DrawString(LVC简单画图 - GDI增强版, -1, font, Gdiplus::PointF(10, 10), brush); EndPaint(hwnd, ps); break; } // WM_DESTROY中清理 case WM_DESTROY: if (pGraphics) { delete pGraphics; pGraphics nullptr; } Gdiplus::GdiplusShutdown(gdiplusToken); PostQuitMessage(0); break;参数说明SmoothingModeAntiAlias开启路径抗锯齿对曲线和斜线效果显著InterpolationModeHighQualityBicubic提升图像缩放质量避免StretchBlt模糊DrawString()支持Unicode中文显示无乱码且字体平滑度远超GDI的TextOutDrawBezier()用4个点定义三次贝塞尔曲线比GDI的PolyBezier更易控制曲率。此方案让VC简单画图突破GDI瓶颈却仍保持Win32原生轻量——无需链接MFC库不增加安装包体积编译后EXE仅300KB左右。5.2 实现撤销/重做栈用std::vector管理绘图操作的历史快照真正的画图工具必须支持撤销。GDI本身无状态快照机制但我们可以为每次用户操作如画一条线保存其参数重绘时回放。这里采用“命令模式”简化实现struct DrawCommand { enum Type { LINE, BEZIER, TEXT } type; std::vectorPOINT points; std::wstring text; Gdiplus::RectF textRect; COLORREF color; float width; }; static std::vectorDrawCommand commandHistory; static size_t historyIndex 0; // 当前有效命令数 // 用户画线时调用 void AddLineCommand(const POINT start, const POINT end, COLORREF clr RGB(0,0,255)) { DrawCommand cmd{DrawCommand::LINE, {start, end}, L, {}, clr, 2.0f}; if (historyIndex commandHistory.size()) { commandHistory.erase(commandHistory.begin() historyIndex, commandHistory.end()); } commandHistory.push_back(cmd); historyIndex; } // WM_PAINT中回放所有命令 if (pGraphics !commandHistory.empty()) { for (size_t i 0; i historyIndex; i) { const auto cmd commandHistory[i]; Gdiplus::Pen pen(Gdiplus::Color(255, GetRValue(cmd.color), GetGValue(cmd.color), GetBValue(cmd.color)), cmd.width); switch (cmd.type) { case DrawCommand::LINE: if (cmd.points.size() 2) { Gdiplus::Point pts[2] { Gdiplus::Point(cmd.points[0].x, cmd.points[0].y), Gdiplus::Point(cmd.points[1].x, cmd.points[1].y) }; pGraphics-DrawLine(pen, pts[0], pts[1]); } break; // ... 其他类型处理 } } }技巧价值此撤销栈不保存位图快照内存爆炸只存参数1000次操作内存占用不足1MB支持无限步撤销且与GDI/GDI绘图解耦未来切换渲染引擎无需重构历史逻辑。我一般会在AddLineCommand中加入时间戳和操作ID方便调试时定位哪次点击触发了异常重绘。VC简单画图走到这一步早已不是教科书里的玩具demo——它是Windows图形编程的锚点是理解现代UI框架如何封装HDC与WM_PAINT的活体标本。我坚持在每个新项目初期用它验证图形链路因为只要这段代码能跑通就意味着你的开发环境、DPI设置、GDI资源管理全部在线。那些看似“过时”的BeginPaint/EndPaint配对恰恰是Windows三十年图形稳定性的基石。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

ZYT-World:用条件扩散实现自动驾驶世界模型的时空一致性重访

ZYT-World:用条件扩散实现自动驾驶世界模型的时空一致性重访

1. 项目概述:当世界模型开始记住“这条路我来过”最近在自动驾驶算法圈里,一个叫ZYT-World的模型名字频繁跳出来,不是因为又堆了多大的参数量,而是因为它干了一件过去世界模型几乎不干的事——它开始“认路”了。你没看错&#xf…

2026/10/15 13:17:50 阅读更多 →
VS2015 MSVC编译器实战:v140工具链与命令行构建避坑指南

VS2015 MSVC编译器实战:v140工具链与命令行构建避坑指南

简介:VS2015 MSVC 编译器便携版是一套免安装的 C 开发工具集,面向需要在 Windows 平台编译原生应用的开发者,尤其适合无管理员权限、需频繁切换开发环境的场景。解压后可直接调用 cl、nmake 等命令行工具,配合头文件、导入库完成从…

2026/10/15 13:17:50 阅读更多 →
CoconutKit动态本地化实战:一个方法调用切换App语言,IB内零代码翻译

CoconutKit动态本地化实战:一个方法调用切换App语言,IB内零代码翻译

移动开发开发工具 【免费下载链接】CoconutKit CoconutKit is a productivity framework for iOS, crafted with love and focusing on ease of use 项目地址: https://gitcode.com/gh_mirrors/co/CoconutKit 点击查看 免费下载 CoconutKit 是一款注重易用性的 iOS…

2026/10/15 13:17:50 阅读更多 →

最新新闻

S变换在配电网混合线路故障选线中的应用

S变换在配电网混合线路故障选线中的应用

1. 项目背景与核心价值在配电网系统中,电缆-架空线混合线路的故障选线一直是困扰运维人员的难题。传统基于工频量的选线方法在面对高阻接地、间歇性电弧等复杂故障时,往往会出现误判。而S变换作为一种时频分析工具,能够同时保留信号的时间与频…

2026/10/15 13:58:46 阅读更多 →
基于S变换的配电网混合线路故障选线方法

基于S变换的配电网混合线路故障选线方法

1. 项目背景与核心价值在配电网系统中,电缆-架空线混合线路的故障选线一直是个棘手问题。传统基于工频量的选线方法在面对这类混合线路时,往往会因为线路参数差异大、故障特征复杂而失效。我在某地区电网的实际运维中就遇到过这样的案例:一条…

2026/10/15 13:58:46 阅读更多 →
1688图片搜索API技术内幕:从特征提取到向量匹配的工程实现

1688图片搜索API技术内幕:从特征提取到向量匹配的工程实现

图片搜索这件事,表面上看是"传一张图,返回一堆相似商品",但真正落到工程实现上,它是一条从像素到向量的完整流水线。1688的图片搜索API背后,核心要解决的是"如何让机器理解一张商品图里到底有什么&…

2026/10/15 13:58:46 阅读更多 →
乱抛垃圾行为识别监测系统

乱抛垃圾行为识别监测系统

城市公共街道、小区园区、公园广场、环卫责任片区、垃圾桶周边等公共区域,是市容环境治理与文明城市建设的核心场景。日常公共环境管理中,市民随手乱扔纸屑、果皮、包装袋、废弃杂物,垃圾桶旁乱堆乱放垃圾等不文明行为屡禁不止,不…

2026/10/15 13:58:46 阅读更多 →
AI辅助开发App全流程:从技术选型到上架发布的个人开发者实战指南

AI辅助开发App全流程:从技术选型到上架发布的个人开发者实战指南

1. 从零到一:AI辅助开发一款App的整体思路拆解1.1 为什么现在个人开发者也能独立完成App放在五年前,一个没有移动端经验的后端程序员想独立做出一款能上架的App,基本等于痴人说梦。UI设计、原生开发、后端接口、应用商店审核,每一…

2026/10/15 13:58:46 阅读更多 →
微信小程序预约挂号系统:号源并发扣减与排班逻辑实战

微信小程序预约挂号系统:号源并发扣减与排班逻辑实战

简介:这份资源是面向计算机专业毕业设计场景的微信小程序预约挂号系统完整论文资料,适合正在准备毕设选题、需要参考系统分析与设计写作范式的学生,以及希望了解SSM框架与微信小程序结合开发思路的开发者。压缩包共1个doc文件,约2…

2026/10/15 13:57:45 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →