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);
|
||
}
|
||
```
|
||
|
||
两种方法都是有效的,选择哪种取决于你的设计偏好。保留中间槽函数的方式更灵活,便于以后添加额外处理逻辑。 |