Files
QTradeProgram/Sqbase/qbigorderviewer.cpp
2025-08-15 15:56:40 +08:00

297 lines
9.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "qbigorderviewer.h"
#include "qbigordermanager.h"
#include "qhistoryorderdialog.h"
#include <QHeaderView>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPainter>
#include <QFileDialog>
#include <QTextStream>
#include <QLineEdit>
#include <QComboBox>
#include <QTableView>
#include <QPushButton>
#include <QWidget>
#include <QCheckBox>
//// ==================== OrderTypeDelegate ====================
//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);
//}
// ==================== QBigOrderViewer ====================
QBigOrderViewer::QBigOrderViewer(QWidget *parent)
: QWidget(parent),
m_model(new QStandardItemModel(0, 7, this)),
m_proxyModel(new QSortFilterProxyModel(this)),
m_typeDelegate(new OrderTypeDelegate(this))
{
initUI();
initConnections();
QBigOrderManager* manager = QBigOrderManager::instance();
connect(manager, &QBigOrderManager::bigOrderAdded,
this, &QBigOrderViewer::onBigOrderAdded);
connect(manager, &QBigOrderManager::saveOverRefreshView,
this, [this]() {
m_model->removeRows(0, m_model->rowCount());
}, Qt::QueuedConnection // 必须使用跨线程连接
);
}
QBigOrderViewer::~QBigOrderViewer()
{
delete m_model;
delete m_proxyModel;
delete m_typeDelegate;
}
void QBigOrderViewer::initUI()
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// 过滤控件区域
QHBoxLayout *filterLayout = new QHBoxLayout();
QCheckBox *cboAutoSave = new QCheckBox("自动保存数据");
cboAutoSave->setChecked(true);
filterLayout->addWidget(cboAutoSave);
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("买入", "BID");
m_orderTypeFilter->addItem("卖出", "ASK");
filterLayout->addWidget(m_orderTypeFilter);
filterLayout->addStretch();
// 添加历史查询按钮
QPushButton *historyButton = new QPushButton("历史查询");
filterLayout->addWidget(historyButton);
m_exportButton = new QPushButton("导出数据");
filterLayout->addWidget(m_exportButton);
mainLayout->addLayout(filterLayout);
// 表格视图配置
m_tableView = new QTableView();
m_proxyModel->setSourceModel(m_model);
m_tableView->setModel(m_proxyModel);
m_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
// 设置表头(股票代码、名称、类型、数量、价格、订单数、时间)
m_model->setHorizontalHeaderLabels(
QStringList()
<< "股票代码"
<< "股票名称"
<< "订单类型"
<< "股票数量"
<< "股票价格"
<< "订单档位"
<< "时间"
);
// 表格属性
m_tableView->setItemDelegateForColumn(2, m_typeDelegate);
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
m_tableView->setSortingEnabled(true);
// m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// 默认按时间列第6列索引5升序排序
const int timeColumnIndex = 6;
m_proxyModel->sort(timeColumnIndex, Qt::AscendingOrder);
mainLayout->addWidget(m_tableView);
// 连接历史查询按钮
connect(historyButton, &QPushButton::clicked, this, [this] {
QHistoryOrderDialog *dialog = new QHistoryOrderDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
});
connect(cboAutoSave, &QCheckBox::stateChanged, [](int state) {
if (state == Qt::Checked) {
QBigOrderManager::instance()->setAutoSave(true);
// 复选框被选中
}
else if (state == Qt::Unchecked) {
QBigOrderManager::instance()->setAutoSave(false);
// 复选框被取消选中
}
});
}
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);
// // 表头点击排序使用lambda适配参数
connect(m_tableView->horizontalHeader(), &QHeaderView::sectionClicked,
[this](int logicalIndex) {
Qt::SortOrder currentOrder = m_proxyModel->sortOrder();
m_proxyModel->sort(logicalIndex,
currentOrder == Qt::AscendingOrder
? Qt::AscendingOrder
: Qt::DescendingOrder);
});
QObject::connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
[&](const QItemSelection &selected, const QItemSelection &deselected) {
Q_UNUSED(deselected); // 未使用deselected避免警告
// 获取当前选中的所有行
QModelIndexList selectedIndexes = m_tableView->selectionModel()->selectedIndexes();
// 如果没有选中任何项
if (selectedIndexes.isEmpty()) {
return;
}
emit sendStockCodeToMainForm(m_proxyModel->index(selectedIndexes.at(0).row(), selectedIndexes.at(0).column()).data().toString());
});
}
void QBigOrderViewer::updateView()
{
m_model->removeRows(0, m_model->rowCount());
for (const auto& order : m_currentOrders) {
QList<QStandardItem*> rowItems;
rowItems << new QStandardItem(order->code);
rowItems << new QStandardItem(order->name);
int nType = order->nBigOrderType;
if(nType)
rowItems << new QStandardItem("多单");
else
rowItems << new QStandardItem("空单");
rowItems << new QStandardItem(QString::number(std::fabs(order->volume/1000)) + "K");
rowItems << new QStandardItem(QString::number(order->price, 'f', 2));
rowItems << new QStandardItem(QString::number(order->level));
rowItems << new QStandardItem(order->svrRecvTime.mid(12));
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->code.contains(stockCode, Qt::CaseInsensitive)) {
match = false;
}
if (!orderType.isEmpty() && order->nBigOrderType != orderType) {
match = false;
}
if (match) m_currentOrders.append(order);
}
}
void QBigOrderViewer::onBigOrderAdded(const BigOrderInfo &order)
{
auto newOrder = QSharedPointer<BigOrderInfo>::create(order);
m_allOrders.append(newOrder);
if (matchesFilter(newOrder)) {
m_currentOrders.append(newOrder);
// 高效插入单行
int row = m_model->rowCount();
m_model->insertRow(row);
setRowData(row, newOrder);
}
}
// 新增辅助函数
void QBigOrderViewer::setRowData(int row, QSharedPointer<BigOrderInfo> order)
{
m_model->setData(m_model->index(row, 0), order->code);
m_model->setData(m_model->index(row, 1), order->name);
m_model->setData(m_model->index(row, 2),
order->nBigOrderType == 0 ? "卖出" : "买入");
m_model->setData(m_model->index(row, 3),
QString::number(std::fabs(order->volume / 1000)) + "K");
m_model->setData(m_model->index(row, 4),
QString::number(order->price, 'f', 2));
m_model->setData(m_model->index(row, 5),
QString::number(order->level));
m_model->setData(m_model->index(row, 6), order->svrRecvTime);
}
bool QBigOrderViewer::matchesFilter(QSharedPointer<BigOrderInfo> order)
{
QString stockCode = m_stockCodeFilter->text().trimmed();
QString orderType = m_orderTypeFilter->currentData().toString();
return (stockCode.isEmpty() || order->code.contains(stockCode, Qt::CaseInsensitive))
&& (orderType.isEmpty() || order->nBigOrderType == orderType);
}
void QBigOrderViewer::onFilterChanged()
{
applyFilters();
updateView();
}
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);
out.setCodec("GBK");
// 写入表头
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();
}