ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用Qt写跨平台迷你看盘软件:C++ Qt完整项目实战与编译指南

用Qt写跨平台迷你看盘软件:C++ Qt完整项目实战与编译指南 简介一份基于Qt开发的跨平台迷你看盘软件完整源码包覆盖Windows、Linux、macOS三大平台面向正在学习C与Qt框架的初学者也适合快速上手金融行情展示项目的开发者。软件以实时行情显示为核心可帮助理解跨平台GUI程序的界面组织、信号与槽通信、数据刷新及网络请求等关键环节。资源共509个文件压缩包约14.73MB。包含h/c/cpp等源代码、Qt工程与界面文件.pro/.ui/.qrc、跨平台构建脚本.am/.in、Markdown/PDF说明文档以及图标字体等资源文件目录结构清晰便于按模块阅读和编译调试。目前已有134人浏览/学习。通过研读实现代码可以掌握Qt Widgets的信号槽机制、事件处理流程以及TCP或WebSocket方式的实时数据获取与解析同时还能了解跨平台编译配置、不同系统的部署细节。整体上是一份贴近实战的入门级C/Qt学习素材既能直接运行观察效果也可作为二次开发和课程设计的参考模板。1. 用Qt写跨平台迷你看盘软件新手学习C Qt最容易出成果的完整项目很多自学C的人学到Qt就卡住了控件教程刷了一堆真打开Qt Creator新建项目面对main.cpp和.pro文件却不知道下一步做什么。看盘软件恰好是这类瓶颈的解药——它足够小不需要后端和数据库但又把C Qt开发里最常碰到的几件事全占了用结构体组织数据、用QTimer做定时刷新、用QPainter自绘K线、用信号槽连接网络与界面最后还要处理win32、Linux、macOS三套编译环境。这个迷你看盘软件就是典型代表一个能显示行情列表、定时刷新、画出K线的小桌面程序界面靠Qt Widgets实现工程结构清晰。对刚学完C语法、想完整跑通一个Qt项目的开发者来说这个zip里的代码是很好的起步样本对需要内部行情工具的人也值得拿去做二次改造。2. 拆解Qt工程骨架为什么跨平台看盘项目要先理清.pro与数据层Qt跨平台本质上是“写一遍源码按平台翻译”。gui和widgets模块在Windows下调Win32 API在Linux走X11/Wayland在macOS走Cocoacore、network这类模块也是逐平台实现对外接口保持一致。看盘软件用到的界面、定时器、HTTP请求、绘图全在Qt封装范围内所以工程层面几乎不需要写#if defined(_WIN32)这类平台分支就能在三个平台编译——前提是.pro文件、源文件编码、编译器选型从一开始就是对的。这个前提新手往往要翻一次车才真正理解。2.1 先看.pro和main.cppQt跨平台工程的中枢配置拿到任何一个Qt学习项目第一个打开的文件永远是.pro。qmake的.pro文件相当于Qt工程的心脏三个平台共用一份里面写清楚用了哪些模块、目标叫什么、哪些源文件参与编译。一个迷你看盘软件的.pro通常长这样QT core gui widgets network TARGET MiniStock TEMPLATE app CONFIG c17 SOURCES \ main.cpp \ mainwindow.cpp \ stockdata.cpp \ klinewidget.cpp HEADERS \ mainwindow.h \ stockdata.h \ klinewidget.h这段配置里最重要的是第一行QT 。core和gui是Qt默认模块新手容易漏掉的是network和widgets看盘软件要用HTTP接口拉行情必须加network要用QTableWidget、QSplitter这类控件必须加widgets。不加的话编译到QNetworkAccessManager那行就报“未定义引用”。TARGET是生成的可执行文件名三个平台会分别生成MiniStock.exe、MiniStockLinux ELF和MiniStockmacOS Mach-O。CONFIG c17指定C标准Qt 5.15的容器和语法在C17下最省心。如果项目还引用了第三方库那就要把库路径写进LIBS但看盘软件这个体量通常用不上。main.cpp是所有Qt Widgets程序的统一入口内容非常固定#include QApplication #include mainwindow.h int main(int argc, char *argv[]) { QApplication app(argc, argv); // 每个Widgets程序只能有一个QApplication MainWindow w; w.show(); return app.exec(); // 进入事件循环之后全是信号槽在驱动 }这里的逻辑不复杂QApplication负责初始化GUI环境并管理事件循环exec()一旦返回程序就退出。看盘软件里的QTimer超时信号、网络请求的回传、按钮点击全部靠exec()转起来所以不要在exec()之前做耗时初始化否则窗口还没显示出来程序就卡在构造函数里了。2.2 界面怎么分工主窗口、行情表格、自绘K线控件各管一块Qt界面设计在这个项目里通常划分为三个区域MainWindow放菜单和状态栏中间用QSplitter把窗口拆成左右两块左边是QTableWidget行情列表右边是自定义的KLineWidget。把K线图做成独立QWidget子类、重写paintEvent而不是把绘图代码塞进MainWindow是为了让界面刷新和绘图隔离——行情列表每次进来一条数据只更新一行K线区域则要整块重绘两者刷新频率和数据粒度都不同。这里顺便说下Qt Widgets和QML的取舍。Qt Quick/QML适合做偏动画、偏触摸的界面但看盘软件这种信息密度高、控件交互传统的场景用Widgets写起来更直接调试也简单。学习C Qt也建议从Widgets切入把信号槽和事件循环搞明白再去看QML会更轻松。常见的组织方式是MainWindow持有DataProvider和两个界面组件实例用信号槽把它们接起来。表格数据变化时只更新表格K线数据变化时调用klineWidget-update()触发重绘。这个拆分看起来简单但对新手来说它决定了以后加功能是“在MainWindow里继续堆代码”还是“新增一个类、几行信号槽接入”。.ui文件是一种可选的界面组织方式配套的界面设计器能拖拽摆放控件生成XML格式的.ui文件由uic编译成C代码。迷你看盘软件这种界面不复杂的程序纯代码创建控件反而更直白因为你能清楚看到每个控件在哪个函数里new出来的界面设计器拖出来的嵌套布局新手后期反而不容易改。2.3 数据层与界面层分离给看盘软件一个MVC雏形很多新手项目翻车都是把行情拉取、解析、刷新逻辑全写在MainWindow的实现里最后MainWindow变成上千行的上帝类。更稳的做法是学MVC/MVVM的拆分思路在Qt里用类加信号槽实现。定义一个DataProvider类专门拉数据class DataProvider : public QObject { Q_OBJECT public: void fetch() { // 发起HTTP请求也可以先读本地模拟数据 // 拿到结果后组装 QVectorStockItem emit dataReady(items); } signals: void dataReady(const QVectorStockItem items); };struct StockItem { QString code; // 股票代码 QString name; // 名称 double price; // 最新价 double changePercent; // 涨跌幅 QVectordouble closes; // 收盘价序列画K线用 };StockItem用QString和double这些对Qt友好且可跨平台转移的类型在信号槽里传递不会有字节对齐和指针生命周期问题。DataProvider发dataReady信号MainWindow槽函数里只做界面更新。这套结构其实就是Qt里常见的观察者模式等写到第二个项目时你会发现这套拆分可以平滑过渡到更规范的MVVM配合QAbstractTableModel但对迷你看盘软件来说数据层两层拆分已经够用。QVectorStockItem经由信号槽传递时Qt会自动拷贝这个容器界面拿到的是一份独立数据不会出现后台线程改数据、界面读到一半的竞态问题。3. 三平台编译实操win32、Linux、macOS最小构建命令与套件选择同一个zip在三个平台上编译最大的变量不是源码而是Qt套件Kit和编译器。Qt Creator把“编译器Qt库mkspec”打包成一个个Kit选错Kit是一切编译怪问题的源头。这一章把三个平台的最小构建路径都过一遍命令行方式为主因为命令行你一旦跑通对Qt构建过程的理解会比只点绿色三角号深得多。3.1 WindowsMSVC 2019还是MinGWVS2022 Qt Tools怎么配合Windows上有两种主流组合。第一种是Qt官方安装器里装Qt 5.15.2补上MinGW 8.1或MSVC2019_64套件用Qt Creator自带Kit编译运行。第二种是装VS2022并安装Qt VS Tools扩展在Visual Studio里直接打开.pro工程。两种我都试过建议新手优先用第一种环境问题最少。如果你习惯VSCode需要自己装C/C扩展和CMake插件Qt工程的构建仍然依赖qmake或CMake编辑器只是壳。手动命令行构建时要显式指定mkspec和编译命令mkdir build cd build qmake ..\MiniStock\MiniStock.pro -spec win32-msvc CONFIGdebug nmake这里的-spec win32-msvc是给MSVC用的如果选MinGW套件就改成-spec win32-g最后用mingw32-make而不是nmake。很多教程只写qmake make在Windows上直接报错找不到make就是因为没区分编译器命令行。32位构建的mkspec同样是win32-msvc但需要安装对应x86的Qt库并选择带x86字样的套件。这个zip标题里的win32指的就是这类Windows桌面构建目标Windows 10/11上64位系统跑32位程序完全没压力。MSVC编译出的程序发布到别的机器时目标机器可能还需要装对应版本的Visual C运行库否则程序一启动就报缺VCRUNTIME140.dll这也是新手发布时容易忽略的一环。3.2 Ubuntu/国产Linuxapt安装Qt依赖后用qmake构建Linux下构建最省事的是用发行版自带的Qt库不需要从Qt官方安装器拖几个GB的SDKsudo apt update sudo apt install qtbase5-dev qttools5-dev-tools qmake --version qmake MiniStock.pro make -j$(nproc) ./MiniStockqtbase5-dev提供QtWidgets和QtNetwork的头文件与库qttools5-dev-tools提供qmake等命令行工具。Ubuntu 20.04默认是Qt 5.12比5.15少了一些API如果zip里代码用到5.15才有的接口编译会直接报“no member named xxx”这时要么升级到Qt 5.15的官方安装包要么改代码规避。国产Linux发行版大多是Debian系apt源里的包名基本一致装法相同源里没有的包就改用Qt官方安装器装到用户目录不影响系统。构建时如果同时装了系统Qt和手动安装的Qt注意qmake指向哪个版本用qmake -query QT_VERSION确认指向错了需要调整PATH。Qt命令行工具在Linux下同样有效qmake的配置会在Makefile里自动带上-lQt5Widgets这类链接参数你不需要手动写库路径这也是qmake比直接写g命令省心的地方。3.3 macOSXcode命令行工具与Qt 5.15的编译参数macOS上先装CommandLineTools再装Qt。用Homebrew装Qt 5的典型流程是xcode-select --install brew install qt5 export PATH/opt/homebrew/opt/qt5/bin:$PATH qmake MiniStock.pro make注意Apple Silicon机器上brew路径是/opt/homebrewIntel机器是/usr/local。Qt 5.15的macOS套件会走macx-clang的mkspec自动根据当前系统架构编译。如果zip里的工程是旧配置构建的x86_64产物在新机器上重编一次就变成arm64源码不用改。显卡驱动和高DPI缩放下Qt 5.15在macOS上表现正常但如果你用的是很老的Qt安装器包macOS会提示“不能从你正运行的macOS版本使用此安装器”这种情况直接放弃老安装包改用brew或Qt官方在线安装器拉最新补丁版本。macOS的程序是一堆库嵌在一个.app目录里的直接跑终端编译出来的可执行文件也能弹窗但要做成能分发的.app还得用macdeployqt这个放到3.4节说。3.4 用Qt命令行工具完成构建与部署前检查qmake加make只是构建环节要让程序在别的机器上能跑还需要部署工具把Qt运行库收集到一起Windows是windeployqtLinux是linuxdeployqt社区维护macOS是macdeployqt。在写这个看盘软件的构建步骤时我一般会在make命令之后补一步部署# Windows: 把Qt运行时和platforms插件拷到可执行文件旁 windeployqt build\debug\MiniStock.exe # macOS: 生成app bundle并内嵌依赖库 macdeployqt build/MiniStock.app部署的本质是把程序依赖的Qt5Widgets.dll、Qt5Network.dll以及platforms目录拷到发布目录。忽略这一步程序在开发机跑得好好的拷到别的电脑上双击没反应或弹“无法启动此程序因为计算机中丢失Qt5Widgets.dll”这是发布阶段最常见的返工原因。Linux下的linuxdeployqt经常需要自己拉依赖我习惯直接用ldd命令检查缺哪些so再手工拷进发布目录。平台构建工具编译命令部署工具win32nmake / mingw32-makeqmake -spec win32-msvc nmakewindeployqtLinuxmakeqmake make -j$(nproc)linuxdeployqt 或手动拷 somacOSmakeqmake makemacdeployqt4. 核心功能实现行情结构体、QTimer刷新与QPainter画K线的落地写法搭建完工程、能在本机跑起来之后就到了最值得读源码的部分行情数据怎么组织、刷新循环怎么写、K线怎么画。这三个点分别对应C的struct、Qt的事件循环机制和绘图系统也是看盘软件区别于普通增删改查程序的核心。4.1 用结构体定义行情数据跨平台类型与JSON解析看盘软件的第一步不是画界面而是定数据结构。所有界面展示、指标计算、K线绘制都建立在行情结构体上struct StockItem { QString code; // 股票代码不带交易所前缀 QString name; // 名称 double price; // 最新价 double changePercent; // 涨跌幅单位是百分比 QVectordouble closes; // 收盘价序列最后一根是最新价 }; bool parseStockItem(const QByteArray json, StockItem out) { QJsonDocument doc QJsonDocument::fromJson(json); if (!doc.isObject()) return false; QJsonObject obj doc.object(); out.code obj.value(code).toString(); out.price obj.value(price).toDouble(); out.closes ...; // 从数组字段读取 return true; }这里有个新手常踩的细节价格字段用double而不是float。行情软件里价格精确到小数点后两位float的精度足够但在Qt的QVariant和JSON序列化链路里double是直接支持的float经常要额外转换。跨平台传输时double没有平台差异结构体里统一用double后面算涨跌幅、画坐标都不用担心类型转换丢精度。解析逻辑单独做成一个函数还有个好处可以先用本地JSON文件验证解析再切换真实网络接口两个阶段互不干扰。4.2 QTimer驱动行情刷新别把网络请求写进界面线程迷你看盘软件的刷新循环由QTimer驱动这是Qt里做周期性任务的标准工具m_timer new QTimer(this); m_timer-setInterval(3000); // 3秒刷新一次看盘软件常见周期 connect(m_timer, QTimer::timeout, this, MainWindow::refreshQuotes); m_timer-start();void MainWindow::refreshQuotes() { m_provider-fetch(); // 异步发起HTTP请求不阻塞UI }这里的关键词是“异步”。如果直接在refreshQuotes里用QNetworkAccessManager的同步阻塞接口或者用QThread::sleep模拟等待界面会每隔3秒卡死一次用户拖窗口都拖不动行情刷新频率越高卡得越明显。正确做法是fetch里发起异步请求请求完成时通过信号通知界面在槽函数里更新表格和K线。QTimer和网络信号同属事件循环的一部分天然协作不需要额外开线程。刷新周期也要讲分寸盘中最快3秒5秒更稳妥再快容易触发行情接口的频率限制这在真实项目中吃过亏。4.3 用QPainter自绘K线像素坐标映射与涨跌配色K线图是看盘软件里最有技术含量的一块核心是坐标映射把价格区间映射到控件像素区间void KLineWidget::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); const int m 8; // 四周留边距防止K线贴边 const double maxV *std::max_element(m_highs.begin(), m_highs.end()); const double minV *std::min_element(m_lows.begin(), m_lows.end()); const int n m_closes.size(); if (n 2) return; auto px [](int i) { return m (width() - 2 * m) * i / (n - 1); }; auto py [](double v) { return height() - m - (height() - 2 * m) * (v - minV) / (maxV - minV); }; for (int i 0; i n; i) { bool up m_closes[i] m_opens[i]; painter.setPen(up ? QColor(#e24b4b) : QColor(#1a9850)); painter.drawLine(px(i), py(m_highs[i]), px(i), py(m_lows[i])); // 上下影线 painter.drawRect(px(i) - 2, py(m_opens[i]), 4, (int)(py(m_closes[i]) - py(m_opens[i]))); // 实体 } }绘图有两个细节值得注意。第一坐标转换必须先算像素再画不能把价格直接当像素坐标用否则在高价股和低价股之间切换时图形会飞掉maxV和minV分别是当前显示区间里的最高价和最低价区间变了K线会自动缩放。第二涨跌色彩在不同市场习惯不同国内红涨绿跌海外绿涨红跌把颜色定义成可配置常量后期切换市场时不用改绘图代码。窗口resize时paintEvent会跟着重新触发坐标计算全部基于this-width()和height()所以K线图不会因为拉大窗口而变形这一点拖动窗口试试就知道。5. 新手编译Qt跨平台项目必踩的五个坑现象、原因、解决这一章把新手在这个类型项目上最常遇到的问题整理成册每一条都是“现象—原因—解决”三段式。前两条是编译期报错中间两条是运行期崩溃最后一条是发布期翻车基本覆盖了从拿到zip到能发给别人用的全流程。5.1 dependent ....\qt\5.15.2\msvc2019_64\include\qtwidgets 路径依赖报错现象在Qt Creator里打开别人的项目后生成构建目录时报“:-1: error: dependent ............\qt\5.15.2\msvc2019_64\include\qtwidgets 不存在”还没开始编译就直接失败构建输出里全是一长串相对路径。原因这类.pro文件里手工写了INCLUDEPATH指向某个Qt安装目录的相对路径打包成zip换了电脑目录层级一变路径就失效。Qt自己的头文件根本不需要这样手工指路模块路径由qmake按QT 配置自动定位。解决打开.pro把以../../开头的INCLUDEPATH和DEPENDPATH条目全部删掉只保留项目自身目录的路径然后删除构建目录可能是影子构建目录重新qmake再构建。以后新建Qt项目也不要往.pro里写Qt安装路径那是在给自己埋地雷。5.2 directory picker failed: win32 folder dialog worker 文件夹对话框崩溃现象在Windows上运行程序点击导入数据或保存录制的按钮时弹窗报“directory picker failed: directory picker failed: win32 folder dialog worker”文件夹选择框不出来。原因Qt 5.15.x在Windows上调用系统原生文件夹对话框时需要借助系统Shell的win32 folder dialog worker进程。某些精简版系统、远程桌面会话或程序跑在非交互Session里时这个辅助进程起不来Qt的原生对话框直接失败。解决让对话框退回Qt自带实现不依赖系统组件QString dir QFileDialog::getExistingDirectory( this, 选择数据目录, QDir::homePath(), QFileDialog::ShowDirsOnly | QFileDialog::DontUseNativeDialog);加上DontUseNativeDialog之后文件夹选择框走Qt自己的窗口样式朴素一点但不会触发win32 dialog worker的报错。如果你是在远程会话里碰到这问题这个标记就是后悔药不用重装系统。5.3 Qt库与编译器不匹配编译通过运行即崩现象安装Qt时勾选了MSVC 2019 64bit的Qt库却用MinGW的Kit打开.pro编译能出exe一运行就弹“应用程序无法正常启动0xc000007b”或者停在某个Qt库内部断点处崩溃。原因Qt库本身是用MSVC编译的带的是MSVC运行时依赖。换成MinGW的g去链接生成的程序把Qt符号和C运行库符号链得乱七八糟最坏情况是编译期不报错运行期在Qt内部炸掉。这种“编译通过运行炸”的问题在Qt跨平台里极像玄学实际就是套件选错了。解决在Qt Creator里重新选择套件确保编译器与Qt库版本严格对应。装了MSVC2019_64的Qt库就选“Desktop Qt 5.15.2 MSVC2019 64bit”并确认VS组件里有C工具集想用MinGW就重新下载MinGW套件的Qt安装包。一个构建目录只对应一个Kit切换Kit必须清掉shadow build目录重新构建不清的话旧文件和新链接器混在一起各种诡异报错。5.4 中文源码在win32下乱码与编译失败现象代码里写了中文注释或中文字符串在Windows上编译报C2001“常量中有换行符”或者程序运行后窗口标题和按钮显示乱码。同一份源码在Linux和macOS上编译却没有问题。原因MSVC默认按本地代码页解析无BOM的源文件中文Windows的代码页是GBK而Qt Creator默认保存为UTF-8。编译器把UTF-8字节当成GBK解析字符串长度和字符边界全错位直接报语法错误或产生乱码。解决统一源码文件编码为UTF-8并在.pro里对MSVC显式声明msvc: QMAKE_CXXFLAGS /utf-8这样MSVC按UTF-8解析所有源文件中文注释和字符串都稳定。Linux和macOS默认UTF-8不受此坑影响。所以同一个zip在win32上翻车、在Linux上却正常先查编码这比查代码逻辑快得多。5.5 换机器运行提示缺少platforms插件/DLL现象把自己构建的MiniStock.exe拷贝到另一台电脑双击没反应命令行运行报“This application failed to start because it could not find or load the Qt platform plugin windows”Linux下报“cannot open shared object file: libQt5Widgets.so.5”。原因没做部署。Qt程序运行需要Qt动态库和platforms目录里的qwindows.dllLinux是qxcb.somacOS是libqcocoa.dylib少了任何一个都起不来。开发机因为装了Qt SDK系统路径里能找到库所以从来不会暴露这个问题。解决发布前用部署工具收集依赖Windows用windeployqtmacOS用macdeployqtLinux用ldd检查后手工拷so。另外在程序目录放一个qt.conf指定插件路径也能解决一部分问题但最稳的还是把部署命令固定到构建脚本里。我自己第一个发布版就在这里翻过车开发机一切正常发给同事后打不开排查了半天就是少了platforms目录。6. 把迷你看盘改成自己的工具数据源替换、指标叠加与回归验证6.1 把模拟数据源换成真实HTTP接口动手改之前先在DataProvider里把数据源从“读本地JSON文件模拟”切换成QNetworkAccessManager请求真实接口同时保留模拟模式作为脱网调试手段void DataProvider::fetch() { QNetworkRequest req(QUrl(https://your-quote-api.example.com/quotes)); m_nam-get(req); // 异步发送绝不阻塞UI }收到响应后在finished信号里解析JSON组装成QVectorStockItem再发出dataReady。注意设置一个合理的超时时间行情接口偶尔慢是常态QNetworkAccessManager默认超时机制不明显我一般手动加QTimer单发超时兜底防止程序在接口卡住时永远不刷新。6.2 给K线叠加一条均线在KLineWidget里加一个成员m_ma5paintEvent里先算好均线序列再用drawPolyline连接QVectordouble ma5; for (int i 0; i n; i) { if (i 4) ma5.append(std::numeric_limitsdouble::quiet_NaN()); else { double sum 0; for (int k 0; k 5; k) sum m_closes[i - k]; ma5.append(sum / 5.0); } }算均线有更高效的前缀和方法但看盘软件一次就几千根K线O(n)直算完全够用代码可读性反而更好。画线时跳过NaN点connectPoints时只对有效区间连线否则线会断成几截。6.3 用Qt Test做主流程回归功能改动后最怕把行情刷新弄坏。我给这个项目写DataProvider和KLineWidget加几个Qt Test用例测试行情解析、结构体转换、坐标映射越界检查。改动数据格式时跑一遍测试比肉眼盯盘确认快得多。测试代码里可以用模拟JSON字符串喂给parseStockItem断言字段值正确K线坐标函数单独抽成一个纯函数输入价格输出像素断言在边界值下不越界。我在自己第一个Qt项目里贪快把解析、刷新、绘图全塞进MainWindow结果加自选股功能时改了三天还引入两个界面卡死的bug。后来老老实实按数据层、界面层、控制刷新三层拆开才意识到看盘软件这个体量的项目架构上的克制比功能堆叠更值钱。这个zip如果能带你跑通一次qmake—编译—部署的完整链路价值就够大再花一个周末把模拟数据换成真实接口你就已经超过大多数只跑通示例工程的初学者了。希望帮到你。本文还有配套的精品资源点击获取
返回列表