#include "qbigorderviewer.h" #include "qbigordermanager.h" #include "qhistoryorderdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include //// ==================== 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::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 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)); QString str = order->svrRecvTime.mid(11); if (str == nullptr) { QDateTime dateTime = QDateTime::currentDateTime(); str = dateTime.toString("hh:mm:ss"); } rowItems << new QStandardItem(str); 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::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 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)); 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); } bool QBigOrderViewer::matchesFilter(QSharedPointer 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(); }