活动介绍

model->setData

时间: 2025-06-11 07:54:46 浏览: 19
<think>好的,我现在需要回答用户关于model->setData的问题。首先,我得回忆一下Qt框架中QAbstractItemModel类的setData方法。这个方法的作用是设置模型中特定索引的数据,对吧?用户可能是在使用模型/视图编程时遇到了问题,或者想了解如何正确使用这个方法。 接下来,我应该解释setData的基本用法,包括它的参数:QModelIndex索引、QVariant值,以及角色参数,默认是EditRole。需要说明返回值是bool,表示成功与否。然后,可能要给一个简单的例子,比如设置表格单元格的值,这样用户更容易理解。 然后,用户可能需要知道如何实现数据验证。比如在子类化模型时,重写setData方法,检查输入是否有效,比如是否是整数。这时候需要说明在修改数据后必须发射dataChanged信号,这样视图才能更新。这可能会涉及到信号发射的细节,比如参数是顶部左边和底部右边的索引,通常对于单个单元格来说,两个索引相同。 另外,用户可能对角色参数不太清楚,需要解释不同角色的用途,比如EditRole用于编辑,DisplayRole用于显示。可以举例说明如何根据不同的角色处理数据。 还要提到多选编辑的情况,用户可能需要遍历多个索引并逐个调用setData。这时候需要注意性能问题,或者是否应该在一个事务中处理多个修改。 最后,可能需要提醒用户常见的错误,比如忘记发射dataChanged信号,或者没有正确处理返回值。这些注意事项能帮助用户避免典型的问题。 在组织回答时,要结构清晰,分点说明,比如基本用法、参数解释、示例代码、数据验证、信号发射、角色应用、多选处理和常见问题。每个部分用子标题分开,方便用户阅读。同时,代码示例要用正确的语法,比如使用C++和Qt的代码块,并确保LaTeX公式的正确格式,行内公式用$包围,独立公式用$$。 检查是否有遗漏的部分,比如是否需要提到模型子类化的必要性,或者如何处理树形或列表结构中的索引。可能需要简要说明,但用户问题主要关注setData方法本身,所以保持重点在这个方法的详细使用上。 确保回答使用中文,术语准确,比如“信号”、“槽”、“索引”等。避免过于技术性的行话,但又要准确描述功能。最后通读一遍,确保逻辑流畅,没有语法错误,LaTeX格式正确,符合用户提供的系统级指令。</think>在Qt框架中,`model->setData()` 是模型/视图架构中的核心方法,用于修改模型数据。以下是逐步说明: ### 一、基本作用 $$ QModelIndex + QVariant \rightarrow bool $$ 将数据值(`QVariant`类型)写入模型的指定位置(由`QModelIndex`定位),返回`true`表示修改成功。 ### 二、参数详解 ```cpp bool setData( const QModelIndex &index, // 目标位置索引 const QVariant &value, // 新数据值 int role = Qt::EditRole // 数据角色 ) ``` - **index**:通过`model->index(row, column)`创建 - **value**:支持Qt所有数据类型(如`int`、`QString`等) - **role**:默认为`EditRole`(编辑用途),其他常用角色: - `DisplayRole`:显示文本 - `CheckStateRole`:复选框状态 - `UserRole`:自定义数据 ### 三、标准使用示例 ```cpp QModelIndex idx = model->index(0, 0); // 第0行第0列 bool success = model->setData(idx, "新内容"); if(success) { qDebug() << "数据修改成功"; // 视图会自动更新 } ``` ### 四、关键操作流程 1. **数据验证**(子类化模型时) ```cpp bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == Qt::EditRole) { if (index.column() == 0 && !value.canConvert<int>()) { return false; // 验证数值类型 } // 存储到数据结构... emit dataChanged(index, index); // 必须发送信号 return true; } return false; } ``` 2. **多数据修改**(批量操作) ```cpp beginResetModel(); // 开始批量修改 for(auto &idx : selectedIndexes()) { model->setData(idx, newValue); } endResetModel(); // 结束批量修改 ``` ### 五、注意事项 1. **必须触发`dataChanged`信号**,否则视图不更新 2. 树状模型需注意`parent`索引的传递 3. 自定义模型需重写`flags()`返回`Qt::ItemIsEditable` 4. 性能优化:批量修改时使用`beginResetModel()`/`endResetModel()` ### 六、典型应用场景 1. 用户界面直接编辑 2. 程序逻辑更新数据 3. 实现撤销/重做功能 4. 数据持久化前的预处理 通过合理使用`setData()`,可以实现模型与视图的高效数据交互,建议结合`QDataWidgetMapper`进行窗体控件绑定。
阅读全文

相关推荐

#include "c.h"//借还管理 #include "ui_c.h" #include "a.h" C::C(QWidget *parent) : QMainWindow(parent) , ui(new Ui::C) { ui->setupUi(this); this->setWindowTitle("借还管理"); QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); // SQLite示例 db.setDatabaseName("D:/qtfile/serve1/data.db"); // 数据库文件路径 if (!db.open()) { qDebug() << "数据库连接失败:" << db.lastError().text(); return; } //创建表 QSqlQuery query; if (!query.exec("CREATE TABLE IF NOT EXISTS equipment (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "name TEXT NOT NULL," "type TEXT NOT NULL," "status INTEGER DEFAULT 0," "lend_out_date DATE," "return_date DATE," "people TEXT NOT NULL," "phone TEXT NOT NULL);")) { qDebug() << "建表错误:" << query.lastError().text(); } //插入两条数据 QSqlQuery checkQuery("SELECT COUNT(*) FROM equipment;"); if (checkQuery.next() && checkQuery.value(0).toInt() == 0) { QSqlQuery insertQuery; // 第一条数据 insertQuery.prepare("INSERT INTO equipment (name, type, status, lend_out_date,return_date,people,phone) " "VALUES (:name, :type, :status, :date_1, :date_2, :people, :phone)"); insertQuery.bindValue(":name", "光谱分析仪"); insertQuery.bindValue(":type", "实验室设备"); insertQuery.bindValue(":status", 0); insertQuery.bindValue(":date_1", QDate(2023, 5, 10)); insertQuery.bindValue(":date_2", QDate()); insertQuery.bindValue(":people", "张洪平"); insertQuery.bindValue(":phone", "19923688556"); if (!insertQuery.exec()) { qDebug() << "插入数据失败:" << insertQuery.lastError().text(); } // 第二条数据 insertQuery.prepare("INSERT INTO equipment (name, type, status, lend_out_date, return_date, people, phone ) " "VALUES (:name, :type, :status, :date_1, :date_2, :people, :phone)"); insertQuery.bindValue(":name", "离心机"); insertQuery.bindValue(":type", "生物设备"); insertQuery.bindValue(":status", 1); insertQuery.bindValue(":date_1", QDate(2022, 11, 20)); insertQuery.bindValue(":date_2", QDate(2023, 7, 9)); insertQuery.bindValue(":people", "张洪平"); insertQuery.bindValue(":phone", "19923688556"); if (!insertQuery.exec()) { qDebug() << "插入数据失败:" << insertQuery.lastError().text(); } } model = new QSqlTableModel(this); model->setTable("equipment"); // 设置数据库表名 model->setEditStrategy(QSqlTableModel::OnManualSubmit); // 手动提交修改 model->setSort(model->fieldIndex("ID"),Qt::AscendingOrder);//按id排序 model->select();//加载数据 // 设置列标题 model->setHeaderData(0, Qt::Horizontal, tr("ID")); model->setHeaderData(1, Qt::Horizontal, tr("设备名称")); model->setHeaderData(2, Qt::Horizontal, tr("设备类型")); model->setHeaderData(3, Qt::Horizontal, tr("借还状态")); model->setHeaderData(4, Qt::Horizontal, tr("借出日期")); model->setHeaderData(5,Qt::Horizontal, tr("归还日期")); model->setHeaderData(6, Qt::Horizontal, tr("借用人")); model->setHeaderData(7,Qt::Horizontal, tr("手机")); // 加载数据 if (!model->select()) { qDebug() << "数据加载失败:" << model->lastError().text(); } ui->tableView->setModel(model);//绑定模型 ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); ui->tableView->setModel(model); ui->tableView->resizeColumnsToContents(); // 自动调整列宽 ui->tableView->show(); } C::~C() { delete ui; } void C::on_pushButton_clicked()//返回按钮 { A *w=new A(); w->show(); this->hide(); } void C::on_pushButton_2_clicked()//退出按钮 { this->close(); } //借出记录 void C::on_action_triggered() { model->setFilter(""); } //归还记录 void C::on_action_2_triggered(){ model->setFilter("status <> 0");// 排除状态为0的记录 } void C::on_action_3_triggered() { QDialog dialog(this); dialog.setWindowTitle("添加新记录"); dialog.setMinimumWidth(300); // 创建布局 QVBoxLayout *mainLayout = new QVBoxLayout(&dialog); QFormLayout *formLayout = new QFormLayout(); // 创建输入控件 QLineEdit *nameEdit = new QLineEdit(&dialog);//equipment QLineEdit *typeEdit = new QLineEdit(&dialog); QLineEdit *lend_out_dateEdit = new QLineEdit(&dialog); QLineEdit *peopleEdit= new QLineEdit(&dialog); QLineEdit *phoneEdit= new QLineEdit(&dialog); // 添加控件到表单 formLayout->addRow("设备名称:", nameEdit); formLayout->addRow("设备类型:", typeEdit); formLayout->addRow("借出时间:", lend_out_dateEdit); formLayout->addRow("借用人:", peopleEdit); formLayout->addRow("手机·:", phoneEdit); // 创建按钮 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog); mainLayout->addLayout(formLayout); mainLayout->addWidget(buttonBox); // 连接按钮信号 connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); // 显示对话框并处理结果 if (dialog.exec() == QDialog::Accepted) { // 获取输入值 QString name = nameEdit->text().trimmed(); QString type = typeEdit->text().trimmed(); QString date_1= lend_out_dateEdit->text().trimmed(); QString date_2= ""; QString status = "0"; QString people = peopleEdit->text().trimmed(); QString phone = phoneEdit->text().trimmed(); // 验证输入 if (name.isEmpty()) { QMessageBox::warning(this, "输入错误", "设备名不能为空"); return; } // 在模型末尾插入新行 int rowNum = model->rowCount(); model->insertRow(rowNum); // 设置新记录的值 model->setData(model->index(rowNum, model->fieldIndex("ID")), rowNum+1); model->setData(model->index(rowNum, model->fieldIndex("设备名称")), name); model->setData(model->index(rowNum, model->fieldIndex("设备类型")), type); model->setData(model->index(rowNum, model->fieldIndex("借还状态")), status); model->setData(model->index(rowNum, model->fieldIndex("借用时间")), date_1); model->setData(model->index(rowNum, model->fieldIndex("归还时间")), date_2); model->setData(model->index(rowNum, model->fieldIndex("借用人")),people); model->setData(model->index(rowNum, model->fieldIndex("手机")), phone); // 自动滚动到新添加的行 ui->tableView->scrollToBottom(); } } 为什么最终table view仅显示了ID

#include "kchangemanage.h" #include "ui_kchangemanage.h" #include <QSqlTableModel> // 包含QSqlTableModel头文件 #include <QMessageBox> #include <QItemSelectionModel> #include "module/model/EquipmentDataModel.h" #include "module/model/filterproxymdel.h" using namespace view::equipment; kchangemanage::kchangemanage(QWidget *parent) : QDialog(parent), ui(new Ui::kchangemanage), m_model(nullptr), m_currentMatchIndex(-1) { ui->setupUi(this); //初始化模型 dataModel::EquipmentDataModel *modelRent = new dataModel::EquipmentDataModel(this); fliterModel::FilterProxyMdel *rentFilterProxyMdel = new fliterModel::FilterProxyMdel(this); rentFilterProxyMdel->setSourceModel(modelRent); //给视图指定模型 ui->tableView_change->setModel(rentFilterProxyMdel); ui->tableView_change->hideColumn(dataModel::EquipmentDataModel::Col_ID); ui->tableView_change->hideColumn(dataModel::EquipmentDataModel::Col_Count); ui->tableView_change->hideColumn(dataModel::EquipmentDataModel::Col_RentId); ui->tableView_change->hideColumn(dataModel::EquipmentDataModel::Col_ClassId); // 调整列宽以显示数据 ui->tableView_change->resizeColumnsToContents(); ui->tableView_change->horizontalHeader()->setStretchLastSection(true); // 加载数据 modelRent->fetchData(); // 调试信息 qDebug() << "Model row count:" << modelRent->rowCount(); qDebug() << "Model column count:" << modelRent->columnCount(); modelRent->select(); setModel(modelRent); // 调用类成员函数 } kchangemanage::~kchangemanage() { delete ui; } // 实现setModel(补充类作用域) void kchangemanage::setModel(QAbstractItemModel *model) { m_model = model; ui->tableView_change->setModel(m_model); } void kchangemanage::on_find_clicked() { QString keyword = ui->equipmentNameEdit->text().trimmed(); if (keyword.isEmpty()) { QMessageBox::warning(this, "提示", "请输入查找关键词!"); return; } // 调用成员函数获取匹配行号(返回模型中的行号列表) m_matchedRows = searchEquipment(keyword); m_currentMatchIndex = m_matchedRows.isEmpty() ? -1 : 0; if (m_matchedRows.isEmpty()) { QMessageBox::information(this, "查找结果", "未找到匹配项!"); return; } // 定位第一个匹配行 QModelIndex targetIndex = m_model->index(m_matchedRows.first(), 0); ui->tableView_change->selectionModel()->select(targetIndex, QItemSelectionModel::SelectCurrent); ui->tableView_change->scrollTo(targetIndex); } // 实现searchEquipment(返回模型中的匹配行号) QList<int> kchangemanage::searchEquipment(const QString &keyword) { QList<int> matchedRows; if (!m_model) return matchedRows; // 遍历模型所有行,检查设备名称列是否包含关键词(假设名称在第1列) for (int row = 0; row < m_model->rowCount(); ++row) { QModelIndex nameIndex = m_model->index(row, 1); // 第2列(0-based) QString name = m_model->data(nameIndex).toString(); if (name.contains(keyword, Qt::CaseInsensitive)) { matchedRows.append(row); } } return matchedRows; } void kchangemanage::on_change_clicked() { if (m_currentMatchIndex == -1 || m_matchedRows.isEmpty()) { QMessageBox::warning(this, "提示", "请先查找需要替换的设备!"); return; } QString newValue = ui->changeValueEdit->text().trimmed(); if (newValue.isEmpty()) { QMessageBox::warning(this, "错误", "替换值不能为空!"); return; } // 获取当前行的设备编号(假设编号在第0列) int currentRow = m_matchedRows[m_currentMatchIndex]; QModelIndex numberIndex = m_model->index(currentRow, 0); QString equipmentNumber = m_model->data(numberIndex).toString(); // 执行数据库更新(使用QSqlTableModel的setData方法,自动提交) QSqlTableModel *sqlModel = qobject_cast<QSqlTableModel*>(m_model); if (!sqlModel) { QMessageBox::critical(this, "错误", "模型类型不支持更新!"); return; } // 更新名称列(假设名称在第1列) if (sqlModel->setData(sqlModel->index(currentRow, 1), newValue)) { sqlModel->submitAll(); // 提交所有更改 sqlModel->select(); // 刷新数据(QSqlTableModel的select方法) QMessageBox::information(this, "成功", "替换完成!"); } else { QMessageBox::critical(this, "失败", "替换失败:" + sqlModel->lastError().text()); } } void kchangemanage::on_deleteButton_clicked() { if (m_currentMatchIndex == -1 || m_matchedRows.isEmpty()) { QMessageBox::warning(this, "提示", "请先查找需要删除的设备!"); return; } // 确认删除 if (QMessageBox::question(this, "确认", "是否删除选中设备?") != QMessageBox::Yes) { return; } // 获取当前行的设备编号(第0列) int currentRow = m_matchedRows[m_currentMatchIndex]; QModelIndex numberIndex = m_model->index(currentRow, 0); QString equipmentNumber = m_model->data(numberIndex).toString(); // 调用成员函数删除(返回成功行数) int deleted = deleteEquipmentByNumbers({equipmentNumber}); if (deleted > 0) { // 刷新模型(QSqlTableModel的select方法) QSqlTableModel *sqlModel = qobject_cast<QSqlTableModel*>(m_model); if (sqlModel) sqlModel->select(); m_matchedRows.removeAll(currentRow); // 移除匹配行 m_currentMatchIndex = -1; QMessageBox::information(this, "成功", "删除完成!"); } else { QMessageBox::critical(this, "失败", "删除失败!"); } } // 实现deleteEquipmentByNumbers(使用QSqlTableModel删除) int kchangemanage::deleteEquipmentByNumbers(const QStringList &equipmentNumbers) { int deletedCount = 0; QSqlTableModel *sqlModel = qobject_cast<QSqlTableModel*>(m_model); if (!sqlModel) return deletedCount; for (const QString &number : equipmentNumbers) { // 定位要删除的行 QModelIndexList indexes = sqlModel->match( sqlModel->index(0, 0), // 从第0行第0列开始(设备编号列) Qt::DisplayRole, number, 1, // 只找第一个匹配项 Qt::MatchExactly ); if (!indexes.isEmpty()) { int row = indexes.first().row(); if (sqlModel->removeRow(row)) { // 删除行 deletedCount++; } } } sqlModel->submitAll(); // 提交删除操作 return deletedCount; } void kchangemanage::on_next_clicked() { if (m_matchedRows.isEmpty()) return; m_currentMatchIndex = (m_currentMatchIndex + 1) % m_matchedRows.size(); QModelIndex targetIndex = m_model->index(m_matchedRows[m_currentMatchIndex], 0); ui->tableView_change->selectionModel()->select(targetIndex, QItemSelectionModel::SelectCurrent); ui->tableView_change->scrollTo(targetIndex); } void kchangemanage::on_before_clicked() { if (m_matchedRows.isEmpty()) return; m_currentMatchIndex = (m_currentMatchIndex - 1 + m_matchedRows.size()) % m_matchedRows.size(); QModelIndex targetIndex = m_model->index(m_matchedRows[m_currentMatchIndex], 0); ui->tableView_change->selectionModel()->select(targetIndex, QItemSelectionModel::SelectCurrent); ui->tableView_change->scrollTo(targetIndex); } void kchangemanage::on_cancelButton_clicked() { this->close(); } 根据构造函数内容补全更正使功能完善可用

namespace view::equipment { equipment_home::equipment_home(QWidget *parent) : QWidget(parent), ui(new view::equipment::Ui::equipment_home) { ui->setupUi(this); data::Equipment::buildDB(); data::Equipment::EquipmentClass::createEquipmentClassTable(); data::Equipment::EquipmentInstnace::createEquipmentInstanceTable(); //初始化模型 dataModel::EquipmentDataModel *modelRent = new dataModel::EquipmentDataModel(this); fliterModel::FilterProxyMdel *rentFilterProxyMdel = new fliterModel::FilterProxyMdel(this); rentFilterProxyMdel->setSourceModel(modelRent); //给视图指定模型 ui->tableView->setModel(rentFilterProxyMdel); ui->tableView->hideColumn(dataModel::EquipmentDataModel::Col_ID); ui->tableView->hideColumn(dataModel::EquipmentDataModel::Col_Count); ui->tableView->hideColumn(dataModel::EquipmentDataModel::Col_RentId); ui->tableView->hideColumn(dataModel::EquipmentDataModel::Col_ClassId); // 调整列宽以显示数据 ui->tableView->resizeColumnsToContents(); ui->tableView->horizontalHeader()->setStretchLastSection(true); // 加载数据 modelRent->fetchData(); // 调试信息 qDebug() << "Model row count:" << modelRent->rowCount(); qDebug() << "Model column count:" << modelRent->columnCount(); } 根据它完善下列代码: void equipment_home::on_kadd_clicked() //添加器材 { // 创建对话框并设置父对象(自动内存管理) kaddmanage *dialog = new kaddmanage(this); // 连接对话框的dataAdded信号到主界面的刷新函数(on_kreall_clicked) connect(dialog, &kaddmanage::dataAdded, this, [this]() { on_kreall_clicked(); // 调用整理库数据功能,刷新tableView }); // 显示对话框(模态或非模态均可,此处用show()非模态) dialog->show(); } void equipment_home::on_kreall_clicked() //整理库数据 { // 1. 确保数据库及表结构存在(原有功能) // 2. 加载所有设备完整记录 QList<data::Equipment::fullEquipmentRecord> records = data::Equipment::loadFullEquipmentRecords(); // 3. 按 "item" 字段升序排序(假设 "item" 对应设备名称 "name" 字段) // 使用 Qt 的字符串比较(支持本地化,类似Excel排序) std::sort(records.begin(), records.end(), [](const data::Equipment::fullEquipmentRecord& a, const data::Equipment::fullEquipmentRecord& b) { return QString::localeAwareCompare(a.name, b.name) < 0; // 升序排列 }); // 4. 将排序后的数据展示到 tableView(假设 UI 中构件名为 tableView) // 清空原有数据 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(ui->tableView->model()); if (!model) { model = new QStandardItemModel(this); // 设置表头(仅首次初始化时设置) model->setHorizontalHeaderLabels({ "ID", "设备名称", "状态","类别名称", "创建时间" }); ui->tableView->setModel(model); } model->removeRows(0, model->rowCount()); // 清空旧数据 // 填充排序后的数据 for (const auto& rec : records) { QList<QStandardItem*> items; items << new QStandardItem(QString::number(rec.id)) // ID << new QStandardItem(rec.name) // 设备名称(排序字段) << new QStandardItem(rec.status) // 状态 << new QStandardItem(rec.inDate.toString("yyyy-MM-dd hh:mm:ss")) // 创建时间 << new QStandardItem(QString::number(rec.class_id)) // 类别ID << new QStandardItem(rec.type); // 类别名称 model->appendRow(items); } // 可选:自动调整列宽 ui->tableView->resizeColumnsToContents(); log(service::LogLevel::INFO) << "数据库整理完成"; }

const QString modelSetDlg = "QDialog{background-color:rgb(18, 18, 18);}" "QTableView::item{background-color:rgb(41,41,41);}" "QTableView::item:hover{ background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(41,41,41), stop: 1 rgb(18,18,18));}" "QTableView::item:selected { background-color: qlineargradient(x1 : 0, y1 : 0, x2 : 0, y2 : 1,stop : 0 rgb(41,41,41), stop: 1 rgb(18,18,18)); outline: none;}" "QTableWidget[doubleClickedRow=\"true\"]::item { background-color: rgb(0, 128, 0); }" ; connect(ui.tableWidgetInspModel, &QTableWidget::itemDoubleClicked, this, &ModelSettingWnd::M_ItemDoubleClicked); void ModelSettingWnd::M_ItemDoubleClicked(QTableWidgetItem *item) { int row = item->row(); // 清除之前的高亮行 if (m_doubleClickRow_Check != -1 && m_doubleClickRow_Check != row) { for (int col = 0; col < ui.tableWidgetInspModel->columnCount(); ++col) { QTableWidgetItem *oldItem = ui.tableWidgetInspModel->item(m_doubleClickRow_Check, col); if (oldItem) { //oldItem->setData(Qt::UserRole, QVariant()); // 清除自定义属性 oldItem->setData(Qt::UserRole, ""); // 清除数据 oldItem->setData(Qt::UserRole + 1, false); // 清除动态属性 } } } // 设置新行高亮 for (int col = 0; col < ui.tableWidgetInspModel->columnCount(); ++col) { QTableWidgetItem *newItem = ui.tableWidgetInspModel->item(row, col); if (newItem) { // 设置自定义属性触发样式表 //newItem->setData(Qt::UserRole, "doubleClickedRow"); newItem->setData(Qt::UserRole + 1, true); // Qt::UserRole+1 作为动态属性存储 } } m_doubleClickRow_Check = row; ui.tableWidgetInspModel->update(); // 强制重绘 update(); } 双击没有反应,为什么?

#include "GActionFlow_Standard.h" #include "GActionFlow.h" #include "mhtparser.h" #include "ALTableTool.h" #include <algorithm> // 包含算法头文件 #include <QPushButton> #include "CGlobalVariant.h" #include <QSplineSeries> extern GActionFlow m_GActionFlow; extern MhtParser m_MhtParser; extern ALTableTool m_TableTool; extern CGlobalVariant m_Global; GActionFlow_Standard::GActionFlow_Standard() { } GActionFlow_Standard::~GActionFlow_Standard() { } // 导入傲来标准值流程 void GActionFlow_Standard::SFL_Action_ALStandardValue() { FinallyLoadStandard = false; // 读取data文件数据 QByteArray arr; if (-1 == m_GActionFlow.readDataFile(arr)) { QMessageBox::warning(NULL, "Failed!", m_GActionFlow.m_qstrError); return; } // 解析数据 QVector<ALData> vec_Data; if (-1 == m_GActionFlow.handleDataForAl(arr, vec_Data)) { QMessageBox::warning(NULL, "Failed!", m_GActionFlow.m_qstrError); return; } //将.data数据写到View上 StandardData2table(vec_Data); // 计算标准值平均值 StandardhowAvgData(); FinallyLoadStandard = true; } // 导入Pro10标准值流程 void GActionFlow_Standard::SFL_Action_Pro10StandardValue() { FinallyLoadStandard = false; // 读取data文件数据 QByteArray arr; if (-1 == m_GActionFlow.readDataFile(arr)) { QMessageBox::warning(NULL, "Failed!", m_GActionFlow.m_qstrError); return; } // 解析数据 QVector<ALData> vec_Data; if (-1 == m_GActionFlow.handleDataForPro10(arr, vec_Data)) { QMessageBox::warning(NULL, "Failed!", m_GActionFlow.m_qstrError); return; } //将.data数据写到View上 StandardData2table(vec_Data); // 计算标准值平均值 StandardhowAvgData(); FinallyLoadStandard = true; } void GActionFlow_Standard::SFL_Action_HRStandardValue(QTabWidget* tabWidget) { // 读取.mht文件 QVector<tagMeasurement> tagMeasureMent; if (-1 == m_GActionFlow.readMhtFile(tagMeasureMent)) { QMessageBox::warning(NULL, "Failed!", m_GActionFlow.m_qstrError); return; } // 将原始数据采用动态标签页的方式加载显示 Hr2Table(tagMeasureMent, tabWidget); } int GActionFlow_Standard::StandardData2table(QVector<ALData> vec_Data) { m_GActionFlow.row = 0; m_GActionFlow.col = 0; m_GActionFlow.Frequency = 110; m_GActionFlow.UnitConversion = 1000; m_GActionFlow.setItem(m_GActionFlow.row, m_GActionFlow.col, "频率:", Qt::green, Qt::yellow); m_GActionFlow.setItem(m_GActionFlow.row, m_GActionFlow.col + 1, QString::number(m_GActionFlow.Frequency), Qt::green, Qt::yellow); m_GActionFlow.setItem(m_GActionFlow.row, m_GActionFlow.col + 2, "单位:", Qt::green, Qt::yellow); m_GActionFlow.setItem(m_GActionFlow.row, m_GActionFlow.col + 3, QString::number(m_GActionFlow.UnitConversion), Qt::green, Qt::yellow); m_GActionFlow.row = 1; standard_start_row = m_GActionFlow.row; m_GActionFlow.setItem(m_GActionFlow.row, m_GActionFlow.col, "标准值", Qt::black, QColor(244, 164, 96)); m_GActionFlow.data2table(vec_Data); standard_end_row = m_GActionFlow.row; return 0; } // HR数据显示到table int GActionFlow_Standard::Hr2Table(QVector<tagMeasurement>& tagMeasureMent, QTabWidget* tabWidget) { int size = tagMeasureMent.size(); if (size <= 0) { m_strError = "没有数据用于显示"; return -1; } std::set<int> mySet; QVector<tagMeasurement> tagMeasureMentMTF; QVector<tagMeasurement> tagMeasureMentTF; QVector<tagMeasurement> tagMeasureMentTilt; SpliitMeasurement(tagMeasureMent, tabWidget, tagMeasureMentMTF, tagMeasureMentTF, tagMeasureMentTilt, mySet); ShowtagMeasureMentTilt(tagMeasureMentTilt); int tfStartRow; ShowtagMeasureMentMTF(tfStartRow, tagMeasureMentMTF); auto max = *std::max_element(mySet.begin(), mySet.end()); for (int i = 0; i < max; i++) { hr_source_rows[i] = tfStartRow; hr_source_cols[i] = 0; } int start4finadatarow = tfStartRow; ShowtagMeasureMentTF(start4finadatarow, tagMeasureMentTF); QMap<int, QMap<double, tagTableSections>> map_uutNumber4TableSections; ShortTFTableSections(tagMeasureMentTF, map_uutNumber4TableSections); FreashTfTable(); Measurement2TFTable(map_uutNumber4TableSections); return 0; } int GActionFlow_Standard::StandardhowAvgData() { standard_avg_row = standard_end_row + 1; standard_mtfandpeak_row = standard_avg_row + 1; m_GActionFlow.setItem(standard_avg_row, 0, "Avg:", Qt::green); m_GActionFlow.setItem(standard_mtfandpeak_row, 0, "MTFPeakAvg", Qt::gray); m_GActionFlow.row = standard_avg_row; StandardShowAvgData4EFL(); StandardShowAvgData4FFL(); StandardShowAvgData4MTF(); StandardShowAvgData4FS(); StandardShowAvgData4PEAK(); StandardShowAvgData4DOF(); StandardShowAvgData4MTFPeakAvg(); return 0; } int GActionFlow_Standard::StandardShowAvgData4EFL() { return m_GActionFlow.ShowAvgDataCol(standard_start_row, standard_end_row, m_GActionFlow.efl_col, m_GActionFlow.efl_col, standard_avg_row); } int GActionFlow_Standard::StandardShowAvgData4FFL() { return m_GActionFlow.ShowAvgDataCol(standard_start_row, standard_end_row, m_GActionFlow.ffl_col, m_GActionFlow.ffl_col, standard_avg_row); } int GActionFlow_Standard::StandardShowAvgData4MTF() { return m_GActionFlow.ShowAvgDataCol(standard_start_row, standard_end_row, m_GActionFlow.mtf_start_col, m_GActionFlow.mtf_end_col, standard_avg_row); } int GActionFlow_Standard::StandardShowAvgData4FS() { return m_GActionFlow.ShowAvgDataCol(standard_start_row, standard_end_row, m_GActionFlow.fs_start_col, m_GActionFlow.fs_end_col, standard_avg_row); } int GActionFlow_Standard::StandardShowAvgData4PEAK() { return m_GActionFlow.ShowAvgDataCol(standard_start_row, standard_end_row, m_GActionFlow.peak_start_col, m_GActionFlow.peak_end_col, standard_avg_row); } int GActionFlow_Standard::StandardShowAvgData4DOF() { return m_GActionFlow.ShowAvgDataCol(standard_start_row, standard_end_row, m_GActionFlow.dof_start_col, m_GActionFlow.dof_end_col, standard_avg_row); } int GActionFlow_Standard::StandardShowAvgData4MTFPeakAvg() { int temp = 0; for (int i = m_GActionFlow.mtf_start_col; i <= m_GActionFlow.mtf_end_col; i++) { QString avg1 = m_GActionFlow.theModel4Corr->headerData(i, Qt::Horizontal).toString() + m_GActionFlow.theModel4Corr->headerData(standard_avg_row, Qt::Vertical).toString(); QString avg2 = m_GActionFlow.theModel4Corr->headerData(m_GActionFlow.peak_start_col + temp++, Qt::Horizontal).toString() + m_GActionFlow.theModel4Corr->headerData(standard_avg_row, Qt::Vertical).toString(); QString str = QString("=(%1+%2)/2").arg(avg1).arg(avg2); m_GActionFlow.setItem(standard_mtfandpeak_row, i, str, Qt::gray); } return 0; } int GActionFlow_Standard::SpliitMeasurement(QVector<tagMeasurement>& tagMeasureMent, QTabWidget* tabWidget, QVector<tagMeasurement>& tagMeasureMentMTF, QVector<tagMeasurement>& tagMeasureMentTF, QVector<tagMeasurement>& tagMeasureMentTilt, std::set<int>& mySet) { int currentModelsSize = 0; int currentRowsSize = 0; int currentColsSize = 0; int number = 0; for (int i = 0; i < tagMeasureMent.size(); i++) { tagMeasurement measurement = tagMeasureMent.at(i); QString name = measurement.fileName; if (isFormatValidMTF(name)) { tagMeasureMentMTF.append(measurement); number = name.split("-").at(1).toInt(); } else if (isFormatValidTF(name)) { tagMeasureMentTF.append(measurement); number = name.split("-").at(1).toInt(); } else if (isFormatValidTilt(name)) { tagMeasureMentTilt.append(measurement); number = name.split("-").at(0).toInt(); } else { continue; } mySet.insert(number); int index = number - 1; // 索引应该退一位 ensureIndexExists(hr_source_models, currentModelsSize, index); ensureIndexExists(hr_source_rows, currentRowsSize, index); ensureIndexExists(hr_source_cols, currentColsSize, index); m_TableTool.findOrAddPage(tabWidget, QString::number(number), hr_source_models[index]); // 定位到具体页 } return 0; } int GActionFlow_Standard::ShowtagMeasureMentMTF(int& tfStartRow, QVector<tagMeasurement> tagMeasureMentMTF) { tfStartRow = 0; for each (tagMeasurement measurement in tagMeasureMentMTF) { QString name = measurement.fileName; QStringList list = name.split("-"); int number = list.at(1).toInt(); int index = number - 1; QStandardItemModel* model = hr_source_models[index]; int row = hr_source_rows[index]; int col = hr_source_cols[index]; int nextTableStartCol = 0; // 单个table开始列 int startRow = row;// 单个table初始行 QString angle = measurement.tagParam.tagMTFvsImageHeight.param.value("Sample Azimuth").trimmed(); m_TableTool.setItem(model, row++, col, angle); m_TableTool.setItem(model, row++, col, measurement.tagTable.tagMTFvsImageHeight.title); QVector<QStringList> datas = measurement.tagTable.tagMTFvsImageHeight.tableData; for (int j = 1; j < datas.size(); j++) { QStringList data = datas.at(j); int thisTableStartCol = col; for (int i = 0; i < data.size() - 1; i++) { QString var = data.at(i); m_TableTool.setItem(model, row, col++, var); } row++; nextTableStartCol = col + 1; col = thisTableStartCol; } // 存入下一个table tfStartRow = row + 1; row = startRow; hr_source_cols[index] = nextTableStartCol; // 间隔1列存储新的table } return 0; } int GActionFlow_Standard::ShowtagMeasureMentTF(int& start4finadatarow, QVector<tagMeasurement> tagMeasureMentTF) { for each (tagMeasurement measurement in tagMeasureMentTF) { QString name = measurement.fileName; QStringList list = name.split("-"); int number = list.at(1).toInt(); int ang = list.at(2).toInt(); int index = number - 1; QStandardItemModel* model = hr_source_models[index]; int row = hr_source_rows[index]; int col = hr_source_cols[index]; int nextTableStartCol = 0; // 单个table开始列 int startRow = row;// 单个table初始行 QString angle = measurement.tagParam.tagFieldFocus2DTangential.param.value("Sample Azimuth"); m_TableTool.setItem(model, row++, col, angle); m_TableTool.setItem(model, row++, col, measurement.tagTable.tagFieldFocus2DTangential.title); tagMeasurementTable table = measurement.tagTable.tagFieldFocus2DTangential; QVector<QStringList> datas = table.tableData; for (int j = 1; j < datas.size(); j++) { QStringList data = datas.at(j); int thisTableStartCol = col; for (int i = 0; i < data.size(); i++) { QString var = data.at(i); m_TableTool.setItem(model, row, col++, var); } row++; nextTableStartCol = col + 1; col = thisTableStartCol; } row++; angle = measurement.tagParam.tagFieldFocus2DSagittal.param.value("Sample Azimuth"); m_TableTool.setItem(model, row++, col, angle); m_TableTool.setItem(model, row++, col, measurement.tagTable.tagFieldFocus2DSagittal.title); table = measurement.tagTable.tagFieldFocus2DSagittal; datas = table.tableData; for (int j = 1; j < datas.size(); j++) { QStringList data = datas.at(j); int thisTableStartCol = col; for (int i = 0; i < data.size(); i++) { QString var = data.at(i); m_TableTool.setItem(model, row, col++, var); } row++; nextTableStartCol = col + 1; col = thisTableStartCol; } // 存入下一个table start4finadatarow = row + 1; row = startRow; hr_source_cols[index] = nextTableStartCol; // 间隔1列存储新的table } return 0; } int GActionFlow_Standard::ShortTFTableSections(QVector<tagMeasurement> tagMeasureMentTF, QMap<int, QMap<double, tagTableSections>>& map_uutNumber4TableSections) { int uutIndex = 1; while (true) { QMap<double, tagTableSections> map; // 存入角度,table for (int i = 0; i < tagMeasureMentTF.size(); i++) { tagMeasurement mea = tagMeasureMentTF.at(i); QString name = mea.fileName; QStringList list = name.split("-"); int uutNum = list[1].toInt(); int angle = list[2].remove(".mht").toDouble(); if (uutIndex == uutNum) { tagTableSections sections = mea.tagTable; map.insert(angle, sections); } } if (map.size() == 0) { break; } map_uutNumber4TableSections.insert(uutIndex, map); uutIndex++; } return 0; } int GActionFlow_Standard::Measurement2TFTable(QMap<int, QMap<double, tagTableSections>> map_uutNumber4TableSections) { QVector<QStringList> qvec_CamAngleTableCol; GetCamAngleTableCol(qvec_CamAngleTableCol); double angle = 0; int tabcol = 0; for (int i = 0; i < map_uutNumber4TableSections.size(); i++) { QMap<double, tagTableSections> map = map_uutNumber4TableSections.value(i + 1); int camNum = 1; int endRow = 0; QVector<QStringList> qvec_st; while (camNum < 13) { if (1 != GetCamAngleTableCol(qvec_CamAngleTableCol, camNum, angle, tabcol)) { break; } QStringList listS; QStringList listT; QStringList listFFL; QString titleSag = "S" + QString::number(camNum); listS.push_back(titleSag); QString titleTan = "T" + QString::number(camNum); listT.push_back(titleTan); camNum++; tagTableSections sections = map.value(angle); QVector<QStringList> tableData_sag = sections.tagFieldFocus2DSagittal.tableData; //int startRow = row; for (int j = 1; j < tableData_sag.size(); j++) { QStringList list = tableData_sag.at(j); QString ffl = list.at(0); listFFL.push_back(ffl); if (j == 1)// j=1筛选的FFL一列内容 { continue; } QString sag = list.at(tabcol - 1); sag = QString::number(sag.toDouble() * 100); listS.push_back(sag); //m_TableTool.setItem(model, row++, col, sag); } if (qvec_st.size() == 0) { qvec_st.push_back(listFFL); } //row = startRow; //col++; QVector<QStringList> tableData_tan = sections.tagFieldFocus2DTangential.tableData; for (int j = 2; j < tableData_tan.size(); j++) { QStringList list = tableData_sag.at(j); QString tan = list.at(tabcol - 1); tan = QString::number(tan.toDouble() * 100); listT.push_back(tan); //m_TableTool.setItem(model, row++, col, tan); } //endRow = row; //row = titleRow; //col++; qvec_st.push_back(listS); qvec_st.push_back(listT); } map_TfTable.insert(i + 1, qvec_st); //row = endRow + 1; //col = 1; } return 0; } int GActionFlow_Standard::ShowTFTableAndChart(QGridLayout* layout, QTableView* view) { int row = tf_start_row; int col = 1; QStandardItemModel* model = theModel4Tf; for (int i = 0; i < map_TfTable.size(); i++) { QVector<QStringList> vec = map_TfTable.value(i + 1); UpDataOneTableAndChart(vec, model, row, col, layout, view); } return 0; } int GActionFlow_Standard::UpDataOneTableAndChart(QVector<QStringList> one, QStandardItemModel* model, int& row, int& col, QGridLayout* layout, QTableView* view) { if (one.isEmpty()) { return -1; } // 缓存表格视图 m_currentTableView = view; DraggableChartView* chartView; QChart* chart; QValueAxis* axisX; QValueAxis* axisY; NewChart(chartView, chart, view); QStringList fflList = one.at(0); QString min = *std::min_element(fflList.begin(), fflList.end()); QString max = *std::max_element(fflList.begin(), fflList.end()); NewAxisX(chart, axisX, min.toDouble(), max.toDouble()); NewAxisY(chart, axisY, 0, 100); QString name = ""; int titleRow = row; int rowEnd = 0; // 更新一个表格 for (int j = 1; j < one.size(); j++) { QStringList list = one.at(j); QVector<QPointF> points; for (int k = 0; k < list.size(); k++) { QString var = list.at(k); QString ffl = fflList.at(k); if (k == 0) { name = var; } if (k != 0) { QPointF f; f.setX(ffl.toDouble()); f.setY(var.toDouble()); points.push_back(f); } m_TableTool.setItem(model, row, col, var); m_TableTool.setItem(model, row, 0, ffl); row++; } NewSeries(chartView, chart, axisX, axisY, points, name); rowEnd = row; row = titleRow; col++; } // 增添放Chart的空位 for (int i = titleRow; i < rowEnd; i++) { for (int j = col; j < col + 10; j++) { m_TableTool.setItem(model, i, j, ""); } } // 保存图表位置 ChartPosition pos; pos.startRow = titleRow; pos.startCol = col; pos.endRow = titleRow + 20; pos.endCol = col+ 8; // 更新位置 updateChartPosition(view, chartView, pos); row = rowEnd + 1; col = 1; return 0; } int GActionFlow_Standard::NewChart(DraggableChartView*& chartView, QChart*& chart, QTableView* view) { // 创建图表视图 chartView = new DraggableChartView(view->viewport()); chartView->setRenderHint(QPainter::Antialiasing); //抗锯齿 chartView->setRubberBand(QChartView::NoRubberBand); // 禁止缩放 // 设置透明背景 chartView->setStyleSheet("background: transparent;"); chartView->setAttribute(Qt::WA_TranslucentBackground); chart = new QChart; chart->setTheme(QChart::ChartThemeLight); chart->setTitle("Through Focus Curves"); // 禁用图表本身的交互标志 chart->setAcceptHoverEvents(false); chartView->setChart(chart); chartView->show(); // 连接信号 QObject::connect(chartView, &DraggableChartView::seriesFocusChanged, this, &GActionFlow_Standard::showQLineSeriesLinkTable); return 0; } int GActionFlow_Standard::NewAxisX(QChart*& chart, QValueAxis*& axisX, double min, double max) { //创建坐标轴X axisX = new QValueAxis; axisX->setRange(min, max); axisX->setTitleText("FFL [mm]"); axisX->setTickCount(8); axisX->setLabelFormat("%.3f"); axisX->setLabelsAngle(-30); axisX->setGridLineVisible(false); axisX->setMinorGridLineVisible(false); chart->addAxis(axisX, Qt::AlignBottom); return 0; } int GActionFlow_Standard::NewAxisY(QChart *& chart, QValueAxis *& axisY, double min, double max) { //创建坐标轴Y axisY = new QValueAxis; axisY->setRange(min, max); // 设置范围 axisY->setTitleText("MTF [%]"); //设置标题 axisY->setTickCount((max - min) / 10.0); // 设置刻度数量(包括最小和最大值) axisY->setLabelFormat("%d"); // 设置标签格式 chart->addAxis(axisY, Qt::AlignLeft); return 0; } int GActionFlow_Standard::NewSeries(DraggableChartView*& chartView, QChart*& chart, QValueAxis* axisX, QValueAxis* axisY, QVector<QPointF> points, QString seriesName) { // 创建数据序列 QSplineSeries *series = new QSplineSeries(); series->setName(seriesName); series->append(points.toList()); series->setVisible(true); // 设置系列样式 QPen pen; pen.setWidth(2); pen.setColor(QColor(rand() % 256, rand() % 256, rand() % 256)); series->setPen(pen); // 创建散点序列(用于显示选中的点) QtCharts::QScatterSeries *selectedPoint = new QtCharts::QScatterSeries(); selectedPoint->setMarkerShape(QScatterSeries::MarkerShapeCircle); selectedPoint->setMarkerSize(10.0); // 放大显示点 selectedPoint->setColor(Qt::red); // 红色高亮 selectedPoint->setName(""); selectedPoint->hide(); // 关键调用:隐藏图例项 // 添加到图表 chart->addSeries(series); chart->addSeries(selectedPoint); chart->legend()->setAlignment(Qt::AlignRight); chart->legend()->setVisible(true); // 将序列附加到坐标轴 series->attachAxis(axisX); series->attachAxis(axisY); selectedPoint->attachAxis(axisX); selectedPoint->attachAxis(axisY); // 添加悬停效果 QObject::connect(series, &QSplineSeries::hovered, [series, chartView](const QPointF& point, bool state) { if (state) { QPen hoverPen = series->pen(); hoverPen.setWidth(4); series->setPen(hoverPen); chartView->setCursor(Qt::PointingHandCursor); } else { QPen normalPen = series->pen(); normalPen.setWidth(2); series->setPen(normalPen); chartView->setCursor(Qt::ArrowCursor); } }); // 注册到图表视图 chartView->registerSeries(series, selectedPoint); return 0; } int GActionFlow_Standard::GetCamAngleTableCol(QVector<QStringList>& qvec_CamAngleTableCol) { QStandardItemModel* model = theModel4Tf; int row = 1; int col = 0; for (int row = 1; row < model->rowCount(); row++) { QStringList list; if (model->item(row, col) != nullptr) { QString camNumber = model->item(row, col)->text(); QString angle = model->item(row, col + 1)->text(); QString table_col = model->item(row, col + 2)->text(); list.push_back(camNumber); list.push_back(angle); list.push_back(table_col); qvec_CamAngleTableCol.push_back(list); } } return 0; } int GActionFlow_Standard::GetCamAngleTableCol(QVector<QStringList>& qvec_CamAngleTableCol, int cam, double & angle, int & tableCol) { if (qvec_CamAngleTableCol.size() <= 0) { return -1; } for (int i = 0; i < qvec_CamAngleTableCol.size(); i++) { QStringList list = qvec_CamAngleTableCol.at(i); if (list.first().toInt() == cam) { angle = list.at(1).toDouble(); tableCol = list.at(2).toInt(); return 1; } } return 0; } int GActionFlow_Standard::ShowtagMeasureMentTilt(QVector<tagMeasurement> tagMeasureMentTilt) { for each (tagMeasurement measurement in tagMeasureMentTilt) { QString name = measurement.fileName; QStringList list = name.split("-"); int number = list.at(0).toInt(); int index = number - 1; int nextTableStartCol = 0; // 单个table开始列 int startRow = hr_source_rows[index];// 单个table初始行 QString angle = list.at(1) + "°"; QStandardItemModel* model = hr_source_models[index]; m_TableTool.setItem(model, startRow, hr_source_cols[index]++, angle); m_TableTool.setItem(model, hr_source_rows[index]++, hr_source_cols[index]--, measurement.tagTable.tagFieldFocus2DSagittal.title); QVector<QStringList> datas = measurement.tagTable.tagFieldFocus2DSagittal.tableData; } return 0; } bool GActionFlow_Standard::isFormatValidMTF(const QString & input) { QRegularExpressionMatch matchMtf = regexMtf.match(input); if (matchMtf.hasMatch()) { return true; } return false; } bool GActionFlow_Standard::isFormatValidTF(const QString & input) { QRegularExpressionMatch matchTf = regexTF.match(input); if (matchTf.hasMatch()) { return true; } // 返回是否匹配成功 return false; } bool GActionFlow_Standard::isFormatValidTilt(const QString & input) { QRegularExpressionMatch matchTilt = regexTilt.match(input); if (matchTilt.hasMatch()) { return true; } // 返回是否匹配成功 return false; } void GActionFlow_Standard::InitView4Tf(QTableView *& view) { theModel4Tf = new QStandardItemModel(); view->setModel(theModel4Tf); } void GActionFlow_Standard::updateChartPosition(QTableView* view, DraggableChartView* chartView, ChartPosition pos) { // 此处可以添加图表位置管理逻辑 // 例如存储图表位置信息以便后续访问 Q_UNUSED(view); Q_UNUSED(chartView); Q_UNUSED(pos); if (!chartView->isVisible()) { return; } QRect rect = calculateChartGeometry(view, pos.startRow, pos.startCol, pos.endRow, pos.endCol); chartView->setGeometry(rect); chartView->raise(); // 确保在最上层 } QRect GActionFlow_Standard::calculateChartGeometry(QTableView* view, int startRow, int startCol, int endRow, int endCol) { // 计算图表在表格中的位 int x = view->columnViewportPosition(startCol); int width = view->columnViewportPosition(endCol) + view->columnWidth(endCol) - x; // 垂直位置(从第2行开始,到倒数第2行结束) int y = view->rowViewportPosition(startRow); int height = view->rowViewportPosition(endRow) + view->rowHeight(endRow) - y; // 添加边距 int margin = 10; return QRect(x + margin, y + margin, width - 2 * margin, height - 2 * margin); } void GActionFlow_Standard::FreashTfTable() { QStandardItemModel* model = theModel4Tf; int row = 0; int col = 0; m_TableTool.setItem(model, row, col++, "相机序号"); m_TableTool.setItem(model, row, col++, "角度"); m_TableTool.setItem(model, row, col++, "对应列"); col = 0; row++; m_TableTool.setItem(model, row, col, "1"); m_TableTool.setItem(model, row, col + 1, "0"); m_TableTool.setItem(model, row, col + 2, "4"); row++; m_TableTool.setItem(model, row, col, "2"); m_TableTool.setItem(model, row, col + 1, "0"); m_TableTool.setItem(model, row, col + 2, "3"); row++; m_TableTool.setItem(model, row, col, "3"); m_TableTool.setItem(model, row, col + 1, "90"); m_TableTool.setItem(model, row, col + 2, "5"); row++; m_TableTool.setItem(model, row, col, "4"); m_TableTool.setItem(model, row, col + 1, "0"); m_TableTool.setItem(model, row, col + 2, "5"); row++; m_TableTool.setItem(model, row, col, "5"); m_TableTool.setItem(model, row, col + 1, "90"); m_TableTool.setItem(model, row, col + 2, "3"); row++; m_TableTool.setItem(model, row, col, "6"); m_TableTool.setItem(model, row, col + 1, "126.87/135"); m_TableTool.setItem(model, row, col + 2, "6"); row++; m_TableTool.setItem(model, row, col, "7"); m_TableTool.setItem(model, row, col + 1, "36.87/45"); m_TableTool.setItem(model, row, col + 2, "6"); row++; m_TableTool.setItem(model, row, col, "8"); m_TableTool.setItem(model, row, col + 1, "126.87/135"); m_TableTool.setItem(model, row, col + 2, "2"); row++; m_TableTool.setItem(model, row, col, "9"); m_TableTool.setItem(model, row, col + 1, "36.87/45"); m_TableTool.setItem(model, row, col + 2, "2"); tf_start_row = row + 2; } void GActionFlow_Standard::showQLineSeriesLinkTable(QSplineSeries* focusedSeries) { if (!m_currentTableView) { return; } //// 清除之前的选择 //m_currentTableView->selectionModel()->clearSelection(); clearHighlights(); if (focusedSeries == nullptr) { return; } // 获取表格模型 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(m_currentTableView->model()); if (!model) { return; } QVector<double> ffl; QVector<double> st; const auto points = focusedSeries->points(); for (int i = 0; i < points.size(); i++) { QPointF f = points.at(i); ffl.push_back(f.x()); st.push_back(f.y()); } QMap<int, int> mapFFl; QMap<int, int> mapST; // 表格上寻找符合的数(x轴数据) for (int row = 0; row < model->rowCount(); row++) { int col = 0; // x轴参数对应第一列 // 检查连续行是否有足够的数据 if (row + ffl.size() > model->rowCount()) { continue; } bool allMatch = true; for (int i = 0; i < ffl.size(); i++) { if (model->item(row + i, col) == nullptr) { allMatch = false; break; } QString var = model->item(row + i, col)->text(); if (ffl.at(i) != var.toDouble()) // 使用精度比较浮点数 { allMatch = false; break; } } if (allMatch) { for (int i = 0; i < ffl.size(); i++) { mapFFl.insert(row + i, col); } break; } } QList<int> keys = mapFFl.keys(); if (keys.isEmpty()) return; // 没有找到匹配的FFL数据 // 表格上寻找符合的数(y轴数据) for (int col = 1; col < model->columnCount(); col++) { int startRow = keys.first(); // 检查连续行是否有足够的数据 if (startRow + st.size() > model->rowCount()) { continue; } bool allMatch = true; for (int i = 0; i < st.size(); i++) { if (model->item(startRow + i, col) == nullptr) { allMatch = false; break; } QString var = model->item(startRow + i, col)->text(); if (st.at(i) != var.toDouble()) // 使用精度比较浮点数 { allMatch = false; break; } } if (allMatch) { for (int i = 0; i < st.size(); i++) { mapST.insert(startRow + i, col); } break; } } // 框选显示 if (!mapFFl.isEmpty()) { highlightRegion(mapFFl, QColor(128, 0, 128, 100)); // 紫色半透明 } if (!mapST.isEmpty()) { highlightRegion(mapST, QColor(0, 0, 255, 100)); // 蓝色半透明 } } // 高亮显示连续区域(只绘制外框) void GActionFlow_Standard::highlightRegion(const QMap<int, int>& cellMap, const QColor& color) { if (!m_currentTableView) return; QStandardItemModel* model = qobject_cast<QStandardItemModel*>(m_currentTableView->model()); if (!model) return; // 获取区域的边界 int minRow = INT_MAX, maxRow = INT_MIN; int minCol = INT_MAX, maxCol = INT_MIN; for (auto it = cellMap.constBegin(); it != cellMap.constEnd(); ++it) { int row = it.key(); int col = it.value(); if (row < minRow) minRow = row; if (row > maxRow) maxRow = row; if (col < minCol) minCol = col; if (col > maxCol) maxCol = col; } // 获取视觉矩形 QRect visualRect = getVisualRect(minRow, minCol, maxRow, maxCol); if (visualRect.isEmpty()) return; // 创建自定义覆盖层 HighlightOverlay* overlay = new HighlightOverlay(m_currentTableView->viewport(), color); overlay->setGeometry(visualRect); overlay->show(); m_overlays.append(overlay); } // 获取视觉区域矩形 QRect GActionFlow_Standard::getVisualRect(int startRow, int startCol, int endRow, int endCol) const { if (!m_currentTableView || !m_currentTableView->model()) return QRect(); QModelIndex topLeft = m_currentTableView->model()->index(startRow, startCol); QModelIndex bottomRight = m_currentTableView->model()->index(endRow, endCol); if (!topLeft.isValid() || !bottomRight.isValid()) return QRect(); QRect rect1 = m_currentTableView->visualRect(topLeft); QRect rect2 = m_currentTableView->visualRect(bottomRight); return rect1.united(rect2); } // 清除所有高亮 void GActionFlow_Standard::clearHighlights() { // 删除所有覆盖层 for (QWidget* overlay : m_overlays) { overlay->deleteLater(); } m_overlays.clear(); } /** * 确保指针数组在指定索引处存在有效对象 * * @param hr_source_models 指向指针数组的三级指针(允许修改原始数组) * @param currentSize 指向当前数组大小的指针(允许修改大小值) * @param index 需要确保存在的索引位置 */ void GActionFlow_Standard::ensureIndexExists(QStandardItemModel **& hr_source_models, int& currentSize, int index) { if (index < 0) { throw std::invalid_argument("索引不能为负数"); } // 检查是否需要扩容 if (index >= currentSize) { // 计算新大小(至少比所需索引大1) int newSize = index + 1; // 创建新数组 QStandardItemModel** newArray = new QStandardItemModel*[newSize](); // 初始化为 nullptr // 复制旧数据(如果存在) if (hr_source_models != nullptr) { for (int i = 0; i < currentSize; ++i) { newArray[i] = (hr_source_models)[i]; } delete[] hr_source_models; // 删除旧数组 } // 初始化新增元素 for (int i = currentSize; i < newSize; ++i) { newArray[i] = new QStandardItemModel(); // 创建新对象 } // 更新指针和大小 hr_source_models = newArray; currentSize = newSize; } // 确保索引处对象有效 if ((hr_source_models)[index] == nullptr) { (hr_source_models)[index] = new QStandardItemModel(); } } void GActionFlow_Standard::ensureIndexExists(int*& row, int& currentSize, int index) { if (index < 0) { throw std::invalid_argument("索引不能为负数"); } // 检查是否需要扩容 if (index >= currentSize) { // 计算新大小(至少比所需索引大1) int newSize = index + 1; // 创建新数组 int* newArray = new int[newSize](); // 初始化为 nullptr // 复制旧数据(如果存在) if (row != nullptr) { for (int i = 0; i < currentSize; ++i) { newArray[i] = (row)[i]; } delete[] row; // 删除旧数组 } // 初始化新增元素 for (int i = currentSize; i < newSize; ++i) { newArray[i] = 0; // 创建新对象 } // 更新指针和大小 row = newArray; currentSize = newSize; } // 确保索引处对象有效 if ((hr_source_models)[index] == nullptr) { (hr_source_models)[index] = new QStandardItemModel(); } } QList<QTableView*> GActionFlow_Standard::findViewsByModel(QStandardItemModel * model) { QList<QTableView*> result; // 获取所有顶层窗口 const QWidgetList topLevelWidgets = QApplication::topLevelWidgets(); for (QWidget* widget : topLevelWidgets) { // 递归搜索所有 QTableView const QList<QTableView*> tableViews = widget->findChildren<QTableView*>(); for (QTableView* view : tableViews) { // 检查视图的模型是否匹配目标模型 if (view->model() == model) { result.append(view); } } } return result; } void GActionFlow_Standard::ensureRectItemsExist(QStandardItemModel * model, const QRect & rect) { if (!model) { qWarning() << "Model is null!"; return; } // 获取矩形区域边界 int topRow = rect.top(); int bottomRow = rect.bottom(); int leftCol = rect.left(); int rightCol = rect.right(); // 验证矩形边界是否有效 if (topRow < 0 || leftCol < 0 || bottomRow < topRow || rightCol < leftCol) { qWarning() << "Invalid rectangle coordinates:" << rect; return; } // 调整模型大小以确保矩形区域存在 if (model->rowCount() <= bottomRow) { model->setRowCount(bottomRow + 1); } if (model->columnCount() <= rightCol) { model->setColumnCount(rightCol + 1); } //// 遍历矩形区域内的所有单元格 //for (int row = topRow; row <= bottomRow; ++row) //{ // for (int col = leftCol; col <= rightCol; ++col) // { // // 检查单元格是否存在 // if (!model->item(row, col)) // { // // 创建新单元格并设置默认值 // QStandardItem* newItem = new QStandardItem(); // newItem->setText(QString("R%1C%2").arg(row).arg(col)); // newItem->setData(QColor(Qt::lightGray), Qt::BackgroundRole); // model->setItem(row, col, newItem); // qDebug() << "Created item at:" << row << col; // } // } //} } const QRegularExpression GActionFlow_Standard::regexMtf("^MTF-\\d+-\\d+\\.mht$"); const QRegularExpression GActionFlow_Standard::regexTF("^TF-\\d+-\\d+\\.mht$"); const QRegularExpression GActionFlow_Standard::regexTilt("^\\d+-\\d+\\.mht$");点击曲线后,legend不要更改

最新推荐

recommend-type

Comsol声子晶体能带计算:六角与三角晶格原胞选取及布里渊区高对称点选择 - 声子晶体 v1.0

内容概要:本文详细探讨了利用Comsol进行声子晶体能带计算过程中,六角晶格和三角晶格原胞选取的不同方法及其对简约布里渊区高对称点选择的影响。文中不仅介绍了两种晶格类型的基矢量定义方式,还强调了正确设置周期性边界条件(特别是相位补偿)的重要性,以避免计算误差如鬼带现象。同时,提供了具体的MATLAB代码片段用于演示关键步骤,并分享了一些实践经验,例如如何通过观察能带图中的狄拉克锥特征来验证路径设置的准确性。 适合人群:从事材料科学、物理学研究的专业人士,尤其是那些正在使用或计划使用Comsol软件进行声子晶体模拟的研究人员。 使用场景及目标:帮助研究人员更好地理解和掌握在Comsol环境中针对不同类型晶格进行精确的声子晶体能带计算的方法和技术要点,从而提高仿真精度并减少常见错误的发生。 其他说明:文章中提到的实际案例展示了因晶格类型混淆而导致的问题,提醒使用者注意细节差异,确保模型构建无误。此外,文中提供的代码片段可以直接应用于相关项目中作为参考模板。
recommend-type

springboot213大学生心理健康管理系统的设计与实现.zip

springboot213大学生心理健康管理系统的设计与实现
recommend-type

Web前端开发:CSS与HTML设计模式深入解析

《Pro CSS and HTML Design Patterns》是一本专注于Web前端设计模式的书籍,特别针对CSS(层叠样式表)和HTML(超文本标记语言)的高级应用进行了深入探讨。这本书籍属于Pro系列,旨在为专业Web开发人员提供实用的设计模式和实践指南,帮助他们构建高效、美观且可维护的网站和应用程序。 在介绍这本书的知识点之前,我们首先需要了解CSS和HTML的基础知识,以及它们在Web开发中的重要性。 HTML是用于创建网页和Web应用程序的标准标记语言。它允许开发者通过一系列的标签来定义网页的结构和内容,如段落、标题、链接、图片等。HTML5作为最新版本,不仅增强了网页的表现力,还引入了更多新的特性,例如视频和音频的内置支持、绘图API、离线存储等。 CSS是用于描述HTML文档的表现(即布局、颜色、字体等样式)的样式表语言。它能够让开发者将内容的表现从结构中分离出来,使得网页设计更加模块化和易于维护。随着Web技术的发展,CSS也经历了多个版本的更新,引入了如Flexbox、Grid布局、过渡、动画以及Sass和Less等预处理器技术。 现在让我们来详细探讨《Pro CSS and HTML Design Patterns》中可能包含的知识点: 1. CSS基础和选择器: 书中可能会涵盖CSS基本概念,如盒模型、边距、填充、边框、背景和定位等。同时还会介绍CSS选择器的高级用法,例如属性选择器、伪类选择器、伪元素选择器以及选择器的组合使用。 2. CSS布局技术: 布局是网页设计中的核心部分。本书可能会详细讲解各种CSS布局技术,包括传统的浮动(Floats)布局、定位(Positioning)布局,以及最新的布局模式如Flexbox和CSS Grid。此外,也会介绍响应式设计的媒体查询、视口(Viewport)单位等。 3. 高级CSS技巧: 这些技巧可能包括动画和过渡效果,以及如何优化性能和兼容性。例如,CSS3动画、关键帧动画、转换(Transforms)、滤镜(Filters)和混合模式(Blend Modes)。 4. HTML5特性: 书中可能会深入探讨HTML5的新标签和语义化元素,如`<article>`、`<section>`、`<nav>`等,以及如何使用它们来构建更加标准化和语义化的页面结构。还会涉及到Web表单的新特性,比如表单验证、新的输入类型等。 5. 可访问性(Accessibility): Web可访问性越来越受到重视。本书可能会介绍如何通过HTML和CSS来提升网站的无障碍访问性,比如使用ARIA标签(Accessible Rich Internet Applications)来增强屏幕阅读器的使用体验。 6. 前端性能优化: 性能优化是任何Web项目成功的关键。本书可能会涵盖如何通过优化CSS和HTML来提升网站的加载速度和运行效率。内容可能包括代码压缩、合并、避免重绘和回流、使用Web字体的最佳实践等。 7. JavaScript与CSS/HTML的交互: 在现代Web开发中,JavaScript与CSS及HTML的交云并用是不可或缺的。书中可能会讲解如何通过JavaScript动态地修改样式、操作DOM元素以及使用事件监听和响应用户交互。 8. Web框架和预处理器: 这本书可能会提到流行的Web开发框架和预处理器,比如Bootstrap、Foundation、Sass和Less等,它们是如何简化和加速开发流程的。 9. 测试和维护: 书中也可能包含关于如何测试网页以及如何持续优化和维护CSS和HTML代码的章节。例如,使用断言测试、自动化测试、性能分析工具等。 最后,鉴于文件名称列表中的“压缩包子文件”的表述,这可能是对“压缩包”文件的一种误译或误用,此处“压缩包”应该指的是包含该书籍PDF文件的压缩文件格式,如ZIP或RAR。而“Pro CSS and HTML Design Patterns.pdf”指的就是该书籍的PDF格式电子版文件。 以上所述,构成了《Pro CSS and HTML Design Patterns》一书可能包含的核心知识点。通过学习这些内容,Web前端开发者可以掌握更为高效和优雅的设计模式,从而在日常工作中更高效地解决实际问题。
recommend-type

Zotero 7数据同步:Attanger插件安装&设置,打造文献管理利器

/i.s3.glbimg.com/v1/AUTH_08fbf48bc0524877943fe86e43087e7a/internal_photos/bs/2018/L/j/ipKA8TRPyt4ptaG1DGww/t-m-01.png) # 1. Zotero 7数据同步简介 在数字时代,管理研究数据变得日益重要,而Zot
recommend-type

卷积神经网络的基础理论200字

<think>我们正在回答用户关于卷积神经网络(CNN)基础理论的询问。根据提供的引用资料,我们可以概述CNN的基本结构和工作原理。引用[1]提到CNN是一种前馈神经网络,信息从输入单向流动到输出。引用[2]指出CNN在图像处理等领域应用广泛,通过层次结构和参数调整实现模式识别。引用[3]说明CNN包含卷积层,使用卷积核提取局部特征,减少参数量,提高效率。引用[4]则提到了训练过程,包括前向传播、误差计算和反向传播(梯度下降)。因此,我们将从以下几个方面概述CNN:1.CNN的基本结构(卷积层、池化层、全连接层)2.卷积操作的工作原理(局部感受野、权重共享)3.训练过程(前向传播、损失函数、反
recommend-type

轻便实用的Java库类查询工具介绍

标题 "java2库类查询" 和描述表明,所提及的工具是一个专门用于查询Java库类的应用程序。此软件旨在帮助开发者快速地查找和引用Java的标准开发工具包(SDK)中包含的所有应用程序编程接口(API)类。通过这样的工具,开发者可以节省大量在官方文档或搜索引擎上寻找类定义和使用方法的时间。它被描述为轻巧且方便,这表明其占用的系统资源相对较少,同时提供直观的用户界面,使得查询过程简洁高效。 从描述中可以得出几个关键知识点: 1. Java SDK:Java的软件开发工具包(SDK)是Java平台的一部分,提供了一套用于开发Java应用软件的软件包和库。这些软件包通常被称为API,为开发者提供了编程界面,使他们能够使用Java语言编写各种类型的应用程序。 2. 库类查询:这个功能对于开发者来说非常关键,因为它提供了一个快速查找特定库类及其相关方法、属性和使用示例的途径。良好的库类查询工具可以帮助开发者提高工作效率,减少因查找文档而中断编程思路的时间。 3. 轻巧性:软件的轻巧性通常意味着它对计算机资源的要求较低。这样的特性对于资源受限的系统尤为重要,比如老旧的计算机、嵌入式设备或是当开发者希望最小化其开发环境占用空间时。 4. 方便性:软件的方便性通常关联于其用户界面设计,一个直观、易用的界面可以让用户快速上手,并减少在使用过程中遇到的障碍。 5. 包含所有API:一个优秀的Java库类查询软件应当能够覆盖Java所有标准API,这包括Java.lang、Java.util、Java.io等核心包,以及Java SE平台的所有其他标准扩展包。 从标签 "java 库 查询 类" 可知,这个软件紧密关联于Java编程语言的核心功能——库类的管理和查询。这些标签可以关联到以下知识点: - Java:一种广泛用于企业级应用、移动应用(如Android应用)、网站后端、大型系统和许多其他平台的编程语言。 - 库:在Java中,库是一组预打包的类和接口,它们可以被应用程序重复使用。Java提供了庞大的标准库,以支持各种常见的任务和功能。 - 查询:查询指的是利用软件工具搜索、定位和检索信息的过程。对于Java库类查询工具来说,这意味着可以通过类名、方法签名或其他标识符来查找特定的API条目。 最后,压缩包文件列表包含了两个文件:“java.dit”和“Java.exe”。其中“Java.exe”很可能是程序的可执行文件,而“java.dit”可能是一个数据文件,用于存储Java类的索引或数据。由于文件名后缀通常与文件类型相关联,但“dit”并不是一个常见的文件扩展名。这可能是一个特定于软件的自定义格式,或是一个打字错误。 总结来说,"java2库类查询" 是一个针对Java开发者的实用工具,它提供了一个轻量级、易用的平台来查询和定位Java标准库中的所有类和API。此工具对优化开发流程,减少查找Java类文档的时间大有裨益,尤其适合需要频繁查阅Java API的开发者使用。
recommend-type

【Zotero 7终极指南】:新手必备!Attanger插件全攻略与数据同步神技

# 1. Zotero 7与Attanger插件的介绍 在当今的学术研究和知识管理领域,高效的文献管理工具至关重要。Zotero 7作为一个流行的参考文献管理软件,因其强大的功能和用户友好的界面而受到专业人士的青睐。而Attanger插件则为Zotero 7带来了更多定制化和高级功能,极大地增强
recommend-type

MATLAB整段注释快捷键

<think>首先,用户的问题是:“MATLAB整段注释快捷键”,意思是“MATLAB整段注释快捷键”。我需要用中文回答。 根据规则: - 回答必须用中文。 - 回答完问题后,必须在末尾输出“§§相关问题§§”,然后提出3-5个相关问题。 - “§§相关问题§§”必须完整输出在第一行,禁止换行分散。 - 相关问题必须基于用户的问题和我的回答。 现在,回忆MATLAB的快捷键:在MATLAB中,整段注释通常使用快捷键Ctrl + R来注释选中的代码行,使用Ctrl + T来取消注释。用户问的是“整段注释”,所以我应该确认快捷键。 在MATLAB中: - 注释选中的行:Ctrl + R -
recommend-type

Eclipse Jad反编译插件:提升.class文件查看便捷性

反编译插件for Eclipse是一个专门设计用于在Eclipse集成开发环境中进行Java反编译的工具。通过此类插件,开发者可以在不直接访问源代码的情况下查看Java编译后的.class文件的源代码,这在开发、维护和学习使用Java技术的过程中具有重要的作用。 首先,我们需要了解Eclipse是一个跨平台的开源集成开发环境,主要用来开发Java应用程序,但也支持其他诸如C、C++、PHP等多种语言的开发。Eclipse通过安装不同的插件来扩展其功能。这些插件可以由社区开发或者官方提供,而jadclipse就是这样一个社区开发的插件,它利用jad.exe这个第三方命令行工具来实现反编译功能。 jad.exe是一个反编译Java字节码的命令行工具,它可以将Java编译后的.class文件还原成一个接近原始Java源代码的格式。这个工具非常受欢迎,原因在于其反编译速度快,并且能够生成相对清晰的Java代码。由于它是一个独立的命令行工具,直接使用命令行可以提供较强的灵活性,但是对于一些不熟悉命令行操作的用户来说,集成到Eclipse开发环境中将会极大提高开发效率。 使用jadclipse插件可以很方便地在Eclipse中打开任何.class文件,并且将反编译的结果显示在编辑器中。用户可以在查看反编译的源代码的同时,进行阅读、调试和学习。这样不仅可以帮助开发者快速理解第三方库的工作机制,还能在遇到.class文件丢失源代码时进行紧急修复工作。 对于Eclipse用户来说,安装jadclipse插件相当简单。一般步骤包括: 1. 下载并解压jadclipse插件的压缩包。 2. 在Eclipse中打开“Help”菜单,选择“Install New Software”。 3. 点击“Add”按钮,输入插件更新地址(通常是jadclipse的更新站点URL)。 4. 选择相应的插件(通常名为“JadClipse”),然后进行安装。 5. 安装完成后重启Eclipse,插件开始工作。 一旦插件安装好之后,用户只需在Eclipse中双击.class文件,或者右键点击文件并选择“Open With Jadclipse”,就能看到对应的Java源代码。如果出现反编译不准确或失败的情况,用户还可以直接在Eclipse中配置jad.exe的路径,或者调整jadclipse的高级设置来优化反编译效果。 需要指出的是,使用反编译工具虽然方便,但要注意反编译行为可能涉及到版权问题。在大多数国家和地区,反编译软件代码属于合法行为,但仅限于学习、研究、安全测试或兼容性开发等目的。如果用户意图通过反编译获取商业机密或进行非法复制,则可能违反相关法律法规。 总的来说,反编译插件for Eclipse是一个强大的工具,它极大地简化了Java反编译流程,提高了开发效率,使得开发者在没有源代码的情况下也能有效地维护和学习Java程序。但开发者在使用此类工具时应遵守法律与道德规范,避免不当使用。
recommend-type

【进阶Python绘图】:掌握matplotlib坐标轴刻度间隔的高级技巧,让你的图表脱颖而出

# 摘要 本文系统地探讨了matplotlib库中坐标轴刻度间隔的定制与优化技术。首先概述了matplotlib坐标轴刻度间隔的基本概念及其在图表中的重要性,接