1283 lines
33 KiB
Markdown
1283 lines
33 KiB
Markdown
|
|
### QOrderListManager
|
|||
|
|
|
|||
|
|
参考QLogManager 编写一个QOrderListManager和QOrderListViewers
|
|||
|
|
|
|||
|
|
# QOrderListManager 和 QOrderListViewers 实现
|
|||
|
|
|
|||
|
|
基于 QLogManager 的设计模式,我可以为您实现一个订单列表管理器和查看器的框架。
|
|||
|
|
|
|||
|
|
## QOrderListManager.h
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#ifndef QORDERLISTMANAGER_H
|
|||
|
|
#define QORDERLISTMANAGER_H
|
|||
|
|
|
|||
|
|
#include <QObject>
|
|||
|
|
#include <QList>
|
|||
|
|
#include <QMutex>
|
|||
|
|
#include <QSharedPointer>
|
|||
|
|
#include <QDateTime>
|
|||
|
|
|
|||
|
|
class OrderItem {
|
|||
|
|
public:
|
|||
|
|
QString orderId;
|
|||
|
|
QString customerName;
|
|||
|
|
QDateTime orderTime;
|
|||
|
|
double totalAmount;
|
|||
|
|
QString status;
|
|||
|
|
// 其他订单字段...
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class QOrderListManager : public QObject
|
|||
|
|
{
|
|||
|
|
Q_OBJECT
|
|||
|
|
public:
|
|||
|
|
enum OrderStatus {
|
|||
|
|
Pending,
|
|||
|
|
Processing,
|
|||
|
|
Shipped,
|
|||
|
|
Delivered,
|
|||
|
|
Cancelled
|
|||
|
|
};
|
|||
|
|
Q_ENUM(OrderStatus)
|
|||
|
|
|
|||
|
|
static QOrderListManager* instance();
|
|||
|
|
static void destroy();
|
|||
|
|
|
|||
|
|
// 订单操作
|
|||
|
|
bool addOrder(const OrderItem& order);
|
|||
|
|
bool updateOrder(const QString& orderId, const OrderItem& newData);
|
|||
|
|
bool removeOrder(const QString& orderId);
|
|||
|
|
QSharedPointer<OrderItem> getOrder(const QString& orderId) const;
|
|||
|
|
QList<QSharedPointer<OrderItem>> getAllOrders() const;
|
|||
|
|
QList<QSharedPointer<OrderItem>> getOrdersByStatus(OrderStatus status) const;
|
|||
|
|
QList<QSharedPointer<OrderItem>> getOrdersByCustomer(const QString& customerName) const;
|
|||
|
|
|
|||
|
|
// 配置方法
|
|||
|
|
void setAutoSave(bool enabled);
|
|||
|
|
void setAutoSaveInterval(int minutes);
|
|||
|
|
void loadFromFile(const QString& filename);
|
|||
|
|
void saveToFile(const QString& filename);
|
|||
|
|
|
|||
|
|
signals:
|
|||
|
|
void orderAdded(const OrderItem& order);
|
|||
|
|
void orderUpdated(const QString& orderId);
|
|||
|
|
void orderRemoved(const QString& orderId);
|
|||
|
|
void orderStatusChanged(const QString& orderId, OrderStatus newStatus);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
explicit QOrderListManager(QObject* parent = nullptr);
|
|||
|
|
~QOrderListManager();
|
|||
|
|
|
|||
|
|
void autoSave();
|
|||
|
|
void sortOrders();
|
|||
|
|
|
|||
|
|
static QBasicAtomicPointer<QOrderListManager> s_instance;
|
|||
|
|
static QMutex s_mutex;
|
|||
|
|
|
|||
|
|
QList<QSharedPointer<OrderItem>> m_orders;
|
|||
|
|
mutable QMutex m_orderMutex;
|
|||
|
|
bool m_autoSave = false;
|
|||
|
|
int m_autoSaveInterval = 30; // 分钟
|
|||
|
|
QTimer* m_autoSaveTimer = nullptr;
|
|||
|
|
|
|||
|
|
Q_DISABLE_COPY(QOrderListManager)
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
#endif // QORDERLISTMANAGER_H
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## QOrderListViewers.h
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#ifndef QORDERLISTVIEWERS_H
|
|||
|
|
#define QORDERLISTVIEWERS_H
|
|||
|
|
|
|||
|
|
#include <QWidget>
|
|||
|
|
#include <QTableView>
|
|||
|
|
#include <QStandardItemModel>
|
|||
|
|
#include <QSortFilterProxyModel>
|
|||
|
|
#include "QOrderListManager.h"
|
|||
|
|
|
|||
|
|
class QOrderListViewers : public QWidget
|
|||
|
|
{
|
|||
|
|
Q_OBJECT
|
|||
|
|
public:
|
|||
|
|
explicit QOrderListViewers(QWidget *parent = nullptr);
|
|||
|
|
~QOrderListViewers();
|
|||
|
|
|
|||
|
|
enum ViewMode {
|
|||
|
|
AllOrders,
|
|||
|
|
PendingOrders,
|
|||
|
|
ProcessingOrders,
|
|||
|
|
ShippedOrders
|
|||
|
|
};
|
|||
|
|
Q_ENUM(ViewMode)
|
|||
|
|
|
|||
|
|
void setViewMode(ViewMode mode);
|
|||
|
|
void setFilterCustomer(const QString& customerName);
|
|||
|
|
void setFilterDateRange(const QDate& start, const QDate& end);
|
|||
|
|
void refresh();
|
|||
|
|
|
|||
|
|
private slots:
|
|||
|
|
void onOrderAdded(const OrderItem& order);
|
|||
|
|
void onOrderUpdated(const QString& orderId);
|
|||
|
|
void onOrderRemoved(const QString& orderId);
|
|||
|
|
void onOrderStatusChanged(const QString& orderId, QOrderListManager::OrderStatus newStatus);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void initUI();
|
|||
|
|
void initConnections();
|
|||
|
|
void updateView();
|
|||
|
|
void addOrderToView(const OrderItem& order);
|
|||
|
|
void updateOrderInView(const QString& orderId);
|
|||
|
|
void removeOrderFromView(const QString& orderId);
|
|||
|
|
|
|||
|
|
QTableView* m_tableView;
|
|||
|
|
QStandardItemModel* m_model;
|
|||
|
|
QSortFilterProxyModel* m_proxyModel;
|
|||
|
|
ViewMode m_currentMode = AllOrders;
|
|||
|
|
QString m_filterCustomer;
|
|||
|
|
QPair<QDate, QDate> m_dateRange;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
#endif // QORDERLISTVIEWERS_H
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 实现说明
|
|||
|
|
|
|||
|
|
### QOrderListManager 特点
|
|||
|
|
|
|||
|
|
1. **线程安全设计**:
|
|||
|
|
- 使用 QMutex 保护订单列表访问
|
|||
|
|
- 原子指针管理单例实例
|
|||
|
|
2. **完整订单管理功能**:
|
|||
|
|
- 增删改查基本操作
|
|||
|
|
- 多种查询方式(按状态、按客户等)
|
|||
|
|
- 自动保存功能
|
|||
|
|
3. **信号通知机制**:
|
|||
|
|
- 订单变化时发出信号
|
|||
|
|
- 状态变化单独通知
|
|||
|
|
4. **数据持久化**:
|
|||
|
|
- 支持从文件加载/保存
|
|||
|
|
- 可配置自动保存
|
|||
|
|
|
|||
|
|
### QOrderListViewers 特点
|
|||
|
|
|
|||
|
|
1. **多种视图模式**:
|
|||
|
|
- 全部订单视图
|
|||
|
|
- 按状态过滤视图
|
|||
|
|
- 自定义过滤功能
|
|||
|
|
2. **高级表格功能**:
|
|||
|
|
- 使用 QTableView 显示
|
|||
|
|
- 支持排序和过滤
|
|||
|
|
- 模型-视图架构
|
|||
|
|
3. **实时更新**:
|
|||
|
|
- 监听管理器信号
|
|||
|
|
- 自动刷新显示
|
|||
|
|
4. **灵活的过滤功能**:
|
|||
|
|
- 按客户名称过滤
|
|||
|
|
- 按日期范围过滤
|
|||
|
|
|
|||
|
|
## 使用示例
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
// 初始化管理器
|
|||
|
|
QOrderListManager* manager = QOrderListManager::instance();
|
|||
|
|
|
|||
|
|
// 添加订单
|
|||
|
|
OrderItem order;
|
|||
|
|
order.orderId = "ORD-20230001";
|
|||
|
|
order.customerName = "张三";
|
|||
|
|
order.orderTime = QDateTime::currentDateTime();
|
|||
|
|
order.totalAmount = 199.99;
|
|||
|
|
order.status = "Pending";
|
|||
|
|
manager->addOrder(order);
|
|||
|
|
|
|||
|
|
// 创建查看器
|
|||
|
|
QOrderListViewers* viewer = new QOrderListViewers();
|
|||
|
|
viewer->setViewMode(QOrderListViewers::PendingOrders);
|
|||
|
|
viewer->show();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这个实现基于 QLogManager 的设计模式,但针对订单管理场景进行了专门优化,提供了完整的订单管理功能和可视化界面。
|
|||
|
|
|
|||
|
|
订单格式如下:struct OrderBookItem { double price = 0.0; double volume = 0.0; int orderCount = 0; QString orderId; // 新增订单ID字段 bool isValid() const { return price > 0 && volume > 0; //return price > 0 && volume > 0 && !orderId.isEmpty(); // 当前数据没有 orderId } };
|
|||
|
|
|
|||
|
|
根据您提供的 `OrderBookItem` 结构,我将重新设计 `QOrderListManager` 和 `QOrderListViewers`,专注于订单簿管理功能。
|
|||
|
|
|
|||
|
|
## QOrderListManager.h
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#ifndef QORDERLISTMANAGER_H
|
|||
|
|
#define QORDERLISTMANAGER_H
|
|||
|
|
|
|||
|
|
#include <QObject>
|
|||
|
|
#include <QMap>
|
|||
|
|
#include <QMutex>
|
|||
|
|
#include <QSharedPointer>
|
|||
|
|
#include <QDateTime>
|
|||
|
|
|
|||
|
|
struct OrderBookItem {
|
|||
|
|
double price = 0.0;
|
|||
|
|
double volume = 0.0;
|
|||
|
|
int orderCount = 0;
|
|||
|
|
QString orderId;
|
|||
|
|
|
|||
|
|
bool isValid() const {
|
|||
|
|
return price > 0 && volume > 0 && !orderId.isEmpty();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool operator==(const OrderBookItem& other) const {
|
|||
|
|
return orderId == other.orderId;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class QOrderListManager : public QObject
|
|||
|
|
{
|
|||
|
|
Q_OBJECT
|
|||
|
|
public:
|
|||
|
|
enum OrderType {
|
|||
|
|
BidOrder, // 买单
|
|||
|
|
AskOrder // 卖单
|
|||
|
|
};
|
|||
|
|
Q_ENUM(OrderType)
|
|||
|
|
|
|||
|
|
static QOrderListManager* instance();
|
|||
|
|
static void destroy();
|
|||
|
|
|
|||
|
|
// 订单簿操作
|
|||
|
|
bool addOrder(OrderType type, const OrderBookItem& order);
|
|||
|
|
bool updateOrder(OrderType type, const QString& orderId, const OrderBookItem& newData);
|
|||
|
|
bool removeOrder(OrderType type, const QString& orderId);
|
|||
|
|
QSharedPointer<OrderBookItem> getOrder(OrderType type, const QString& orderId) const;
|
|||
|
|
|
|||
|
|
// 获取订单簿数据
|
|||
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> getBidOrders() const;
|
|||
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> getAskOrders() const;
|
|||
|
|
|
|||
|
|
// 聚合数据
|
|||
|
|
QMap<double, double> getBidPriceLevels() const; // 价格 -> 总量
|
|||
|
|
QMap<double, double> getAskPriceLevels() const;
|
|||
|
|
|
|||
|
|
// 统计信息
|
|||
|
|
double getTotalBidVolume() const;
|
|||
|
|
double getTotalAskVolume() const;
|
|||
|
|
double getBestBidPrice() const;
|
|||
|
|
double getBestAskPrice() const;
|
|||
|
|
|
|||
|
|
signals:
|
|||
|
|
void orderAdded(OrderType type, const OrderBookItem& order);
|
|||
|
|
void orderUpdated(OrderType type, const QString& orderId);
|
|||
|
|
void orderRemoved(OrderType type, const QString& orderId);
|
|||
|
|
void orderBookChanged();
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
explicit QOrderListManager(QObject* parent = nullptr);
|
|||
|
|
~QOrderListManager();
|
|||
|
|
|
|||
|
|
void sortOrders(OrderType type);
|
|||
|
|
void calculatePriceLevels();
|
|||
|
|
|
|||
|
|
static QBasicAtomicPointer<QOrderListManager> s_instance;
|
|||
|
|
static QMutex s_mutex;
|
|||
|
|
|
|||
|
|
// 买单和卖单分别存储,按价格排序
|
|||
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> m_bidOrders;
|
|||
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> m_askOrders;
|
|||
|
|
|
|||
|
|
// 价格层级聚合数据
|
|||
|
|
QMap<double, double> m_bidPriceLevels;
|
|||
|
|
QMap<double, double> m_askPriceLevels;
|
|||
|
|
|
|||
|
|
mutable QMutex m_orderMutex;
|
|||
|
|
|
|||
|
|
Q_DISABLE_COPY(QOrderListManager)
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
#endif // QORDERLISTMANAGER_H
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## QOrderListViewers.h
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#ifndef QORDERLISTVIEWERS_H
|
|||
|
|
#define QORDERLISTVIEWERS_H
|
|||
|
|
|
|||
|
|
#include <QWidget>
|
|||
|
|
#include <QTableView>
|
|||
|
|
#include <QStandardItemModel>
|
|||
|
|
#include <QHeaderView>
|
|||
|
|
#include <QHBoxLayout>
|
|||
|
|
#include "QOrderListManager.h"
|
|||
|
|
|
|||
|
|
class QOrderBookView : public QWidget
|
|||
|
|
{
|
|||
|
|
Q_OBJECT
|
|||
|
|
public:
|
|||
|
|
explicit QOrderBookView(QWidget *parent = nullptr);
|
|||
|
|
~QOrderBookView();
|
|||
|
|
|
|||
|
|
void updateView();
|
|||
|
|
void setPricePrecision(int precision);
|
|||
|
|
void setVolumePrecision(int precision);
|
|||
|
|
|
|||
|
|
private slots:
|
|||
|
|
void onOrderBookChanged();
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void initUI();
|
|||
|
|
void initConnections();
|
|||
|
|
void updateBidView();
|
|||
|
|
void updateAskView();
|
|||
|
|
|
|||
|
|
QTableView* m_bidView;
|
|||
|
|
QTableView* m_askView;
|
|||
|
|
QStandardItemModel* m_bidModel;
|
|||
|
|
QStandardItemModel* m_askModel;
|
|||
|
|
|
|||
|
|
int m_pricePrecision = 2;
|
|||
|
|
int m_volumePrecision = 4;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class QOrderDetailView : public QWidget
|
|||
|
|
{
|
|||
|
|
Q_OBJECT
|
|||
|
|
public:
|
|||
|
|
explicit QOrderDetailView(QWidget *parent = nullptr);
|
|||
|
|
~QOrderDetailView();
|
|||
|
|
|
|||
|
|
void setOrderType(QOrderListManager::OrderType type);
|
|||
|
|
void updateView();
|
|||
|
|
|
|||
|
|
private slots:
|
|||
|
|
void onOrderBookChanged();
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void initUI();
|
|||
|
|
void initConnections();
|
|||
|
|
|
|||
|
|
QTableView* m_detailView;
|
|||
|
|
QStandardItemModel* m_detailModel;
|
|||
|
|
QOrderListManager::OrderType m_orderType;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
#endif // QORDERLISTVIEWERS_H
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 实现特点
|
|||
|
|
|
|||
|
|
### QOrderListManager 改进
|
|||
|
|
|
|||
|
|
1. **订单簿专用数据结构**:
|
|||
|
|
- 使用 `QMap<double, QList<QSharedPointer<OrderBookItem>>>` 按价格层级存储订单
|
|||
|
|
- 区分买单(Bid)和卖单(Ask)
|
|||
|
|
2. **高效查询功能**:
|
|||
|
|
- 提供价格层级聚合数据 (`getBidPriceLevels`/`getAskPriceLevels`)
|
|||
|
|
- 快速获取最优买卖价 (`getBestBidPrice`/`getBestAskPrice`)
|
|||
|
|
3. **线程安全**:
|
|||
|
|
- 所有公共方法都使用互斥锁保护
|
|||
|
|
- 原子指针管理单例
|
|||
|
|
4. **信号通知**:
|
|||
|
|
- 订单变化时发出详细信号
|
|||
|
|
- 订单簿变化时发出汇总信号
|
|||
|
|
|
|||
|
|
### QOrderListViewers 改进
|
|||
|
|
|
|||
|
|
1. **专业订单簿视图**:
|
|||
|
|
- 分左右两栏显示买卖盘
|
|||
|
|
- 支持价格和数量的精度设置
|
|||
|
|
2. **详细订单视图**:
|
|||
|
|
- 可查看特定价格层的所有订单
|
|||
|
|
- 显示订单详细信息
|
|||
|
|
3. **实时更新**:
|
|||
|
|
- 监听订单簿变化信号
|
|||
|
|
- 自动刷新视图
|
|||
|
|
|
|||
|
|
## 使用示例
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
// 初始化管理器
|
|||
|
|
QOrderListManager* manager = QOrderListManager::instance();
|
|||
|
|
|
|||
|
|
// 添加订单
|
|||
|
|
OrderBookItem bidOrder;
|
|||
|
|
bidOrder.price = 100.50;
|
|||
|
|
bidOrder.volume = 10.0;
|
|||
|
|
bidOrder.orderCount = 1;
|
|||
|
|
bidOrder.orderId = "BID-001";
|
|||
|
|
manager->addOrder(QOrderListManager::BidOrder, bidOrder);
|
|||
|
|
|
|||
|
|
OrderBookItem askOrder;
|
|||
|
|
askOrder.price = 101.00;
|
|||
|
|
askOrder.volume = 5.0;
|
|||
|
|
askOrder.orderCount = 1;
|
|||
|
|
askOrder.orderId = "ASK-001";
|
|||
|
|
manager->addOrder(QOrderListManager::AskOrder, askOrder);
|
|||
|
|
|
|||
|
|
// 创建视图
|
|||
|
|
QOrderBookView* orderBookView = new QOrderBookView();
|
|||
|
|
orderBookView->setPricePrecision(2);
|
|||
|
|
orderBookView->setVolumePrecision(4);
|
|||
|
|
orderBookView->show();
|
|||
|
|
|
|||
|
|
QOrderDetailView* bidDetailView = new QOrderDetailView();
|
|||
|
|
bidDetailView->setOrderType(QOrderListManager::BidOrder);
|
|||
|
|
bidDetailView->show();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这个实现专门针对订单簿场景优化,提供了高效的订单管理和专业的可视化界面,适合金融交易系统使用。
|
|||
|
|
|
|||
|
|
完善实现文件
|
|||
|
|
|
|||
|
|
以下是完整的实现文件,包括 `QOrderListManager.cpp` 和 `QOrderListViewers.cpp` 的实现:
|
|||
|
|
|
|||
|
|
## QOrderListManager.cpp
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#include "QOrderListManager.h"
|
|||
|
|
#include <QDebug>
|
|||
|
|
|
|||
|
|
QBasicAtomicPointer<QOrderListManager> QOrderListManager::s_instance = QBasicAtomicPointer<QOrderListManager>(nullptr);
|
|||
|
|
QMutex QOrderListManager::s_mutex;
|
|||
|
|
|
|||
|
|
QOrderListManager* QOrderListManager::instance()
|
|||
|
|
{
|
|||
|
|
if (!s_instance.loadAcquire()) {
|
|||
|
|
QMutexLocker locker(&s_mutex);
|
|||
|
|
if (!s_instance.loadAcquire()) {
|
|||
|
|
s_instance.storeRelease(new QOrderListManager());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return s_instance.loadAcquire();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderListManager::destroy()
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&s_mutex);
|
|||
|
|
delete s_instance.loadAcquire();
|
|||
|
|
s_instance.storeRelease(nullptr);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QOrderListManager::QOrderListManager(QObject *parent) : QObject(parent)
|
|||
|
|
{
|
|||
|
|
// 初始化代码
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QOrderListManager::~QOrderListManager()
|
|||
|
|
{
|
|||
|
|
// 清理代码
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool QOrderListManager::addOrder(OrderType type, const OrderBookItem &order)
|
|||
|
|
{
|
|||
|
|
if (!order.isValid()) {
|
|||
|
|
qWarning() << "Invalid order data";
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
|
|||
|
|
auto& orderMap = (type == BidOrder) ? m_bidOrders : m_askOrders;
|
|||
|
|
auto& orderList = orderMap[order.price];
|
|||
|
|
|
|||
|
|
// 检查订单是否已存在
|
|||
|
|
for (const auto& existingOrder : orderList) {
|
|||
|
|
if (existingOrder->orderId == order.orderId) {
|
|||
|
|
qWarning() << "Order already exists:" << order.orderId;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
auto newOrder = QSharedPointer<OrderBookItem>::create(order);
|
|||
|
|
orderList.append(newOrder);
|
|||
|
|
|
|||
|
|
// 排序订单
|
|||
|
|
sortOrders(type);
|
|||
|
|
calculatePriceLevels();
|
|||
|
|
|
|||
|
|
locker.unlock();
|
|||
|
|
|
|||
|
|
emit orderAdded(type, order);
|
|||
|
|
emit orderBookChanged();
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool QOrderListManager::updateOrder(OrderType type, const QString &orderId, const OrderBookItem &newData)
|
|||
|
|
{
|
|||
|
|
if (!newData.isValid()) {
|
|||
|
|
qWarning() << "Invalid order data";
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
|
|||
|
|
auto& orderMap = (type == BidOrder) ? m_bidOrders : m_askOrders;
|
|||
|
|
bool found = false;
|
|||
|
|
|
|||
|
|
for (auto it = orderMap.begin(); it != orderMap.end(); ++it) {
|
|||
|
|
for (auto& order : it.value()) {
|
|||
|
|
if (order->orderId == orderId) {
|
|||
|
|
// 如果价格变化,需要重新分组
|
|||
|
|
if (order->price != newData.price) {
|
|||
|
|
auto orderList = it.value();
|
|||
|
|
orderList.removeOne(order);
|
|||
|
|
if (orderList.isEmpty()) {
|
|||
|
|
orderMap.erase(it);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
auto newOrder = QSharedPointer<OrderBookItem>::create(newData);
|
|||
|
|
orderMap[newData.price].append(newOrder);
|
|||
|
|
} else {
|
|||
|
|
*order = newData;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
found = true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (found) break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!found) {
|
|||
|
|
qWarning() << "Order not found:" << orderId;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 排序订单
|
|||
|
|
sortOrders(type);
|
|||
|
|
calculatePriceLevels();
|
|||
|
|
|
|||
|
|
locker.unlock();
|
|||
|
|
|
|||
|
|
emit orderUpdated(type, orderId);
|
|||
|
|
emit orderBookChanged();
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool QOrderListManager::removeOrder(OrderType type, const QString &orderId)
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
|
|||
|
|
auto& orderMap = (type == BidOrder) ? m_bidOrders : m_askOrders;
|
|||
|
|
bool found = false;
|
|||
|
|
|
|||
|
|
for (auto it = orderMap.begin(); it != orderMap.end(); ++it) {
|
|||
|
|
for (auto& order : it.value()) {
|
|||
|
|
if (order->orderId == orderId) {
|
|||
|
|
auto orderList = it.value();
|
|||
|
|
orderList.removeOne(order);
|
|||
|
|
if (orderList.isEmpty()) {
|
|||
|
|
orderMap.erase(it);
|
|||
|
|
}
|
|||
|
|
found = true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (found) break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!found) {
|
|||
|
|
qWarning() << "Order not found:" << orderId;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
calculatePriceLevels();
|
|||
|
|
|
|||
|
|
locker.unlock();
|
|||
|
|
|
|||
|
|
emit orderRemoved(type, orderId);
|
|||
|
|
emit orderBookChanged();
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QSharedPointer<OrderBookItem> QOrderListManager::getOrder(OrderType type, const QString &orderId) const
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
|
|||
|
|
const auto& orderMap = (type == BidOrder) ? m_bidOrders : m_askOrders;
|
|||
|
|
|
|||
|
|
for (const auto& orderList : orderMap) {
|
|||
|
|
for (const auto& order : orderList) {
|
|||
|
|
if (order->orderId == orderId) {
|
|||
|
|
return order;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nullptr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> QOrderListManager::getBidOrders() const
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
return m_bidOrders;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> QOrderListManager::getAskOrders() const
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
return m_askOrders;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QMap<double, double> QOrderListManager::getBidPriceLevels() const
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
return m_bidPriceLevels;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QMap<double, double> QOrderListManager::getAskPriceLevels() const
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
return m_askPriceLevels;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double QOrderListManager::getTotalBidVolume() const
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
double total = 0.0;
|
|||
|
|
for (const auto& volume : m_bidPriceLevels) {
|
|||
|
|
total += volume;
|
|||
|
|
}
|
|||
|
|
return total;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double QOrderListManager::getTotalAskVolume() const
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
double total = 0.0;
|
|||
|
|
for (const auto& volume : m_askPriceLevels) {
|
|||
|
|
total += volume;
|
|||
|
|
}
|
|||
|
|
return total;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double QOrderListManager::getBestBidPrice() const
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
if (m_bidOrders.isEmpty()) return 0.0;
|
|||
|
|
return m_bidOrders.lastKey();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double QOrderListManager::getBestAskPrice() const
|
|||
|
|
{
|
|||
|
|
QMutexLocker locker(&m_orderMutex);
|
|||
|
|
if (m_askOrders.isEmpty()) return 0.0;
|
|||
|
|
return m_askOrders.firstKey();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderListManager::sortOrders(OrderType type)
|
|||
|
|
{
|
|||
|
|
auto& orderMap = (type == BidOrder) ? m_bidOrders : m_askOrders;
|
|||
|
|
|
|||
|
|
if (type == BidOrder) {
|
|||
|
|
// 买单按价格降序排列
|
|||
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> sortedMap;
|
|||
|
|
auto keys = orderMap.keys();
|
|||
|
|
std::sort(keys.begin(), keys.end(), std::greater<double>());
|
|||
|
|
|
|||
|
|
for (const auto& key : keys) {
|
|||
|
|
sortedMap.insert(key, orderMap.value(key));
|
|||
|
|
}
|
|||
|
|
orderMap = sortedMap;
|
|||
|
|
} else {
|
|||
|
|
// 卖单按价格升序排列
|
|||
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> sortedMap;
|
|||
|
|
auto keys = orderMap.keys();
|
|||
|
|
std::sort(keys.begin(), keys.end());
|
|||
|
|
|
|||
|
|
for (const auto& key : keys) {
|
|||
|
|
sortedMap.insert(key, orderMap.value(key));
|
|||
|
|
}
|
|||
|
|
orderMap = sortedMap;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderListManager::calculatePriceLevels()
|
|||
|
|
{
|
|||
|
|
m_bidPriceLevels.clear();
|
|||
|
|
for (auto it = m_bidOrders.constBegin(); it != m_bidOrders.constEnd(); ++it) {
|
|||
|
|
double totalVolume = 0.0;
|
|||
|
|
for (const auto& order : it.value()) {
|
|||
|
|
totalVolume += order->volume;
|
|||
|
|
}
|
|||
|
|
m_bidPriceLevels.insert(it.key(), totalVolume);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
m_askPriceLevels.clear();
|
|||
|
|
for (auto it = m_askOrders.constBegin(); it != m_askOrders.constEnd(); ++it) {
|
|||
|
|
double totalVolume = 0.0;
|
|||
|
|
for (const auto& order : it.value()) {
|
|||
|
|
totalVolume += order->volume;
|
|||
|
|
}
|
|||
|
|
m_askPriceLevels.insert(it.key(), totalVolume);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## QOrderListViewers.cpp
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#include "QOrderListViewers.h"
|
|||
|
|
#include <QHeaderView>
|
|||
|
|
#include <QHBoxLayout>
|
|||
|
|
#include <QVBoxLayout>
|
|||
|
|
#include <QLabel>
|
|||
|
|
|
|||
|
|
QOrderBookView::QOrderBookView(QWidget *parent) : QWidget(parent)
|
|||
|
|
{
|
|||
|
|
initUI();
|
|||
|
|
initConnections();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QOrderBookView::~QOrderBookView()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderBookView::initUI()
|
|||
|
|
{
|
|||
|
|
QHBoxLayout *mainLayout = new QHBoxLayout(this);
|
|||
|
|
|
|||
|
|
// 买单视图
|
|||
|
|
m_bidModel = new QStandardItemModel(this);
|
|||
|
|
m_bidModel->setColumnCount(3);
|
|||
|
|
m_bidModel->setHorizontalHeaderLabels({"价格", "数量", "订单数"});
|
|||
|
|
|
|||
|
|
m_bidView = new QTableView(this);
|
|||
|
|
m_bidView->setModel(m_bidModel);
|
|||
|
|
m_bidView->verticalHeader()->setVisible(false);
|
|||
|
|
m_bidView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|||
|
|
m_bidView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|||
|
|
m_bidView->setSelectionMode(QAbstractItemView::SingleSelection);
|
|||
|
|
|
|||
|
|
// 卖单视图
|
|||
|
|
m_askModel = new QStandardItemModel(this);
|
|||
|
|
m_askModel->setColumnCount(3);
|
|||
|
|
m_askModel->setHorizontalHeaderLabels({"价格", "数量", "订单数"});
|
|||
|
|
|
|||
|
|
m_askView = new QTableView(this);
|
|||
|
|
m_askView->setModel(m_askModel);
|
|||
|
|
m_askView->verticalHeader()->setVisible(false);
|
|||
|
|
m_askView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|||
|
|
m_askView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|||
|
|
m_askView->setSelectionMode(QAbstractItemView::SingleSelection);
|
|||
|
|
|
|||
|
|
// 布局
|
|||
|
|
QVBoxLayout *bidLayout = new QVBoxLayout();
|
|||
|
|
bidLayout->addWidget(new QLabel("买单", this));
|
|||
|
|
bidLayout->addWidget(m_bidView);
|
|||
|
|
|
|||
|
|
QVBoxLayout *askLayout = new QVBoxLayout();
|
|||
|
|
askLayout->addWidget(new QLabel("卖单", this));
|
|||
|
|
askLayout->addWidget(m_askView);
|
|||
|
|
|
|||
|
|
mainLayout->addLayout(bidLayout);
|
|||
|
|
mainLayout->addLayout(askLayout);
|
|||
|
|
|
|||
|
|
setLayout(mainLayout);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderBookView::initConnections()
|
|||
|
|
{
|
|||
|
|
auto manager = QOrderListManager::instance();
|
|||
|
|
connect(manager, &QOrderListManager::orderBookChanged, this, &QOrderBookView::updateView);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderBookView::updateView()
|
|||
|
|
{
|
|||
|
|
updateBidView();
|
|||
|
|
updateAskView();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderBookView::updateBidView()
|
|||
|
|
{
|
|||
|
|
m_bidModel->removeRows(0, m_bidModel->rowCount());
|
|||
|
|
|
|||
|
|
auto bids = QOrderListManager::instance()->getBidPriceLevels();
|
|||
|
|
int row = 0;
|
|||
|
|
|
|||
|
|
for (auto it = bids.constBegin(); it != bids.constEnd(); ++it) {
|
|||
|
|
m_bidModel->insertRow(row);
|
|||
|
|
|
|||
|
|
QStandardItem *priceItem = new QStandardItem(QString::number(it.key(), 'f', m_pricePrecision));
|
|||
|
|
QStandardItem *volumeItem = new QStandardItem(QString::number(it.value(), 'f', m_volumePrecision));
|
|||
|
|
|
|||
|
|
// 计算订单数
|
|||
|
|
int orderCount = 0;
|
|||
|
|
auto bidOrders = QOrderListManager::instance()->getBidOrders();
|
|||
|
|
if (bidOrders.contains(it.key())) {
|
|||
|
|
orderCount = bidOrders.value(it.key()).size();
|
|||
|
|
}
|
|||
|
|
QStandardItem *countItem = new QStandardItem(QString::number(orderCount));
|
|||
|
|
|
|||
|
|
m_bidModel->setItem(row, 0, priceItem);
|
|||
|
|
m_bidModel->setItem(row, 1, volumeItem);
|
|||
|
|
m_bidModel->setItem(row, 2, countItem);
|
|||
|
|
|
|||
|
|
row++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderBookView::updateAskView()
|
|||
|
|
{
|
|||
|
|
m_askModel->removeRows(0, m_askModel->rowCount());
|
|||
|
|
|
|||
|
|
auto asks = QOrderListManager::instance()->getAskPriceLevels();
|
|||
|
|
int row = 0;
|
|||
|
|
|
|||
|
|
for (auto it = asks.constBegin(); it != asks.constEnd(); ++it) {
|
|||
|
|
m_askModel->insertRow(row);
|
|||
|
|
|
|||
|
|
QStandardItem *priceItem = new QStandardItem(QString::number(it.key(), 'f', m_pricePrecision));
|
|||
|
|
QStandardItem *volumeItem = new QStandardItem(QString::number(it.value(), 'f', m_volumePrecision));
|
|||
|
|
|
|||
|
|
// 计算订单数
|
|||
|
|
int orderCount = 0;
|
|||
|
|
auto askOrders = QOrderListManager::instance()->getAskOrders();
|
|||
|
|
if (askOrders.contains(it.key())) {
|
|||
|
|
orderCount = askOrders.value(it.key()).size();
|
|||
|
|
}
|
|||
|
|
QStandardItem *countItem = new QStandardItem(QString::number(orderCount));
|
|||
|
|
|
|||
|
|
m_askModel->setItem(row, 0, priceItem);
|
|||
|
|
m_askModel->setItem(row, 1, volumeItem);
|
|||
|
|
m_askModel->setItem(row, 2, countItem);
|
|||
|
|
|
|||
|
|
row++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderBookView::setPricePrecision(int precision)
|
|||
|
|
{
|
|||
|
|
m_pricePrecision = precision;
|
|||
|
|
updateView();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderBookView::setVolumePrecision(int precision)
|
|||
|
|
{
|
|||
|
|
m_volumePrecision = precision;
|
|||
|
|
updateView();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QOrderDetailView::QOrderDetailView(QWidget *parent) : QWidget(parent),
|
|||
|
|
m_orderType(QOrderListManager::BidOrder)
|
|||
|
|
{
|
|||
|
|
initUI();
|
|||
|
|
initConnections();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QOrderDetailView::~QOrderDetailView()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderDetailView::initUI()
|
|||
|
|
{
|
|||
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|||
|
|
|
|||
|
|
m_detailModel = new QStandardItemModel(this);
|
|||
|
|
m_detailModel->setColumnCount(4);
|
|||
|
|
m_detailModel->setHorizontalHeaderLabels({"订单ID", "价格", "数量", "时间"});
|
|||
|
|
|
|||
|
|
m_detailView = new QTableView(this);
|
|||
|
|
m_detailView->setModel(m_detailModel);
|
|||
|
|
m_detailView->verticalHeader()->setVisible(false);
|
|||
|
|
m_detailView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|||
|
|
m_detailView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|||
|
|
m_detailView->setSelectionMode(QAbstractItemView::SingleSelection);
|
|||
|
|
|
|||
|
|
mainLayout->addWidget(m_detailView);
|
|||
|
|
setLayout(mainLayout);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderDetailView::initConnections()
|
|||
|
|
{
|
|||
|
|
auto manager = QOrderListManager::instance();
|
|||
|
|
connect(manager, &QOrderListManager::orderBookChanged, this, &QOrderDetailView::updateView);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderDetailView::setOrderType(QOrderListManager::OrderType type)
|
|||
|
|
{
|
|||
|
|
m_orderType = type;
|
|||
|
|
updateView();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderDetailView::updateView()
|
|||
|
|
{
|
|||
|
|
m_detailModel->removeRows(0, m_detailModel->rowCount());
|
|||
|
|
|
|||
|
|
auto manager = QOrderListManager::instance();
|
|||
|
|
auto orders = (m_orderType == QOrderListManager::BidOrder) ?
|
|||
|
|
manager->getBidOrders() : manager->getAskOrders();
|
|||
|
|
|
|||
|
|
int row = 0;
|
|||
|
|
for (auto it = orders.constBegin(); it != orders.constEnd(); ++it) {
|
|||
|
|
for (const auto& order : it.value()) {
|
|||
|
|
m_detailModel->insertRow(row);
|
|||
|
|
|
|||
|
|
QStandardItem *idItem = new QStandardItem(order->orderId);
|
|||
|
|
QStandardItem *priceItem = new QStandardItem(QString::number(order->price, 'f', 2));
|
|||
|
|
QStandardItem *volumeItem = new QStandardItem(QString::number(order->volume, 'f', 4));
|
|||
|
|
QStandardItem *timeItem = new QStandardItem(QDateTime::currentDateTime().toString("hh:mm:ss.zzz"));
|
|||
|
|
|
|||
|
|
m_detailModel->setItem(row, 0, idItem);
|
|||
|
|
m_detailModel->setItem(row, 1, priceItem);
|
|||
|
|
m_detailModel->setItem(row, 2, volumeItem);
|
|||
|
|
m_detailModel->setItem(row, 3, timeItem);
|
|||
|
|
|
|||
|
|
row++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 主要特点
|
|||
|
|
|
|||
|
|
1. **线程安全设计**:
|
|||
|
|
- 使用 QMutex 保护所有订单数据访问
|
|||
|
|
- 原子指针管理单例实例
|
|||
|
|
2. **高效订单管理**:
|
|||
|
|
- 按价格层级存储订单 (QMap<double, QList>)
|
|||
|
|
- 自动计算价格层级聚合数据
|
|||
|
|
- 支持快速查询最优买卖价
|
|||
|
|
3. **专业视图组件**:
|
|||
|
|
- 订单簿视图 (QOrderBookView) 分左右显示买卖盘
|
|||
|
|
- 订单详情视图 (QOrderDetailView) 显示单个价格层的所有订单
|
|||
|
|
- 支持自定义价格和数量显示精度
|
|||
|
|
4. **实时更新机制**:
|
|||
|
|
- 使用信号-槽机制实现数据变化时自动更新视图
|
|||
|
|
- 细粒度信号 (单个订单变化和整个订单簿变化)
|
|||
|
|
5. **完整的功能实现**:
|
|||
|
|
- 支持订单的增删改查
|
|||
|
|
- 提供多种查询方式
|
|||
|
|
- 自动排序和聚合计算
|
|||
|
|
|
|||
|
|
这个实现完全基于您提供的 OrderBookItem 结构,并针对金融订单簿场景进行了优化,适合用于交易系统的开发。
|
|||
|
|
|
|||
|
|
error: undefined reference to `QOrderBookView::onOrderBookChanged()'
|
|||
|
|
|
|||
|
|
这个错误是因为在 `QOrderListViewers.h` 中声明了 `onOrderBookChanged()` 槽函数,但在 `QOrderListViewers.cpp` 中没有实现它。让我们修正这个问题:
|
|||
|
|
|
|||
|
|
## 修正后的 QOrderListViewers.cpp
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#include "QOrderListViewers.h"
|
|||
|
|
#include <QHeaderView>
|
|||
|
|
#include <QHBoxLayout>
|
|||
|
|
#include <QVBoxLayout>
|
|||
|
|
#include <QLabel>
|
|||
|
|
|
|||
|
|
// [其他现有代码保持不变...]
|
|||
|
|
|
|||
|
|
void QOrderBookView::initConnections()
|
|||
|
|
{
|
|||
|
|
auto manager = QOrderListManager::instance();
|
|||
|
|
connect(manager, &QOrderListManager::orderBookChanged,
|
|||
|
|
this, &QOrderBookView::onOrderBookChanged);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加这个实现
|
|||
|
|
void QOrderBookView::onOrderBookChanged()
|
|||
|
|
{
|
|||
|
|
updateView();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// [其他现有代码保持不变...]
|
|||
|
|
|
|||
|
|
void QOrderDetailView::initConnections()
|
|||
|
|
{
|
|||
|
|
auto manager = QOrderListManager::instance();
|
|||
|
|
connect(manager, &QOrderListManager::orderBookChanged,
|
|||
|
|
this, &QOrderDetailView::onOrderBookChanged);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加这个实现
|
|||
|
|
void QOrderDetailView::onOrderBookChanged()
|
|||
|
|
{
|
|||
|
|
updateView();
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 修正后的 QOrderListViewers.h
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#ifndef QORDERLISTVIEWERS_H
|
|||
|
|
#define QORDERLISTVIEWERS_H
|
|||
|
|
|
|||
|
|
#include <QWidget>
|
|||
|
|
#include <QTableView>
|
|||
|
|
#include <QStandardItemModel>
|
|||
|
|
#include <QHeaderView>
|
|||
|
|
#include <QHBoxLayout>
|
|||
|
|
#include "QOrderListManager.h"
|
|||
|
|
|
|||
|
|
class QOrderBookView : public QWidget
|
|||
|
|
{
|
|||
|
|
Q_OBJECT
|
|||
|
|
public:
|
|||
|
|
explicit QOrderBookView(QWidget *parent = nullptr);
|
|||
|
|
~QOrderBookView();
|
|||
|
|
|
|||
|
|
void updateView();
|
|||
|
|
void setPricePrecision(int precision);
|
|||
|
|
void setVolumePrecision(int precision);
|
|||
|
|
|
|||
|
|
private slots:
|
|||
|
|
void onOrderBookChanged(); // 确保这里已声明
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void initUI();
|
|||
|
|
void initConnections();
|
|||
|
|
void updateBidView();
|
|||
|
|
void updateAskView();
|
|||
|
|
|
|||
|
|
// [其他成员变量保持不变...]
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class QOrderDetailView : public QWidget
|
|||
|
|
{
|
|||
|
|
Q_OBJECT
|
|||
|
|
public:
|
|||
|
|
explicit QOrderDetailView(QWidget *parent = nullptr);
|
|||
|
|
~QOrderDetailView();
|
|||
|
|
|
|||
|
|
void setOrderType(QOrderListManager::OrderType type);
|
|||
|
|
void updateView();
|
|||
|
|
|
|||
|
|
private slots:
|
|||
|
|
void onOrderBookChanged(); // 确保这里已声明
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void initUI();
|
|||
|
|
void initConnections();
|
|||
|
|
|
|||
|
|
// [其他成员变量保持不变...]
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
#endif // QORDERLISTVIEWERS_H
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 为什么会出现这个错误?
|
|||
|
|
|
|||
|
|
1. **声明与实现不匹配**:在头文件中声明了槽函数 `onOrderBookChanged()`,但在源文件中没有提供实现
|
|||
|
|
2. **连接信号时的问题**:虽然你直接连接信号到 `updateView()`,但头文件中声明了这个槽函数,所以编译器期望找到它的实现
|
|||
|
|
|
|||
|
|
## 解决方案的两种选择:
|
|||
|
|
|
|||
|
|
### 选择1:保留槽函数并实现它(如上所示)
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
void QOrderBookView::onOrderBookChanged()
|
|||
|
|
{
|
|||
|
|
updateView();
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 选择2:移除槽函数声明,直接连接信号
|
|||
|
|
|
|||
|
|
修改头文件,移除 `onOrderBookChanged()` 的声明,然后修改连接方式:
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
// 在initConnections()中改为:
|
|||
|
|
connect(manager, &QOrderListManager::orderBookChanged,
|
|||
|
|
this, &QOrderBookView::updateView);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
两种方法都是可行的,选择哪种取决于你的设计偏好。第一种方法更符合Qt的命名惯例,特别是如果你以后需要在这个槽函数中添加更多处理逻辑。第二种方法更直接,减少了不必要的间接调用。
|
|||
|
|
|
|||
|
|
error: undefined reference to `QOrderDetailView::onOrderBookChanged()'
|
|||
|
|
|
|||
|
|
这个错误表明 `QOrderDetailView` 类中的 `onOrderBookChanged()` 槽函数在头文件中声明了,但在源文件中没有实现。以下是完整的修正方案:
|
|||
|
|
|
|||
|
|
## 修正方案
|
|||
|
|
|
|||
|
|
### 1. 修改 QOrderListViewers.h
|
|||
|
|
|
|||
|
|
确保槽函数声明正确:
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
class QOrderDetailView : public QWidget
|
|||
|
|
{
|
|||
|
|
Q_OBJECT
|
|||
|
|
public:
|
|||
|
|
// ... 其他公共成员函数 ...
|
|||
|
|
|
|||
|
|
private slots:
|
|||
|
|
void onOrderBookChanged(); // 确保这个声明存在
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
// ... 私有成员函数和变量 ...
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 修改 QOrderListViewers.cpp
|
|||
|
|
|
|||
|
|
添加缺失的实现:
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
void QOrderDetailView::onOrderBookChanged()
|
|||
|
|
{
|
|||
|
|
updateView(); // 直接调用updateView()更新界面
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 确保连接正确
|
|||
|
|
|
|||
|
|
在 `initConnections()` 中正确连接信号和槽:
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
void QOrderDetailView::initConnections()
|
|||
|
|
{
|
|||
|
|
auto manager = QOrderListManager::instance();
|
|||
|
|
connect(manager, &QOrderListManager::orderBookChanged,
|
|||
|
|
this, &QOrderDetailView::onOrderBookChanged);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 完整修正后的 QOrderDetailView 相关代码
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
// QOrderListViewers.h
|
|||
|
|
class QOrderDetailView : public QWidget
|
|||
|
|
{
|
|||
|
|
Q_OBJECT
|
|||
|
|
public:
|
|||
|
|
explicit QOrderDetailView(QWidget *parent = nullptr);
|
|||
|
|
~QOrderDetailView();
|
|||
|
|
|
|||
|
|
void setOrderType(QOrderListManager::OrderType type);
|
|||
|
|
void updateView();
|
|||
|
|
|
|||
|
|
private slots:
|
|||
|
|
void onOrderBookChanged();
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void initUI();
|
|||
|
|
void initConnections();
|
|||
|
|
|
|||
|
|
QTableView* m_detailView;
|
|||
|
|
QStandardItemModel* m_detailModel;
|
|||
|
|
QOrderListManager::OrderType m_orderType;
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
// QOrderListViewers.cpp
|
|||
|
|
QOrderDetailView::QOrderDetailView(QWidget *parent)
|
|||
|
|
: QWidget(parent), m_orderType(QOrderListManager::BidOrder)
|
|||
|
|
{
|
|||
|
|
initUI();
|
|||
|
|
initConnections();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderDetailView::initConnections()
|
|||
|
|
{
|
|||
|
|
auto manager = QOrderListManager::instance();
|
|||
|
|
connect(manager, &QOrderListManager::orderBookChanged,
|
|||
|
|
this, &QOrderDetailView::onOrderBookChanged);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderDetailView::onOrderBookChanged()
|
|||
|
|
{
|
|||
|
|
updateView();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ... 其他成员函数的实现保持不变 ...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 为什么会出现这个错误?
|
|||
|
|
|
|||
|
|
1. **声明与实现不匹配**:在头文件中声明了 `onOrderBookChanged()` 槽函数,但在源文件中没有提供实现
|
|||
|
|
2. **Qt的moc机制**:Qt的元对象编译器(moc)会为声明的槽函数生成代码,如果没有实现就会导致链接错误
|
|||
|
|
|
|||
|
|
## 替代解决方案
|
|||
|
|
|
|||
|
|
如果你不想保留这个槽函数,也可以直接连接信号到 `updateView()`:
|
|||
|
|
|
|||
|
|
1. 从头文件中移除 `onOrderBookChanged()` 的声明
|
|||
|
|
2. 修改连接代码:
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
void QOrderDetailView::initConnections()
|
|||
|
|
{
|
|||
|
|
auto manager = QOrderListManager::instance();
|
|||
|
|
connect(manager, &QOrderListManager::orderBookChanged,
|
|||
|
|
this, &QOrderDetailView::updateView);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
两种方法都是有效的,选择哪种取决于你的设计偏好。保留中间槽函数的方式更灵活,便于以后添加额外处理逻辑。
|