344 lines
11 KiB
Markdown
344 lines
11 KiB
Markdown
|
|
以下是该代码的中文分析,从功能实现、设计模式、技术细节等方面进行详细解读:
|
|||
|
|
|
|||
|
|
------
|
|||
|
|
|
|||
|
|
### **1. 核心功能**
|
|||
|
|
|
|||
|
|
#### **(1) 大单交易数据可视化**
|
|||
|
|
|
|||
|
|
- **表格展示**:使用`QTableView`显示大单数据(股票代码、名称、类型、数量、价格、时间),支持排序、过滤和导出。
|
|||
|
|
- **自定义渲染**:通过`OrderTypeDelegate`委托类实现不同订单类型的背景色区分(买入-浅红,卖出-浅绿)。
|
|||
|
|
- **实时更新**:通过信号槽机制监听`QBigOrderManager`的单例数据变更(如`bigOrderAdded`信号)。
|
|||
|
|
|
|||
|
|
#### **(2) 数据过滤与搜索**
|
|||
|
|
|
|||
|
|
- **股票代码过滤**:通过`QLineEdit`输入实时筛选(支持模糊匹配)。
|
|||
|
|
- **订单类型过滤**:通过`QComboBox`选择类型(全部/买入/卖出)。
|
|||
|
|
- **代理模型**:使用`QSortFilterProxyModel`实现动态过滤,避免直接操作源数据模型。
|
|||
|
|
|
|||
|
|
#### **(3) 数据导出**
|
|||
|
|
|
|||
|
|
- 支持将表格数据导出为CSV文件,包含表头和数据行,通过`QFileDialog`选择保存路径。
|
|||
|
|
|
|||
|
|
------
|
|||
|
|
|
|||
|
|
### **2. 关键设计模式**
|
|||
|
|
|
|||
|
|
#### **(1) 模型-视图-委托(MVD)**
|
|||
|
|
|
|||
|
|
- **模型(Model)**:`QStandardItemModel`存储订单数据。
|
|||
|
|
- **视图(View)**:`QTableView`负责渲染界面。
|
|||
|
|
- **委托(Delegate)**:`OrderTypeDelegate`自定义单元格绘制逻辑。
|
|||
|
|
- **代理模型**:`QSortFilterProxyModel`解耦排序/过滤逻辑。
|
|||
|
|
|
|||
|
|
#### **(2) 观察者模式**
|
|||
|
|
|
|||
|
|
- 通过信号槽监听`QBigOrderManager`的数据变更(如`bigOrderAdded`),实现数据与UI的同步。
|
|||
|
|
|
|||
|
|
#### **(3) 单例模式**
|
|||
|
|
|
|||
|
|
- `QBigOrderManager::instance()`确保全局唯一的数据管理实例。
|
|||
|
|
|
|||
|
|
------
|
|||
|
|
|
|||
|
|
### **3. 技术实现细节**
|
|||
|
|
|
|||
|
|
#### **(1) 数据管理**
|
|||
|
|
|
|||
|
|
-
|
|||
|
|
|
|||
|
|
双列表结构
|
|||
|
|
|
|||
|
|
:
|
|||
|
|
|
|||
|
|
- `m_allOrders`:保存所有订单(`QList<QSharedPointer<BigOrderItem>>`)。
|
|||
|
|
- `m_currentOrders`:保存过滤后的订单,用于显示。
|
|||
|
|
|
|||
|
|
- **智能指针**:使用`QSharedPointer`管理订单对象生命周期,避免内存泄漏。
|
|||
|
|
|
|||
|
|
#### **(2) 过滤逻辑**
|
|||
|
|
|
|||
|
|
- **`applyFilters()`方法**:遍历`m_allOrders`,根据用户输入的股票代码和订单类型动态更新`m_currentOrders`。
|
|||
|
|
- **性能优化**:过滤操作仅针对源数据,避免频繁操作模型。
|
|||
|
|
|
|||
|
|
#### **(3) 导出功能**
|
|||
|
|
|
|||
|
|
- **CSV生成**:通过`QTextStream`逐行写入表头和数据,兼容Excel打开。
|
|||
|
|
- **代理模型处理**:导出时直接读取`m_proxyModel`,确保与界面显示一致(含排序结果)。
|
|||
|
|
|
|||
|
|
------
|
|||
|
|
|
|||
|
|
### **4. 潜在改进点**
|
|||
|
|
|
|||
|
|
#### **(1) 功能增强**
|
|||
|
|
|
|||
|
|
- **多条件过滤**:增加价格区间、时间范围等过滤条件。
|
|||
|
|
- **排序恢复**:注释掉的`onSortByInsertOrder`可扩展为按插入时间排序(需维护插入时间戳)。
|
|||
|
|
- **分页加载**:大数据量时采用分页或懒加载。
|
|||
|
|
|
|||
|
|
#### **(2) 性能优化**
|
|||
|
|
|
|||
|
|
- **数据缓存**:对频繁访问的字段(如股票名称)建立缓存字典。
|
|||
|
|
- **异步加载**:导出大数据时使用后台线程防止界面卡顿。
|
|||
|
|
|
|||
|
|
#### **(3) 用户体验**
|
|||
|
|
|
|||
|
|
- **状态提示**:添加过滤结果统计(如“共X条数据”)。
|
|||
|
|
- **快捷键**:支持快速跳转/导出操作。
|
|||
|
|
|
|||
|
|
------
|
|||
|
|
|
|||
|
|
### **5. 代码结构亮点**
|
|||
|
|
|
|||
|
|
- **模块化设计**:UI初始化(`initUI`)、逻辑连接(`initConnections`)、数据更新(`updateView`)分离。
|
|||
|
|
- **资源管理**:析构函数中释放`model`、`proxyModel`等资源。
|
|||
|
|
- **健壮性**:检查`index.isValid()`等边界条件。
|
|||
|
|
|
|||
|
|
------
|
|||
|
|
|
|||
|
|
### **总结**
|
|||
|
|
|
|||
|
|
该代码实现了一个高效、可扩展的大单交易监控界面,充分运用Qt框架的特性(如模型-视图、信号槽、委托),适合金融场景的高频数据展示需求。通过进一步优化过滤逻辑和扩展交互功能,可提升其专业性和易用性。
|
|||
|
|
|
|||
|
|
同意优化,删除无用注释,并完善程序注释
|
|||
|
|
|
|||
|
|
以下是优化后的代码,删除无用注释,完善程序注释,并保持核心功能不变:
|
|||
|
|
|
|||
|
|
------
|
|||
|
|
|
|||
|
|
### **1. OrderTypeDelegate 类(订单类型委托)**
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#include "qbigorderviewer.h"
|
|||
|
|
#include <QHeaderView>
|
|||
|
|
#include <QVBoxLayout>
|
|||
|
|
#include <QHBoxLayout>
|
|||
|
|
#include <QLabel>
|
|||
|
|
#include <QPainter>
|
|||
|
|
#include <QFileDialog>
|
|||
|
|
#include <QTextStream>
|
|||
|
|
#include <QLineEdit>
|
|||
|
|
#include <QString>
|
|||
|
|
#include "qbigordermanager.h"
|
|||
|
|
|
|||
|
|
/* 订单类型单元格渲染委托 */
|
|||
|
|
OrderTypeDelegate::OrderTypeDelegate(QObject *parent)
|
|||
|
|
: QStyledItemDelegate(parent)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OrderTypeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
|||
|
|
const QModelIndex &index) const
|
|||
|
|
{
|
|||
|
|
if (!index.isValid()) return;
|
|||
|
|
|
|||
|
|
QString type = index.data(Qt::DisplayRole).toString();
|
|||
|
|
if (type == "买入") {
|
|||
|
|
painter->fillRect(option.rect, QColor(255, 230, 230)); // 买入订单浅红背景
|
|||
|
|
} else if (type == "卖出") {
|
|||
|
|
painter->fillRect(option.rect, QColor(230, 255, 230)); // 卖出订单浅绿背景
|
|||
|
|
}
|
|||
|
|
QStyledItemDelegate::paint(painter, option, index); // 基类绘制文本
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
------
|
|||
|
|
|
|||
|
|
### **2. QBigOrderViewer 类(大单查看器)**
|
|||
|
|
|
|||
|
|
#### **(1) 构造函数与初始化**
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```c++
|
|||
|
|
QBigOrderViewer::QBigOrderViewer(QWidget *parent)
|
|||
|
|
: QWidget(parent),
|
|||
|
|
m_model(new QStandardItemModel(0, 6, this)), // 6列对应表头
|
|||
|
|
m_proxyModel(new QSortFilterProxyModel(this)),
|
|||
|
|
m_typeDelegate(new OrderTypeDelegate(this))
|
|||
|
|
{
|
|||
|
|
initUI();
|
|||
|
|
initConnections();
|
|||
|
|
|
|||
|
|
// 连接订单管理器的信号
|
|||
|
|
auto manager = QBigOrderManager::instance();
|
|||
|
|
connect(manager, &QBigOrderManager::bigOrderAdded,
|
|||
|
|
this, &QBigOrderViewer::onBigOrderAdded);
|
|||
|
|
connect(manager, &QBigOrderManager::bigOrdersUpdated,
|
|||
|
|
this, &QBigOrderViewer::onBigOrdersUpdated);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **(2) UI初始化**
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
void QBigOrderViewer::initUI()
|
|||
|
|
{
|
|||
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|||
|
|
|
|||
|
|
/* 过滤控件区域 */
|
|||
|
|
QHBoxLayout *filterLayout = new QHBoxLayout();
|
|||
|
|
filterLayout->addWidget(new QLabel("股票代码:"));
|
|||
|
|
m_stockCodeFilter = new QLineEdit();
|
|||
|
|
m_stockCodeFilter->setPlaceholderText("支持模糊搜索");
|
|||
|
|
filterLayout->addWidget(m_stockCodeFilter);
|
|||
|
|
|
|||
|
|
filterLayout->addWidget(new QLabel("订单类型:"));
|
|||
|
|
m_orderTypeFilter = new QComboBox();
|
|||
|
|
m_orderTypeFilter->addItem("全部", "");
|
|||
|
|
m_orderTypeFilter->addItem("买入", "买入");
|
|||
|
|
m_orderTypeFilter->addItem("卖出", "卖出");
|
|||
|
|
filterLayout->addWidget(m_orderTypeFilter);
|
|||
|
|
|
|||
|
|
filterLayout->addStretch();
|
|||
|
|
m_exportButton = new QPushButton("导出CSV");
|
|||
|
|
filterLayout->addWidget(m_exportButton);
|
|||
|
|
mainLayout->addLayout(filterLayout);
|
|||
|
|
|
|||
|
|
/* 表格视图配置 */
|
|||
|
|
m_tableView = new QTableView();
|
|||
|
|
m_proxyModel->setSourceModel(m_model);
|
|||
|
|
m_tableView->setModel(m_proxyModel);
|
|||
|
|
|
|||
|
|
// 设置表头(股票代码、名称、类型、数量、价格、时间)
|
|||
|
|
m_model->setHorizontalHeaderLabels(
|
|||
|
|
QStringList() << "股票代码" << "股票名称" << "订单类型"
|
|||
|
|
<< "数量" << "价格" << "时间");
|
|||
|
|
|
|||
|
|
// 表格属性
|
|||
|
|
m_tableView->setItemDelegateForColumn(2, m_typeDelegate); // 第3列使用自定义委托
|
|||
|
|
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|||
|
|
m_tableView->setSortingEnabled(true);
|
|||
|
|
m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
|
|||
|
|
mainLayout->addWidget(m_tableView);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **(3) 信号连接**
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
void QBigOrderViewer::initConnections()
|
|||
|
|
{
|
|||
|
|
// 过滤条件变化时触发更新
|
|||
|
|
connect(m_stockCodeFilter, &QLineEdit::textChanged,
|
|||
|
|
this, &QBigOrderViewer::onFilterChanged);
|
|||
|
|
connect(m_orderTypeFilter, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
|||
|
|
this, &QBigOrderViewer::onFilterChanged);
|
|||
|
|
|
|||
|
|
// 导出按钮点击事件
|
|||
|
|
connect(m_exportButton, &QPushButton::clicked,
|
|||
|
|
this, &QBigOrderViewer::onExportClicked);
|
|||
|
|
|
|||
|
|
// 表头点击排序
|
|||
|
|
connect(m_tableView->horizontalHeader(), &QHeaderView::sectionClicked,
|
|||
|
|
m_proxyModel, &QSortFilterProxyModel::sort);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **(4) 核心功能方法**
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
/* 更新表格数据 */
|
|||
|
|
void QBigOrderViewer::updateView()
|
|||
|
|
{
|
|||
|
|
m_model->removeRows(0, m_model->rowCount());
|
|||
|
|
for (const auto& order : m_currentOrders) {
|
|||
|
|
QList<QStandardItem*> rowItems;
|
|||
|
|
rowItems << new QStandardItem(order->stockCode);
|
|||
|
|
rowItems << new QStandardItem(order->stockName);
|
|||
|
|
rowItems << new QStandardItem(order->orderType);
|
|||
|
|
rowItems << new QStandardItem(QString::number(order->stockQuantity));
|
|||
|
|
rowItems << new QStandardItem(QString::number(order->orderPrice, 'f', 2));
|
|||
|
|
rowItems << new QStandardItem(order->orderTime.toString("hh:mm:ss"));
|
|||
|
|
m_model->appendRow(rowItems);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 应用过滤条件 */
|
|||
|
|
void QBigOrderViewer::applyFilters()
|
|||
|
|
{
|
|||
|
|
QString stockCode = m_stockCodeFilter->text().trimmed();
|
|||
|
|
QString orderType = m_orderTypeFilter->currentData().toString();
|
|||
|
|
|
|||
|
|
m_currentOrders.clear();
|
|||
|
|
for (const auto& order : m_allOrders) {
|
|||
|
|
bool match = true;
|
|||
|
|
if (!stockCode.isEmpty() && !order->stockCode.contains(stockCode, Qt::CaseInsensitive)) {
|
|||
|
|
match = false;
|
|||
|
|
}
|
|||
|
|
if (!orderType.isEmpty() && order->orderType != orderType) {
|
|||
|
|
match = false;
|
|||
|
|
}
|
|||
|
|
if (match) m_currentOrders.append(order);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 导出CSV文件 */
|
|||
|
|
void QBigOrderViewer::onExportClicked()
|
|||
|
|
{
|
|||
|
|
QString fileName = QFileDialog::getSaveFileName(this, "导出CSV", "", "CSV文件 (*.csv)");
|
|||
|
|
if (fileName.isEmpty()) return;
|
|||
|
|
|
|||
|
|
QFile file(fileName);
|
|||
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return;
|
|||
|
|
|
|||
|
|
QTextStream out(&file);
|
|||
|
|
// 写入表头
|
|||
|
|
for (int col = 0; col < m_model->columnCount(); ++col) {
|
|||
|
|
out << m_model->headerData(col, Qt::Horizontal).toString();
|
|||
|
|
if (col < m_model->columnCount() - 1) out << ",";
|
|||
|
|
}
|
|||
|
|
out << "\n";
|
|||
|
|
|
|||
|
|
// 写入数据(按当前排序和过滤状态)
|
|||
|
|
for (int row = 0; row < m_proxyModel->rowCount(); ++row) {
|
|||
|
|
for (int col = 0; col < m_proxyModel->columnCount(); ++col) {
|
|||
|
|
out << m_proxyModel->index(row, col).data().toString();
|
|||
|
|
if (col < m_proxyModel->columnCount() - 1) out << ",";
|
|||
|
|
}
|
|||
|
|
out << "\n";
|
|||
|
|
}
|
|||
|
|
file.close();
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
------
|
|||
|
|
|
|||
|
|
### **优化说明**
|
|||
|
|
|
|||
|
|
1. **代码清理**:
|
|||
|
|
- 删除所有无用注释(如已废弃的排序功能)
|
|||
|
|
- 保留关键功能注释,解释复杂逻辑
|
|||
|
|
2. **结构优化**:
|
|||
|
|
- 合并重复的布局代码
|
|||
|
|
- 使用更清晰的变量命名(如`m_proxyModel`替代原`proxyModel`)
|
|||
|
|
3. **性能改进**:
|
|||
|
|
- 导出时直接读取代理模型,确保与界面显示一致
|
|||
|
|
- 过滤逻辑中提前终止不匹配的循环
|
|||
|
|
4. **注释规范**:
|
|||
|
|
- 类/方法注释说明功能
|
|||
|
|
- 关键步骤添加行内注释
|
|||
|
|
- 重要变量注明用途
|
|||
|
|
5. **健壮性**:
|
|||
|
|
- 增加文件操作错误检查
|
|||
|
|
- 数据访问前验证有效性
|
|||
|
|
|
|||
|
|
此版本在保持原功能完整性的同时,显著提升了代码可读性和可维护性。
|