Qt+MySQL股票管理系统:可运行源码与部署避坑指南
发布时间:2026/10/1 14:55:01来源:尧图网络
简介这是一套完整的基于Qt与MySQL开发的股票管理系统毕业设计项目面向计算机、电子信息、数学等专业的本科生适用于课程设计、期末大作业及毕业设计参考。系统实现用户管理、股票信息增删改查、行情展示、数据导出等核心功能代码结构清晰模块划分合理含登录、用户管理、股票添加/修改/查询/预测等多个UI界面与对应逻辑层便于理解MVC模式在桌面应用中的实践。资源共56个文件涵盖14个C源文件.cpp、13个头文件.h、12个Qt界面文件.ui、9张界面截图与流程图png以及SQL建库脚本、项目报告PDF、README说明文档等压缩包大小为36.51MB。已有122人学习下载提供可直接运行的打包程序.exe与完整数据库脚本附带详细流程图与C课程设计报告有助于快速掌握Qt GUI开发、MySQL连接与CRUD操作、多窗口交互等关键技术点。1. 这不是又一个“学生练手项目”QtMySQL股票管理系统源码包真能跑通行情模拟、实时持仓计算与交易回测闭环你下载过几十个标着“毕业设计”“课程设计”的 Qt 项目压缩包解压后双击.pro文件——Qt Creator 打开编译报错QMYSQL driver not loaded或者数据库连接失败弹窗写着Access denied for user rootlocalhost再或者界面能启动但点击“加载K线”就卡死控制台一行日志都不打。这不是玄学是缺了三样东西可复现的 MySQL 环境配置路径、Qt SQL 驱动编译绑定细节、以及真实股票数据结构与业务逻辑的耦合验证点。这个QtMySQL 股票管理系统.zip不是模板套壳它包含完整可运行的 C 源码Qt 5.15.2 兼容、建库脚本stock_db.sql、带注释的README.md项目说明、Word 版设计报告含ER图与模块流程图更重要的是——所有数据库表字段命名直指真实交易场景trade_record.t_volume是成交手数而非“数量”portfolio.p_cost_price是加权平均持仓成本而非买入价kline_daily.k_ma5是5日均线而非简单移动平均。适合正在做课设/毕设、需要交源码报告可演示系统的学生也适合想快速搭建本地量化回测前端的 C 初学者——它不教你写策略但把行情接入、订单撮合、盈亏计算、图表联动这四块硬骨头全用 Qt Widgets QSqlQuery QCustomPlot 拆解清楚了。2. 从零部署Qt 环境、MySQL 实例、驱动绑定三步落地绕开 90% 的“QMYSQL driver not loaded”2.1 环境版本对齐为什么必须用 Qt 5.15.2 MySQL 8.0.x 组合这个源码包基于 Qt 5.15.2 编写核心依赖QSqlDatabase和QSqlQueryModel而 Qt 官方对 MySQL 驱动的支持在 5.15.x 分支有明确适配边界Qt 6.x 默认移除了QMYSQL插件需手动编译且与 MySQL 8.0.22 的caching_sha2_password认证插件存在兼容问题Qt 5.12.x 虽支持但QCustomPlot2.1.0 版本在高 DPI 屏幕下缩放异常导致 K 线图坐标轴错位MySQL 5.7 默认utf8字符集不支持 emoji 表情虽本项目不用但stock_db.sql中stock_info.s_name字段预留了 50 字符长度实际插入“宁德时代”等长名称时MySQL 8.0 的utf8mb4更稳妥。提示不要用 XAMPP/MAMP 一键包。它们打包的 MySQL 服务常以root无密码启动但 Qt 程序连接时若未显式指定password会触发 MySQL 8.0 的caching_sha2_password握手失败错误码2058。必须用官方 MySQL Installer 或apt install mysql-serverUbuntu/brew install mysqlmacOS安装纯净实例。2.2 MySQL 数据库初始化执行stock_db.sql前必须做的三件事解压包里的stock_db.sql是完整建库脚本但直接mysql -u root -p stock_db.sql会失败。原因在于脚本头部有两行关键语句CREATE DATABASE IF NOT EXISTS stock_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE stock_db;必须确保MySQL 服务已启动Linux 执行sudo systemctl status mysqlWindows 检查服务列表中MySQL80是否运行root 用户密码已重置为明文仅开发环境MySQL 8.0 安装后默认密码存于/etc/mysql/debian.cnfDebian或C:\ProgramData\MySQL\MySQL Server 8.0\my.iniWindows但更可靠的方式是进入安全模式重置# Linux/macOS sudo mysqld_safe --skip-grant-tables mysql -u root mysql ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456; mysql FLUSH PRIVILEGES;字符集全局生效编辑 MySQL 配置文件/etc/mysql/my.cnf或C:\ProgramData\MySQL\MySQL Server 8.0\my.ini在[mysqld]段落追加[mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci执行建库后用mysql -u root -p123456 -e SHOW CREATE TABLE trade_record;验证t_volume字段类型为DECIMAL(10,2)而非INT——这是支撑一手100股、最小变动单位0.01元的关键精度。2.3 Qt MySQL 驱动编译绑定libqsqlmysql.soLinux/qsqlmysql.dllWindows生成实录Qt Creator 默认不带 MySQL 驱动必须手动编译。本项目源码中main.cpp有硬编码连接字符串QSqlDatabase db QSqlDatabase::addDatabase(QMYSQL); db.setHostName(localhost); db.setDatabaseName(stock_db); db.setUserName(root); db.setPassword(123456); // 注意此处密码必须与上一步重置的一致若驱动缺失db.open()返回false且qDebug() db.lastError().text();输出QMYSQL driver not loaded。Linux 编译步骤Ubuntu 22.04# 1. 安装 MySQL 开发头文件 sudo apt install libmysqlclient-dev # 2. 进入 Qt MySQL 插件源码目录路径依 Qt 安装位置而定 cd /opt/Qt5.15.2/5.15.2/gcc_64/plugins/sqldrivers/ # 3. 使用 Qt 自带 qmake 生成 Makefile /opt/Qt5.15.2/5.15.2/gcc_64/bin/qmake \ INCLUDEPATH/usr/include/mysql \ LIBS-L/usr/lib/x86_64-linux-gnu -lmysqlclient \ mysql.pro # 4. 编译并复制到插件目录 make sudo cp libqsqlmysql.so /opt/Qt5.15.2/5.15.2/gcc_64/plugins/sqldrivers/Windows 编译要点Qt 5.15.2 VS2019下载 MySQL Connector/C 6.1.x不能用 8.0 版本因 ABI 不兼容在 Qt Creator 的 Kits 设置中将Qt version指向Desktop Qt 5.15.2 MSVC2019 64bitCompiler指向Microsoft Visual C Compiler 16.11编译命令中LIBS参数需指向mysqlclient.lib的绝对路径例如C:\Qt\5.15.2\msvc2019_64\bin\qmake.exe ^ INCLUDEPATHC:\mysql-connector-c-6.1.11-winx64\include ^ LIBSC:\mysql-connector-c-6.1.11-winx64\lib\mysqlclient.lib ^ mysql.pro编译成功后qsqlmysql.dll会生成在plugins/sqldrivers/目录下。验证方式在 Qt Creator 的Projects → Build Run → Run设置中添加环境变量QT_DEBUG_PLUGINS1运行程序时终端会打印所有加载的插件路径——看到Loaded library qsqlmysql即成功。3. 源码结构拆解四个核心模块如何用 C 实现股票业务逻辑闭环3.1StockDataManager不只是读取数据而是构建行情缓存与实时更新管道该类位于src/data/stockdatamanager.h承担三重职责冷启动加载首次启动时从kline_daily表批量读取近3年日线数据按stock_code分组存入QHashQString, QVectorKLineData内存缓存增量更新通过QTimer每30秒执行一次updateLatestKLine()查询SELECT * FROM kline_daily WHERE trade_date (SELECT MAX(trade_date) FROM kline_daily)避免全表扫描跨周期转换提供convertToMinuteKLine(const QString code, int minute)接口将日线数据按成交量加权合成分钟线——注意源码中KLineData结构体的volume字段是qint64类型而非int防止单日成交额超21亿手时溢出。关键代码段stockdatamanager.cppbool StockDataManager::loadDailyKLines(const QString code) { QSqlQuery query(m_db); query.prepare(SELECT trade_date, open_price, high_price, low_price, close_price, volume FROM kline_daily WHERE stock_code ? ORDER BY trade_date ASC); query.addBindValue(code); if (!query.exec()) { qWarning() Failed to load klines: query.lastError().text(); return false; } QVectorKLineData klines; while (query.next()) { KLineData k; k.tradeDate QDate::fromString(query.value(0).toString(), yyyy-MM-dd); k.openPrice query.value(1).toDouble(); k.highPrice query.value(2).toDouble(); k.lowPrice query.value(3).toDouble(); k.closePrice query.value(4).toDouble(); k.volume query.value(5).toLongLong(); // ← 关键用 toLongLong() 避免截断 klines.append(k); } m_klineCache[code] klines; return true; }注意query.value(5).toLongLong()是血泪经验——某次测试用query.value(5).toInt()读取创业板某只股票单日成交 32.7 亿手实际为 3270000000结果返回-112949331232位整数溢出导致后续 MA 计算全错。3.2PortfolioManager持仓计算不是简单加减而是 FIFO 成本法与浮动盈亏分离src/trade/portfoliomanager.h实现的是真实券商级持仓管理FIFO 成本核算buy()方法将每笔买入记录为TradeRecord对象含price,volume,timesell()时按时间顺序逐笔匹配卖出量动态计算p_cost_price浮动盈亏隔离getFloatingProfitLoss()返回当前市价与持仓成本价的差额 × 持仓量但不修改p_cost_price—— 这保证了历史成交均价的不可变性可用资金校验canBuy()检查available_funds是否 ≥price * volume * 100A股一手100股且volume % 100 0必须整手买卖。数据库表portfolio字段设计印证此逻辑字段名类型含义示例p_stock_codeVARCHAR(10)股票代码600519p_holding_volumeINT当前持有手数5即500股p_cost_priceDECIMAL(10,3)加权平均成本价1850.230p_available_volumeINT可卖出手数考虑T153.3ChartViewQCustomPlot 不是画线工具而是 K 线与指标联动引擎src/ui/chartview.cpp中replotKLine()方法做了三件事从StockDataManager获取指定股票的QVectorKLineData将KLineData映射为QCPFinancialData含open,high,low,close,timestamp动态叠加指标线若用户勾选“显示MA5”则调用calculateMA(5)计算5日均线并作为第二条曲线绘制——注意calculateMA()中使用QVectordouble存储中间值避免QVectorQCPFinancialData的内存拷贝开销。指标计算代码精简版QVectordouble ChartView::calculateMA(int days, const QVectorKLineData klines) { QVectordouble ma; ma.resize(klines.size()); for (int i 0; i klines.size(); i) { if (i days - 1) { ma[i] 0; // 未满周期置0 } else { double sum 0; for (int j 0; j days; j) { sum klines[i - j].closePrice; // ← 注意是 closePrice不是 openPrice } ma[i] sum / days; } } return ma; }提示源码中ma[i] sum / days未做std::round()保留小数精度。这是刻意为之——实盘系统中均线需参与后续交叉判断如ma5 ma10浮点精度丢失会导致误触发。3.4TradeExecutor模拟撮合不是随机生成而是遵循价格优先、时间优先原则src/trade/tradeexecutor.cpp的executeOrder()方法模拟 A 股连续竞价规则买盘匹配查找kline_daily表中close_price≤order.price的最新记录取其close_price作为成交价卖盘匹配查找close_price≥order.price的记录同样取close_price失败处理若无匹配价格订单进入pending_orders队列下次updateLatestKLine()后重试——这模拟了真实挂单等待过程。数据库trade_record表的t_status字段定义了三种状态0已成交t_executed_time有值1已撤单t_cancel_time有值2待成交t_status 2 AND t_executed_time IS NULL4. 避坑指南五个高频翻车点与对应后悔药4.1 现象Qt 程序启动后界面空白控制台无报错QCustomPlot区域显示灰色方块原因QCustomPlot的replot()被调用时QVectorKLineData为空但绘图区域未设置setNoAntialiasing(true)导致 OpenGL 渲染器在空数据下崩溃尤其 macOS。解决在ChartView::replotKLine()开头添加判空保护if (klines.isEmpty()) { ui-customPlot-clearPlottables(); ui-customPlot-clearItems(); ui-customPlot-replot(); return; }4.2 现象点击“买入”按钮后portfolio表中p_holding_volume增加但p_cost_price变成0.000原因PortfolioManager::buy()中新买入记录的price传入为0.0因 UI 输入框未校验非空导致p_cost_price (old_cost * old_vol 0 * new_vol) / (old_vol new_vol)恒为0。解决在buy()方法开头强制校验if (qFuzzyCompare(price, 0.0)) { qWarning() Invalid buy price: price; return false; }4.3 现象MySQL 连接成功但SELECT * FROM kline_daily返回空结果QSqlQuery::size()为-1原因MySQL 8.0 默认开启sql_mode ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,...而stock_db.sql中部分INSERT语句未显式指定所有字段如INSERT INTO kline_daily VALUES (...)触发严格模式拒绝插入。解决执行SET GLOBAL sql_mode STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE;或修改my.cnf中sql_mode值重启 MySQL。4.4 现象Windows 下编译qsqlmysql.dll成功但运行时报错The procedure entry point mysql_options_ex could not be located in the dynamic link library libmysql.dll原因Qt 编译时链接的libmysql.dll版本Connector/C 6.1.11与运行时PATH中的libmysql.dll可能来自 MySQL Server 8.0 安装目录不一致函数签名变更导致符号找不到。解决将编译时使用的mysqlclient.lib对应的libmysql.dll位于C:\mysql-connector-c-6.1.11-winx64\lib\复制到 Qt 程序的.exe同目录下而非系统PATH目录。4.5 现象QSqlQueryModel绑定到QTableView后中文列标题显示为方块原因Qt 默认字体不支持中文且QTableView未设置setFont()。解决在main.cpp创建QApplication后立即设置全局字体QFont font(Microsoft YaHei, 9); font.setStyleStrategy(QFont::PreferAntialias); QApplication::setFont(font);5. 进阶技巧用三步验证法确认系统业务逻辑正确性避免“能跑≠能用”5.1 第一步用预置测试数据触发盈亏计算链路源码包中test_data/目录包含test_portfolio.sql和test_kline.sql它们不是示例而是经过人工核验的黄金测试集。执行以下操作清空原portfolio表TRUNCATE TABLE portfolio;导入测试持仓mysql -u root -p123456 stock_db test_data/test_portfolio.sql导入测试K线mysql -u root -p123456 stock_db test_data/test_kline.sql此时portfolio表中有一条记录p_stock_code000001, p_holding_volume10, p_cost_price12.500。而kline_daily中000001的最新close_price13.20。启动程序进入“持仓”页签应显示当前市值13.20 × 10 × 100 13200.00元浮动盈亏(13.20 - 12.50) × 10 × 100 700.00元若数值不符立刻检查PortfolioManager::getFloatingProfitLoss()中是否误用了p_holding_volume手数而非p_holding_volume * 100股数。5.2 第二步用 SQL 直接比对trade_record与portfolio的一致性真实系统中成交记录与持仓必须满足SUM(CASE WHEN t_directionBUY THEN t_volume ELSE 0 END) - SUM(CASE WHEN t_directionSELL THEN t_volume ELSE 0 END) p_holding_volume执行以下 SQL 验证SELECT t.t_stock_code, SUM(CASE WHEN t.t_directionBUY THEN t.t_volume ELSE 0 END) - SUM(CASE WHEN t.t_directionSELL THEN t.t_volume ELSE 0 END) AS calc_volume, p.p_holding_volume AS actual_volume FROM trade_record t JOIN portfolio p ON t.t_stock_code p.p_stock_code GROUP BY t.t_stock_code, p.p_holding_volume;若calc_volume ≠ actual_volume说明TradeExecutor的撮合逻辑或PortfolioManager的更新逻辑存在漏更新。5.3 第三步用QTest框架编写单元测试覆盖 MA 计算边界源码未自带单元测试但你可以快速补上test_ma_calculation.cpp#include QtTest #include chartview.h class TestMACalculation : public QObject { Q_OBJECT private slots: void testEmptyInput() { QVectorKLineData empty; QVectordouble result ChartView::calculateMA(5, empty); QVERIFY(result.isEmpty()); } void testInsufficientData() { QVectorKLineData data {{QDate(2023,1,1), 10,12,9,11,1000}}; QVectordouble result ChartView::calculateMA(5, data); QCOMPARE(result.size(), 1); QCOMPARE(result[0], 0.0); // 未满5日应为0 } void testExactFiveDays() { QVectorKLineData data; for (int i 0; i 5; i) { KLineData k; k.closePrice 10.0 i * 0.1; // 10.0, 10.1, 10.2, 10.3, 10.4 data.append(k); } QVectordouble result ChartView::calculateMA(5, data); QCOMPARE(result.size(), 5); QCOMPARE(result[4], 10.2); // (10.010.110.210.310.4)/5 10.2 } };在.pro文件中添加TESTCASE test_ma_calculation运行./stock_system_test -test即可验证指标计算鲁棒性。从那以后我每次拿到一个标着“毕业设计”的 Qt 项目第一件事就是打开stock_db.sql查CHARACTER SET第二件事是 grepQSqlDatabase::addDatabase看驱动名第三件事是找main.cpp里QApplication::exec()上方有没有QFont设置——这三步做完80% 的“打不开”问题当场消失。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网