Files
QTradeProgram/Sqbase/qbigorderviewer.cpp

309 lines
9.9 KiB
C++
Raw Normal View History

2025-08-15 15:56:40 +08:00
#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));
2025-08-22 10:59:38 +08:00
QString str = order->svrRecvTime.mid(11);
if (str == nullptr)
{
QDateTime dateTime = QDateTime::currentDateTime();
str = dateTime.toString("hh:mm:ss");
}
rowItems << new QStandardItem(str);
2025-08-15 15:56:40 +08:00
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));
2025-08-22 10:59:38 +08:00
QString str = order->svrRecvTime.mid(11);
if (str == nullptr)
{
QDateTime dateTime = QDateTime::currentDateTime();
str = dateTime.toString("hh:mm:ss");
}
m_model->setData(m_model->index(row, 6), str);
2025-08-15 15:56:40 +08:00
}
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();
}