Qt嵌入式记事本源码实战:QWidget、SQLite与交叉编译部署

发布时间:2026/10/30 5:22:01
Qt嵌入式记事本源码实战:QWidget、SQLite与交叉编译部署 简介这份 Qt 记事本工程面向具备 C 基础、希望学习 Qt6 桌面与嵌入式 GUI 开发的读者也可作为课程设计或小型项目参考。项目以跨平台记事本为例涉及主窗口交互、文本编辑、文件读写与多编码兼容、界面布局和资源打包并兼顾嵌入式环境下的内存管理与性能优化思路。压缩包共 516 个文件以 475 个 idx 索引文件为主搭配 cpp/h 源码、ui/qrc 界面资源、pro/makefile 构建配置及 dll/a 库文件整体约 4.29MB工程结构相对完整。已有 778 人学习。读者可据此梳理 Qt6 工程的模块划分与信号槽协作方式复现可运行的记事本界面理解项目配置、资源编译和跨平台构建流程并参考编码处理与嵌入式资源取舍适合需要完整案例对照练习的开发者。1. 一块触摸屏和一份 Qt 嵌入式记事本源码先把使用边界说清一块带触摸屏的 ARM 板串口能通、屏幕能亮但系统里没有一个趁手的便签工具——这类场景最适合拿一份 Qt 嵌入式记事本源码包来练手。它不是一个桌面级笔记软件而是用 Qt Widgets 做的最小闭环左侧笔记列表、右侧纯文本编辑区、本地落盘、触摸软键盘能在 linuxfb 或 eglfs 下直接起窗口。能解决的是设备点检记录、调试便签、离线工单这类“板子上就地记一笔”的需求不适合多用户同步和富文本排版。适合正在学 Qt 嵌入式交叉编译、需要给 HMI 加一个可运行模块的从业者也适合刚接触 Qt 的同学拿它把信号槽、文件存储和输入法串一遍。源码包里的工程文件、部署脚本和资源目录正好对应后面几章的复现路径。2. 工程拆解QWidget、存储层和构建链怎么分工2.1 界面选 QWidget 还是 QML先看内存和输入法Qt 嵌入式记事本的第一道选型不是“哪个界面好看”而是目标板还剩多少内存、有没有 GPU、触摸输入法准备怎么做。QWidget 走的是传统 C 控件树依赖 qtbase 里的 Widgets 模块绘制后端可以直接落到 framebufferQML 走场景图动画和触控交互更顺但在没有 GPU 的板子上常用软件后端CPU 占用和启动时间都会往上走。记事本这种以文本编辑、列表切换为主的工具交互复杂度不高用 QWidget 更容易把内存和启动时间压在可控范围内。我一般按下面这张表做初筛实际项目再把数字换成板子上的实测值维度QWidget 方案QML 方案记事本场景建议运行时依赖qtbase 的 Widgets、平台插件Qt Quick、场景图、QML 运行时低配板优先 QWidget内存占用相对低控件按需创建场景图和动画缓存更吃内存64MB 级板子先跑 Widgets输入法接入可用 QInputMethod 或自绘键盘Qt Virtual Keyboard 集成更顺中文输入要单独评估触摸与动画需要自己写按压态原生手势和动画记事本动画需求弱维护成本C 信号槽逻辑集中QML 与 C 分层边界要设计小团队选 Widgets 更直接选 QWidget 不代表界面一定“土”。小屏记事本可以把左侧列表压到 160 到 200 像素右侧编辑区用无边框 QTextEdit再配一套深色 QSS触摸目标至少留 40 像素见方。真正影响体验的是字体大小、行高和软键盘遮挡不是控件框架本身。反过来说如果源码包里已经带了 QML 界面也不要硬改成 Widgets先看它有没有依赖 OpenGL、有没有把 Qt Quick 模块裁掉再决定是沿用还是重写。输入法是选型里最容易低估的一块。Widgets 方案下英文和数字键盘可以自己画一个 QDialog点按钮往当前焦点控件插字符中文输入则要接输入法引擎常见做法是部署 Qt Virtual Keyboard 的拼音插件或者调用系统里已有的输入法框架。前者资源占用不低后者要看目标板根文件系统里有没有现成组件。我的习惯是先用自绘键盘把焦点、触摸和插入逻辑跑通再评估中文输入方案不要一上来就把完整拼音引擎塞进 64MB 的板子。2.2 笔记落盘纯文本、JSON、SQLite 三种方案怎么选记事本的数据层看起来简单真正翻车往往在“写一半掉电”和“笔记多了列表卡”。纯文本方案是一条笔记一个.txt标题取首行列表靠扫描目录优点是能用文件管理器直接看缺点是重命名、排序、全文检索都要自己补笔记上千条后目录扫描会拖慢首屏。JSON 方案是单文件全量读写几十条笔记很舒服但每次保存都要重写整个文件掉电时容易把整个文件写坏除非配合临时文件加原子替换。SQLite 方案带事务和索引列表分页、按更新时间排序、增量更新都更稳代价是要把sqldrivers/libqsqlite.so一起部署到板子上。这份 Qt 嵌入式记事本源码包如果定位是“可落地的最小闭环”我建议用 SQLite 做主干导出功能再走纯文本。表结构不用复杂下面这一版够用CREATE TABLE IF NOT EXISTS notes ( id TEXT PRIMARY KEY, -- 用 QUuid 生成避免多端合并时主键冲突 title TEXT NOT NULL, -- 从正文首行截断列表只显示这一列 body TEXT NOT NULL, -- 纯文本正文不存 HTML updated_at INTEGER NOT NULL -- Unix 秒级时间戳排序和增量同步都用它 ); CREATE INDEX IF NOT EXISTS idx_notes_updated ON notes(updated_at DESC);id用QUuid::createUuid().toString(QUuid::WithoutBraces)生成避免用自增整数在导入导出时撞主键。title不要单独让用户填保存时取正文第一行超过 24 个字符就截断并补省略号小屏列表才不会撑破。updated_at用QDateTime::currentSecsSinceEpoch()比存格式化字符串更省空间排序也不用做字符串比较。索引按updated_at DESC建首屏只查最近 50 条别一上来就SELECT *全量拉。写入时用事务包住“更新笔记 更新时间戳”不要每条 SQL 单独提交。SQLite 在嵌入式存储上最怕频繁 fsync批量写入能明显减少卡顿。如果源码包里用的是 QSqlDatabase记得在打开数据库后执行PRAGMA journal_modeWAL;但 WAL 会在同目录多出-wal和-shm文件只读根文件系统上放不下必须把数据库路径指到可写分区。这个点后面避坑章节还会展开。2.3 目录与构建qmake/CMake 两条路和部署文件清单拿到源码包先别急着编译先看目录边界。一个能维护的 Qt 嵌入式记事本通常会把界面、存储、部署脚本分开避免所有代码堆在mainwindow.cpp里。下面是我拆这类工程时常见的目录形态源码包不一定完全一样但层次可以对得上notepad/ ├── CMakeLists.txt # CMake 构建入口交叉编译时配合 toolchain 文件 ├── notepad.pro # qmake 入口老工程或板厂 SDK 里常见 ├── src/ │ ├── main.cpp # 只做 QApplication 初始化、字体和翻译加载 │ ├── mainwindow.cpp # 界面组织、信号槽连接 │ ├── mainwindow.h │ ├── notestore.cpp # SQLite 或文件存储不碰界面 │ └── notestore.h ├── resources/ │ ├── fonts/ # 中文字体部署时拷到目标板 │ └── qss/ # 小屏深色主题 ├── deploy/ │ ├── run-notepad.sh # 启动脚本设置平台插件和库路径 │ └── notepad.service # 需要开机自启时用 └── cmake/ └── toolchain-arm.cmake # 交叉编译工具链描述界面层只负责“显示什么”和“用户点了什么”存储层负责“怎么落盘、怎么查询”main.cpp只做应用级初始化。这样交叉编译出问题时可以先单独编一个只带QApplication和空窗口的 demo确认平台插件能起来再逐步加回业务代码。CMake 入口可以写成下面这样Qt5 和 Qt6 的差别主要在find_package的包名和链接目标cmake_minimum_required(VERSION 3.16) project(EmbeddedNotepad LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) # 有 Q_OBJECT 的类必须开否则链接时报 vtable 未定义 set(CMAKE_AUTORCC ON) # 用到 .qrc 资源时打开 find_package(Qt5 REQUIRED COMPONENTS Widgets Sql) add_executable(notepad src/main.cpp src/mainwindow.cpp src/notestore.cpp ) target_link_libraries(notepad PRIVATE Qt5::Widgets Qt5::Sql) install(TARGETS notepad RUNTIME DESTINATION bin) install(DIRECTORY resources/fonts/ DESTINATION fonts) install(FILES deploy/run-notepad.sh DESTINATION bin PERMISSIONS OWNER_EXECUTABLE)CMAKE_AUTOMOC是 Qt 工程最容易漏的一项漏了以后报错通常不是“找不到 moc”而是链接阶段一堆undefined reference to vtable。find_package里的Widgets和Sql要跟实际用到的模块对齐不用 SQLite 就别链Qt5::Sql能少带一个库。install规则不是给主机用的交叉编译时配合DESTDIR把文件收进一个部署目录后面用 rsync 推到板子上比手工拷文件可靠。部署文件清单我一般按下面几类核对少一类都可能出现“主机能跑、板子黑屏”类别典型文件检查点可执行文件notepad用file确认是 ARM 架构Qt 基础库libQt5Core.so.5、libQt5Gui.so.5、libQt5Widgets.so.5与编译时同一套 sysroot平台插件plugins/platforms/libqlinuxfb.soQT_QPA_PLATFORM_PLUGIN_PATH指对SQL 驱动plugins/sqldrivers/libqsqlite.so用 SQLite 时必须有字体开源中文字体文件QT_QPA_FONTDIR指到目录启动脚本run-notepad.sh设好库路径、平台、字体目录提示先确认源码包用的是 qmake 还是 CMake不要两个构建文件同时改。qmake 工程在板厂 SDK 里更常见CMake 工程更适合自己维护工具链文件选一条路走通另一条只做参考。3. 交叉编译到目标板工具链、sysroot 和首屏参数3.1 先别 make工具链、sysroot 和 ABI 三项核对交叉编译翻车一半以上是工具链和 sysroot 对不上。主机上能编出 x86 程序不代表目标板能跑目标板能跑一个 hello world也不代表 Qt 库的 ABI 一致。我一般先做三件事确认编译器目标架构、确认 sysroot 里的 Qt 库架构、确认浮点 ABI。下面这几条命令不涉及具体板卡型号路径按自己的环境替换# 1. 看交叉编译器目标架构输出里应有 arm 或 aarch64 arm-linux-gnueabihf-gcc -v # 2. 看 sysroot 里的 QtCore 是不是目标架构Machine 应为 ARM arm-linux-gnueabihf-readelf -h /opt/target-sysroot/usr/lib/libQt5Core.so.5 | grep Machine # 3. 看浮点 ABI硬浮点和软浮点不能混 arm-linux-gnueabihf-readelf -A /opt/target-sysroot/usr/lib/libQt5Core.so.5 | grep -i vfpreadelf -h里的Machine如果显示Advanced Micro Devices X86-64说明你拿到的是主机库部署到板子上必然报wrong format。readelf -A里看Tag_ABI_VFP_args硬浮点工具链编出来的库和软浮点根文件系统混用运行时会出现“非法指令”或直接段错误。板厂提供的工具链通常和根文件系统匹配主机自带的交叉编译器不一定能不用就不用。sysroot 里还要确认 Qt 的安装路径。执行目标板版本的qmake -query重点看QT_INSTALL_PREFIX、QT_INSTALL_LIBS、QT_INSTALL_PLUGINS和QT_SYSROOT/opt/target-sysroot/usr/local/qt-notepad/bin/qmake -query如果QT_SYSROOT为空但你的编译命令又依赖 sysroot后面找头文件和库会乱套。常见做法是在 configure 时显式传-sysroot或者用工具链文件里的CMAKE_SYSROOT固定住。主机上如果还装着一套桌面 Qtqmake很可能优先找到主机版本编译出来的程序在板子上跑不起来这时不要靠改PATH猜直接在 CMake 里用CMAKE_PREFIX_PATH指向 sysroot 里的 Qt。3.2 configure 参数逐项拆linuxfb、tslib 和裁剪项Qt 库的 configure 参数决定后面能不能起窗口。记事本这种工具不需要 WebEngine、不需要打印支持、不需要 CUPS能裁就裁。下面是一组常见起点路径和模块按实际源码包调整export TARGET_SYSROOT/opt/target-sysroot export QT_SRC/opt/src/qt-everywhere-src export CROSS_COMPILEarm-linux-gnueabihf- export PATH/opt/toolchain/bin:$PATH $QT_SRC/configure \ -prefix /usr/local/qt-notepad \ -sysroot $TARGET_SYSROOT \ -opensource -confirm-license \ -release -optimize-size \ -no-opengl -linuxfb -tslib \ -qt-zlib -qt-libpng -qt-libjpeg \ -no-feature-cups -no-feature-printsupport \ -nomake examples -nomake tests \ -skip qtwebengine-prefix是目标板上的安装路径不是主机路径后面部署脚本和LD_LIBRARY_PATH都要跟它一致。-sysroot让编译时找头文件和库都限制在目标根文件系统里避免误链主机库。-release -optimize-size偏体积优化适合存储紧张的板子如果调试阶段需要符号可以临时切到-debug但别把调试版直接发到产线。-no-opengl -linuxfb表示走 framebuffer不依赖 GPU如果目标板有 GPU 且系统支持 eglfs可以换成-eglfs但不要在没有验证驱动的情况下硬套。-tslib是触摸校准相关老式电阻屏常用电容屏且内核直接上报多点触摸事件时可能不需要 tslib具体看目标板输入子系统。-qt-zlib、-qt-libpng、-qt-libjpeg让 Qt 自带压缩和图片解码减少对目标根文件系统里第三方库版本的依赖。-no-feature-printsupport对记事本影响不大除非源码包里用了打印预览-skip qtwebengine能省下大量编译时间和空间。裁剪的原则是“先保证 Widgets、Gui、Core、Sql 和平台插件可用”其他模块按需加回。编译 Qt 本身耗时较长我一般会先编一个最小 Qt只带 Widgets 和 linuxfb 插件把空窗口在板子上跑起来再回头补 SQLite 驱动和字体。这样出问题时边界清楚黑屏就是平台插件或 framebuffer 的问题不是业务代码。等空窗口稳定了再编记事本工程链接错误也更容易定位。3.3 部署与启动库、插件、字体一个都不能少编译完不是把可执行文件拷过去就完事。Qt 程序启动时要找平台插件、图片插件、SQL 驱动和字体任何一类缺失都可能表现为“没反应”或“黑屏”。我一般用DESTDIR把安装文件收进一个目录再整体 rsync 到板子cmake -S . -B build-target \ -DCMAKE_TOOLCHAIN_FILEcmake/toolchain-arm.cmake \ -DCMAKE_PREFIX_PATH$TARGET_SYSROOT/usr/local/qt-notepad \ -DCMAKE_INSTALL_PREFIX/usr/local/notepad cmake --build build-target -j4 DESTDIR$PWD/deploy cmake --install build-target # 以下 IP 和路径只是示例换成自己板子的地址和分区 rsync -av deploy/usr/local/notepad/ root192.168.1.50:/usr/local/notepad/ rsync -av $TARGET_SYSROOT/usr/local/qt-notepad/lib/ root192.168.1.50:/usr/local/qt-notepad/lib/ rsync -av $TARGET_SYSROOT/usr/local/qt-notepad/plugins/platforms/ root192.168.1.50:/usr/local/notepad/plugins/platforms/CMAKE_TOOLCHAIN_FILE里要写清楚CMAKE_SYSTEM_NAME、CMAKE_SYSTEM_PROCESSOR、CMAKE_C_COMPILER、CMAKE_CXX_COMPILER和CMAKE_SYSROOT。CMAKE_PREFIX_PATH指向目标板 Qt 的安装前缀不是主机 Qt。DESTDIR只影响安装阶段的根目录不会改变程序里的-prefix所以部署目录结构要和目标板路径对得上。启动脚本建议单独放不要把所有环境变量写进main.cpp。下面这版覆盖了平台、插件、字体和库路径#!/bin/sh export QT_QPA_PLATFORMlinuxfb:fb/dev/fb0 export QT_QPA_PLATFORM_PLUGIN_PATH/usr/local/notepad/plugins/platforms export QT_QPA_FONTDIR/usr/local/notepad/fonts export LD_LIBRARY_PATH/usr/local/qt-notepad/lib:$LD_LIBRARY_PATH exec /usr/local/notepad/bin/notepadQT_QPA_PLATFORM里的fb/dev/fb0要跟目标板实际的 framebuffer 设备一致有的板子是/dev/fb1。QT_QPA_PLATFORM_PLUGIN_PATH指向libqlinuxfb.so所在目录不是 Qt 安装目录的上一级。QT_QPA_FONTDIR只影响 Qt 找字体的目录系统 fontconfig 是另一套路径。LD_LIBRARY_PATH要放在exec之前否则程序启动时动态链接器已经找不到库了。部署后用ldd查一遍缺失库比在板子上看黑屏猜原因快得多LD_LIBRARY_PATH/usr/local/qt-notepad/lib \ ldd /usr/local/notepad/bin/notepad | grep not found如果输出为空说明动态库依赖齐了如果有not found按名字回推是 Qt 库、系统库还是编译器运行时库。常见漏项是libstdc.so.6版本不匹配主机工具链带的版本比板子根文件系统新运行时报GLIBCXX_3.4.xx not found。这种不要往板子上硬塞主机库优先用与根文件系统匹配的工具链重编。4. 笔记功能落地列表、编辑、自动保存和中文输入4.1 主界面最小闭环QListWidget 加 QTextEdit记事本的主界面不需要复杂框架左侧QListWidget管笔记列表右侧QTextEdit管正文中间用QSplitter或QHBoxLayout分开。小屏上我倾向固定左栏宽度把更多空间留给编辑区同时把列表项高度调大方便手指点选。下面这段是构造函数的骨架MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { auto *central new QWidget(this); auto *layout new QHBoxLayout(central); layout-setContentsMargins(4, 4, 4, 4); layout-setSpacing(4); m_list new QListWidget(central); m_list-setObjectName(noteList); m_list-setFixedWidth(180); // 800x480 屏幕上左栏 180 左右按实际分辨率调 m_list-setUniformItemSizes(true); // 列表项高度一致滚动更轻 m_editor new QTextEdit(central); m_editor-setAcceptRichText(false); // 先按纯文本做存储和导出都简单 m_editor-setPlaceholderText(QStringLiteral(点这里开始记)); layout-addWidget(m_list); layout-addWidget(m_editor, 1); setCentralWidget(central); connect(m_list, QListWidget::currentRowChanged, this, MainWindow::loadNote); connect(m_editor, QTextEdit::textChanged, this, MainWindow::scheduleSave); }setFixedWidth(180)不是固定值800x480 上可以 160 到 2001024x600 上可以放到 240。setAcceptRichText(false)很关键富文本会带来 HTML 解析、字体嵌套和存储膨胀记事本场景没必要。setUniformItemSizes(true)让列表项高度一致滚动时不用反复计算低配板子上能省一点 CPU。列表项不要只存标题字符串要把笔记 id 塞进Qt::UserRole否则标题重复时无法定位到具体笔记void MainWindow::reloadList() { const QSignalBlocker blocker(m_list); // 刷新列表时不要触发 currentRowChanged m_list-clear(); const auto notes m_store-listNotes(50); for (const auto n : notes) { auto *item new QListWidgetItem(n.title, m_list); item-setData(Qt::UserRole, n.id); } }QSignalBlocker是刷新列表时的后悔药。不加它clear()和addItem()会触发currentRowChanged可能把正在编辑的内容覆盖掉。listNotes(50)只取最近 50 条首屏不卡要全部笔记时再做分页或搜索。Qt::UserRole存 id显示文本只放标题标题和 id 分开后面重命名笔记时不会把主键改掉。4.2 自动保存与异常恢复QSaveFile 加防抖定时器记事本最怕两件事用户记完没点保存就切走以及保存到一半掉电把原文件写坏。QSaveFile的做法是先写临时文件commit()时再原子替换目标文件掉电时旧文件至少还在。配合一个防抖定时器用户停止输入 800 毫秒后再落盘避免每敲一个字都写存储void MainWindow::scheduleSave() { if (m_loading) return; // 加载笔记时不要触发保存 m_dirty true; m_saveTimer.start(800); // 800ms 防抖触摸屏输入慢别设 50ms } void MainWindow::saveCurrentNote() { if (!m_dirty || m_currentId.isEmpty()) return; QSaveFile file(notePath(m_currentId)); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { showToast(QStringLiteral(保存失败%1).arg(file.errorString())); return; } QTextStream out(file); out.setCodec(UTF-8); // Qt6 改为 out.setEncoding(QStringConverter::Utf8) out m_editor-toPlainText(); if (!file.commit()) { showToast(QStringLiteral(提交失败%1).arg(file.errorString())); return; } m_dirty false; m_store-touch(m_currentId, QDateTime::currentSecsSinceEpoch()); }m_loading是加载标志loadNote()里先置 truesetPlainText()之后再置 false防止“加载触发 textChanged、textChanged 又触发保存”的循环。m_saveTimer用单次触发每次输入重新计时800 毫秒是触摸屏上比较稳的值设得太短存储写入频繁设得太长切换笔记时容易丢最后一段。QSaveFile::commit()返回 false 一定要提示不能只写日志用户看不到日志就等于没保存。如果源码包用的是 SQLite 而不是单文件保存逻辑换成事务即可但防抖和m_loading标志仍然保留。数据库路径要用可写分区比如/userdata/notepad/notes.db不要放在/usr/local/notepad/这种只读根文件系统下。启动时先QDir().mkpath()建目录再打开数据库打开失败要弹窗提示不要静默降级到内存存储否则用户以为保存了重启全丢。4.3 中文显示与触摸输入字体、编码、软键盘三件事中文显示和中文输入要分开处理。显示靠字体和编码输入靠输入法或自绘键盘。先确认板子上有没有中文字体fc-list :langzh如果输出为空界面上的中文大概率是方块。把开源中文字体拷到部署目录的fonts/下启动脚本里设QT_QPA_FONTDIR/usr/local/notepad/fonts再在main.cpp里显式设置应用字体QFont font(QStringLiteral(Noto Sans CJK SC)); font.setPixelSize(18); // 小屏触摸18 到 22 像素比较稳 qApp-setFont(font);字体名要和实际字体文件匹配fc-list里能看到 family 名称。setPixelSize比setPointSize更适合固定分辨率的小屏不受 DPI 缩放影响。编码方面源码文件统一 UTF-8QTextStream写文件时显式设 UTF-8SQLite 里存的也是 UTF-8 字符串不要用本地 locale 默认编码板子上 locale 经常是C中文会变问号。触摸输入如果源码包自带软键盘先看它是自绘键盘还是 Qt Virtual Keyboard。自绘键盘通常只插英文、数字和符号逻辑简单适合先跑通焦点和触摸void SoftKeyboard::insertText(const QString text) { QWidget *focus QApplication::focusWidget(); if (auto *edit qobject_castQLineEdit *(focus)) { edit-insert(text); } else if (auto *textEdit qobject_castQTextEdit *(focus)) { textEdit-insertPlainText(text); } }QApplication::focusWidget()拿到当前焦点控件qobject_cast判断是单行还是多行编辑再插入文本。这个方案不处理拼音候选只适合英文和数字。中文输入常见做法是部署 Qt Virtual Keyboard 的拼音插件或者调用系统输入法框架前者要额外 QML 运行时和词库后者要看根文件系统里有没有现成组件。我的建议是先用自绘键盘验证触摸、焦点和遮挡关系再决定中文方案不要一开始就把完整拼音引擎塞进去。注意软键盘弹出时会遮住编辑区Widgets 里可以在键盘显示时给编辑区加底部边距或者把编辑区滚动到光标位置。这个细节不处理用户输入时看不到自己打的字体验会直接崩。5. 避坑与排查Qt 嵌入式记事本五类翻车现场5.1 黑屏、花屏与平台插件加载失败现象程序启动后没有窗口串口没有明显报错或者屏幕出现花屏、颜色错位。原因通常是QT_QPA_PLATFORM没设、平台插件路径不对、framebuffer 设备不对或者 eglfs 在无 GPU 的板子上硬跑。先开插件调试把加载过程打出来export QT_DEBUG_PLUGINS1 export QT_QPA_PLATFORMlinuxfb:fb/dev/fb0 ./notepad 21 | tee /tmp/qt.log日志里重点看QFactoryLoader有没有找到libqlinuxfb.so以及Cannot load library后面的原因。如果提示找不到平台插件检查QT_QPA_PLATFORM_PLUGIN_PATH是否指到plugins/platforms目录目录里是否有目标架构的.so。花屏则看/proc/fb和fbset确认分辨率、色深和程序假设一致程序里如果写死了 800x480实际屏幕是 1024x600布局会错位但不一定花屏。颜色错位常见于 framebuffer 的 BGR/RGB 顺序先换平台参数或检查内核配置不要急着改业务代码。5.2 中文方块、乱码和输入法不弹现象界面中文显示为方块或者保存后的文件用十六进制看是 GBK 编码换到主机打开乱码。原因分三层字体缺失、源码/运行时编码不对、QTextStream用了本地编码。先查字体再查编码。fc-list :langzh为空就部署中文字体有字体但界面还是方块检查QT_QPA_FONTDIR和QFont的 family 名是否匹配。文件乱码则把写入代码改成显式 UTF-8Qt6 里setCodec已移除要用setEncoding(QStringConverter::Utf8)。数据库连接也要确认存的是 UTF-8 文本不要把QByteArray直接当字符串塞进去。输入法不弹先看焦点控件有没有设置Qt::StrongFocus再看软键盘是不是只对QLineEdit生效。QTextEdit的焦点策略默认可用但如果外面套了QScrollArea或自定义控件焦点可能被吃掉。排查时在focusChanged信号里打印当前焦点控件类名确认点击编辑区后焦点真的过去了。中文输入还要确认输入法插件是否部署QT_IM_MODULE环境变量是否设置没有输入法引擎时自绘键盘只能插英文不要误判为“键盘坏了”。5.3 保存失败、文件丢失和自动保存死循环现象点保存没反应日志里Permission denied或者 CPU 占用突然飙高界面卡住。前者的原因通常是数据库或笔记文件放在只读根文件系统或者当前工作目录不可写后者多半是textChanged里调用了setPlainText()触发递归。保存路径要显式指到可写分区不要用相对路径notes.db因为启动脚本的当前目录不一定是部署目录。QSaveFile本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询