QT6 源(29):QHash<key,T> 的源码阅读

(1)

(2)

谢谢

#ifndef CUSTOMDEVICESMANAGER_H #define CUSTOMDEVICESMANAGER_H #include "scada.h" #include "qtpropertybrowser.h" #include "qtpropertymanager.h" #include <QScopedPointer> #include <QVariantMap> #include <QList> class CustomDevicesManagerPrivate; // DeviceManager class CustomDevicesManager : public QtAbstractPropertyManager { Q_OBJECT public: explicit CustomDevicesManager(QObject* parent = nullptr); ~CustomDevicesManager() override; // get the substring item manager QtStringPropertyManager* subStringPropertyManager() const; // get the ScadaHash struct. Graphics::ScadaHash value(const QtProperty* property) const; bool isManagedProperty(const QtProperty *property) const; QString getValueText(const QtProperty* property) { return valueText(property); } void initDeviceProperty(QtProperty* property) { initializeProperty(property); } void uninitDeviceProperty(QtProperty* property) { uninitializeProperty(property); } // get the property value corresponding to the attribute use QString. QString valueText(const QtProperty* property) const override; public slots: // set the scada property with ScadaHash. void setValue(QtProperty* property, const Graphics::ScadaHash& val); signals: void valueChanged(QtProperty* property, const Graphics::ScadaHash& val); void buttonClicked(QtProperty* property); protected: void initializeProperty(QtProperty* property) override; void uninitializeProperty(QtProperty* property) override; private: QScopedPointer<CustomDevicesManagerPrivate> d_ptr; Q_DECLARE_PRIVATE(CustomDevicesManager) Q_DISABLE_COPY(CustomDevicesManager) // according to the Qt base manager settings. Q_PRIVATE_SLOT(d_func(), void slotStringChanged(QtProperty*, const QString&)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty*)) }; // DevicesManagerPrivate(PIMPL) class CustomDevicesManagerPrivate { CustomDevicesManager* q_ptr; Q_DECLARE_PUBLIC(CustomDevicesManager) public: void slotStringChanged(QtProperty* property, const QString& value); void slotPropertyDestroyed(QtProperty* property); // map from QtProperty to the ScadaHash. typedef QMap<const QtProperty*, Graphics::ScadaHash> PropertyValueMap; PropertyValueMap m_values; // the string manager to the editor lineEdior. QtStringPropertyManager* m_stringPropertyManager = nullptr; // let all these parameters be in one group. QtGroupPropertyManager* m_groupPropertyManager = nullptr; // map the master property to the childern parameters. QMap<const QtProperty*, QList<QtProperty*>> m_propertyToScadas; // 主属性→参数复合属性列表(参数1、参数2...) QMap<const QtProperty*, QList<QtProperty*>> m_scadaToFields; // 参数复合属性→字段子属性列表(LineEdit 对应的字段) QMap<const QtProperty*, QtProperty*> m_fieldToScada; // 字段子属性→所属参数复合属性 QMap<const QtProperty*, QtProperty*> m_scadaToDevice; // 参数复合属性→所属主属性 QMap<const QtProperty*, QString> m_fieldToMember; // 字段子属性→对应数据的键名(QVariantMap 的 key) QMap<const QtProperty*, Graphics::ScadaKey> m_scadaToKey; // Scada复合属性→对应的ScadaKey(用于显示) }; #endif // CUSTOMDEVICESMANAGER_H #include "customdevicesmanager.h" #include <QCoreApplication> #include <QDebug> #include <QMetaProperty> // ====================== private class(CustomDevicesManagerPrivate)====================== void CustomDevicesManagerPrivate::slotStringChanged(QtProperty* fieldProp, const QString& value) { // // 反向查找:字段→Scada复合属性→主属性 // QtProperty* scadaProp = m_fieldToScada.value(fieldProp, nullptr); // QtProperty* deviceProp = m_scadaToDevice.value(scadaProp, nullptr); // QString memberName = m_fieldToMember.value(fieldProp, ""); // if (!scadaProp || !deviceProp || memberName.isEmpty()) return; // // 查找对应的 ScadaKey 和 ScadaPtr // Graphics::ScadaHash& scadaHash = m_values[deviceProp]; // Graphics::ScadaKey scadaKey = m_scadaToKey.value(scadaProp); // if (!scadaHash.contains(scadaKey)) return; // // 更新 ScadaPtr 的元属性值 // Graphics::ScadaPtr scadaPtr = scadaHash[scadaKey]; // if (!scadaPtr) return; // // 按元属性名赋值 // if (memberName == "code") scadaPtr->setCode(value); // else if (memberName == "domain") scadaPtr->setDomain(value); // else if (memberName == "type") scadaPtr->setType(value.toInt()); // else if (memberName == "substation") scadaPtr->setSubstation(value); // else if (memberName == "tableName") scadaPtr->setTableName(value); // else if (memberName == "realTableName") scadaPtr->setRealTableName(value); // else if (memberName == "deviceId") scadaPtr->setDeviceId(value); // else if (memberName == "deviceCode") scadaPtr->setDeviceCode(value); // emit q_ptr->valueChanged(deviceProp, scadaHash); QtProperty* scadaProp = m_fieldToScada.value(fieldProp, nullptr); QtProperty* deviceProp = m_scadaToDevice.value(scadaProp, nullptr); QString memberName = m_fieldToMember.value(fieldProp, ""); if (!scadaProp || !deviceProp || memberName.isEmpty()) return; Graphics::ScadaHash& scadaHash = m_values[deviceProp]; Graphics::ScadaKey scadaKey = m_scadaToKey.value(scadaProp); if (!scadaHash.contains(scadaKey)) return; Graphics::ScadaPtr scadaPtr = scadaHash[scadaKey]; if (!scadaPtr) return; //Get properties through QMetaObject reflection. const QMetaObject* metaObj = scadaPtr->metaObject(); int propIndex = metaObj->indexOfProperty(memberName.toUtf8().constData()); if (propIndex == -1) { qDebug() << "[slotStringChanged] Scada don't have " << memberName << " property,return"; return; } QMetaProperty metaProp = metaObj->property(propIndex); if (metaProp.isWritable()) { // QString/int if (metaProp.type() == QMetaType::QString) { metaProp.write(scadaPtr.get(), QVariant(value)); // } else if (metaProp.type() == QMetaType::Int) { metaProp.write(scadaPtr.get(), QVariant(value.toInt())); } else if (metaProp.type() == QMetaType::Double) { metaProp.write(scadaPtr.get(), QVariant(value.toDouble())); } else { qDebug() << "[slotStringChanged] " << metaProp.typeName() << "(" << memberName << ")"; } } else { qDebug() << "[slotStringChanged] Property" << memberName << "can't writable, jump"; } emit q_ptr->valueChanged(deviceProp, scadaHash); } void CustomDevicesManagerPrivate::slotPropertyDestroyed(QtProperty* fieldProp) { // 清理映射关系 // -A| // ----B1| // -------C1| // -------C2| QtProperty* scadaProp = m_fieldToScada.take(fieldProp);//B if (scadaProp) {//B QtProperty* deviceProp = m_scadaToDevice.value(scadaProp, nullptr);//A if (deviceProp) {//A m_scadaToFields[scadaProp].removeAll(fieldProp);//C if (m_scadaToFields[scadaProp].isEmpty()) {//C m_propertyToScadas[deviceProp].removeAll(scadaProp);//B m_scadaToDevice.remove(scadaProp);//A m_scadaToFields.remove(scadaProp);//C m_scadaToKey.remove(scadaProp); } } m_fieldToMember.remove(fieldProp); } } // ====================== 主管理器类(CustomDevicesManager)====================== CustomDevicesManager::CustomDevicesManager(QObject* parent) : QtAbstractPropertyManager(parent) , d_ptr(new CustomDevicesManagerPrivate) { Q_D(CustomDevicesManager); d->q_ptr = this; // sub String manager. d->m_stringPropertyManager = new QtStringPropertyManager(this); // sub manager signals. connect(d->m_stringPropertyManager, &QtStringPropertyManager::valueChanged, this, [d](QtProperty* prop, const QString& val) { d->slotStringChanged(prop, val); }); connect(d->m_stringPropertyManager, &QtStringPropertyManager::propertyDestroyed, this, [d](QtProperty* prop) { d->slotPropertyDestroyed(prop); }); // group manager. d_ptr->m_groupPropertyManager = new QtGroupPropertyManager(this); // destroyed. connect(d->m_groupPropertyManager, &QtGroupPropertyManager::propertyDestroyed, this, [d](QtProperty* prop) { d->slotPropertyDestroyed(prop); }); } CustomDevicesManager::~CustomDevicesManager() { clear(); } QtStringPropertyManager* CustomDevicesManager::subStringPropertyManager() const { Q_D(const CustomDevicesManager); return d->m_stringPropertyManager; } Graphics::ScadaHash CustomDevicesManager::value(const QtProperty* property) const { Q_D(const CustomDevicesManager); return d->m_values.value(property, Graphics::ScadaHash()); } bool CustomDevicesManager::isManagedProperty(const QtProperty *property) const { Q_D(const CustomDevicesManager); return d->m_values.contains(property); // 直接检查核心映射是否包含该属性 } void CustomDevicesManager::setValue(QtProperty* property, const Graphics::ScadaHash& val) { Q_D(CustomDevicesManager); const auto it = d->m_values.find(property); if (it == d->m_values.end()) return; if (it.value() == val) return; it.value() = val; QList<QtProperty*>& scadaProps = d->m_propertyToScadas[property]; // 关键1:清理无效属性(仅保留val中存在的scadaProp) QList<QtProperty*> validScadaProps; for (QtProperty* prop : scadaProps) { Graphics::ScadaKey key = d->m_scadaToKey.value(prop); if (val.contains(key)) { validScadaProps.append(prop); } else { QList<QtProperty*>& fieldProps = d->m_scadaToFields[prop]; for (QtProperty* fieldProp : fieldProps) { d->m_fieldToScada.remove(fieldProp); d->m_fieldToMember.remove(fieldProp); delete fieldProp; } d->m_scadaToDevice.remove(prop); d->m_scadaToFields.remove(prop); d->m_scadaToKey.remove(prop); delete prop; } } scadaProps = validScadaProps; // 关键2:用QHash替代QMap(无需ScadaKey重载<运算符) QHash<Graphics::ScadaKey, QtProperty*> scadaKeyToProp; for (QtProperty* prop : scadaProps) { scadaKeyToProp.insert(d->m_scadaToKey.value(prop), prop); } // 遍历val,更新或创建属性 int scadaIdx = 0; for (auto hashIt = val.begin(); hashIt != val.end(); ++hashIt) { Graphics::ScadaKey scadaKey = hashIt.key(); Graphics::ScadaPtr scadaPtr = hashIt.value(); QtProperty* scadaProp = scadaKeyToProp.take(scadaKey); // 优先复用 if (!scadaProp) { // 无复用才创建 scadaProp = d->m_groupPropertyManager->addProperty(); scadaProps.append(scadaProp); d->m_scadaToDevice[scadaProp] = property; d->m_scadaToKey[scadaProp] = scadaKey; property->addSubProperty(scadaProp); } // 更新属性名和tooltip scadaProp->setPropertyName(QString("参数%1").arg(scadaIdx + 1)); scadaProp->setToolTip(QString("code: %1, tableName: %2").arg(scadaKey.code).arg(scadaKey.tableName)); // 提取元属性(不变) QList<QPair<QString, QString>> metaProps; if (scadaPtr) { const QMetaObject* metaObj = scadaPtr->metaObject(); for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) { QMetaProperty metaProp = metaObj->property(i); if (!metaProp.isReadable() || !metaProp.isWritable()) continue; QString memberName = metaProp.name(); QString memberLabel = memberName; for (int j = 1; j < memberLabel.size(); ++j) { if (memberLabel[j].isUpper() && memberLabel[j-1].isLower()) { memberLabel.insert(j, ' '); j++; } } memberLabel[0] = memberLabel[0].toUpper(); metaProps.append({memberName, memberLabel}); } } // 处理子属性字段(不变) QList<QtProperty*>& fieldProps = d->m_scadaToFields[scadaProp]; while (fieldProps.size() > metaProps.size()) { QtProperty* delFieldProp = fieldProps.takeLast(); d->m_fieldToScada.remove(delFieldProp); d->m_fieldToMember.remove(delFieldProp); delete delFieldProp; } // 动态创建/更新子字段(不变) for (int fieldIdx = 0; fieldIdx < metaProps.size(); ++fieldIdx) { QString memberName = metaProps[fieldIdx].first; QString memberLabel = metaProps[fieldIdx].second; QtProperty* fieldProp = nullptr; if (fieldIdx < fieldProps.size()) { fieldProp = fieldProps[fieldIdx]; fieldProp->setPropertyName(memberLabel); } else { fieldProp = d->m_stringPropertyManager->addProperty(); fieldProp->setPropertyName(memberLabel); fieldProps.append(fieldProp); d->m_fieldToScada[fieldProp] = scadaProp; d->m_fieldToMember[fieldProp] = memberName; scadaProp->addSubProperty(fieldProp); } // 设置字段值(不变) QString fieldValue; if (scadaPtr) { const QMetaObject* metaObj = scadaPtr->metaObject(); int propIdx = metaObj->indexOfProperty(memberName.toUtf8().constData()); if (propIdx != -1) { QMetaProperty metaProp = metaObj->property(propIdx); QVariant propValue = metaProp.read(scadaPtr.get()); fieldValue = propValue.toString(); } } d->m_stringPropertyManager->setValue(fieldProp, fieldValue); } scadaIdx++; } emit propertyChanged(property); emit valueChanged(property, val); // Q_D(CustomDevicesManager); // const auto it = d->m_values.find(property); // if (it == d->m_values.end()) return; // if (it.value() == val) return; // it.value() = val; // QList<QtProperty*>& scadaProps = d->m_propertyToScadas[property]; // // remove the redundant property. // while (scadaProps.size() > val.size()) { // QtProperty* delScadaProp = scadaProps.takeLast(); // QList<QtProperty*>& fieldProps = d->m_scadaToFields[delScadaProp]; // for (QtProperty* fieldProp : fieldProps) { // d->m_fieldToScada.remove(fieldProp); // d->m_fieldToMember.remove(fieldProp); // delete fieldProp; // } // d->m_scadaToDevice.remove(delScadaProp); // d->m_scadaToFields.remove(delScadaProp); // d->m_scadaToKey.remove(delScadaProp); // delete delScadaProp; // } // // iterate the val // int scadaIdx = 0; // for (auto hashIt = val.begin(); hashIt != val.end(); ++hashIt) { // Graphics::ScadaKey scadaKey = hashIt.key(); // Graphics::ScadaPtr scadaPtr = hashIt.value(); // QtProperty* scadaProp = nullptr; // // 复用或创建复合属性(参数X) // if (scadaIdx < scadaProps.size()) { // scadaProp = scadaProps[scadaIdx]; // scadaProp->setPropertyName(QString("参数%1").arg(scadaIdx + 1)); // scadaProp->setToolTip(QString("code: %1, tableName: %2").arg(scadaKey.code).arg(scadaKey.tableName)); // } else { // scadaProp = d->m_groupPropertyManager->addProperty(); // scadaProp->setPropertyName(QString("参数%1").arg(scadaIdx + 1)); // scadaProp->setToolTip(QString("code: %1, tableName: %2").arg(scadaKey.code).arg(scadaKey.tableName)); // scadaProps.append(scadaProp); // d->m_scadaToDevice[scadaProp] = property; // d->m_scadaToKey[scadaProp] = scadaKey; // property->addSubProperty(scadaProp); // } // // 3. 从 ScadaPtr 元对象中提取元属性(动态替代固定memberList) // QList<QPair<QString, QString>> metaProps; // <属性名(memberName), 显示标签> // if (scadaPtr) { // const QMetaObject* metaObj = scadaPtr->metaObject(); // // 遍历所有可读写的属性(跳过父类继承的属性,仅保留自身属性) // for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) { // QMetaProperty metaProp = metaObj->property(i); // // 关键修正:删除!metaProp.isUser(),避免过滤所有属性 // if (!metaProp.isReadable() || !metaProp.isWritable()) continue; // QString memberName = metaProp.name(); // 属性名(如"code") // // 核心:属性名自动转人性化显示(兼容所有Qt版本) // QString memberLabel = memberName; // for (int j = 1; j < memberLabel.size(); ++j) { // // 驼峰命名分隔(如"tableName"→"Table Name") // if (memberLabel[j].isUpper() && memberLabel[j-1].isLower()) { // memberLabel.insert(j, ' '); // j++; // 跳过新增的空格,避免连续分隔 // } // } // // 首字母大写(如"table name"→"Table Name") // memberLabel[0] = memberLabel[0].toUpper(); // metaProps.append({memberName, memberLabel}); // } // } // // 4. 处理元属性字段(LineEdit) // QList<QtProperty*>& fieldProps = d->m_scadaToFields[scadaProp]; // while (fieldProps.size() > metaProps.size()) { // QtProperty* delFieldProp = fieldProps.takeLast(); // d->m_fieldToScada.remove(delFieldProp); // d->m_fieldToMember.remove(delFieldProp); // delete delFieldProp; // } // // 5. 动态创建/更新字段(无固定字符串判断) // for (int fieldIdx = 0; fieldIdx < metaProps.size(); ++fieldIdx) { // QString memberName = metaProps[fieldIdx].first; // QString memberLabel = metaProps[fieldIdx].second; // QtProperty* fieldProp = nullptr; // if (fieldIdx < fieldProps.size()) { // fieldProp = fieldProps[fieldIdx]; // fieldProp->setPropertyName(memberLabel); // } else { // fieldProp = d->m_stringPropertyManager->addProperty(); // fieldProp->setPropertyName(memberLabel); // fieldProps.append(fieldProp); // d->m_fieldToScada[fieldProp] = scadaProp; // d->m_fieldToMember[fieldProp] = memberName; // scadaProp->addSubProperty(fieldProp); // 子项关联到复合属性 // } // // 动态设置字段值(通过元属性读取,替代固定if判断) // QString fieldValue; // if (scadaPtr) { // const QMetaObject* metaObj = scadaPtr->metaObject(); // int propIdx = metaObj->indexOfProperty(memberName.toUtf8().constData()); // if (propIdx != -1) { // QMetaProperty metaProp = metaObj->property(propIdx); // QVariant propValue = metaProp.read(scadaPtr.get()); // fieldValue = propValue.toString(); // } // } // d->m_stringPropertyManager->setValue(fieldProp, fieldValue); // } // scadaIdx++; // } // emit propertyChanged(property); // emit valueChanged(property, val); // Q_D(CustomDevicesManager); // const auto it = d->m_values.find(property); // if (it == d->m_values.end()) return; // if (it.value() == val) return; // // 更新核心数据(ScadaHash) // it.value() = val; // // 动态创建/更新 Scada 复合属性(参数1、参数2...) // QList<QtProperty*>& scadaProps = d->m_propertyToScadas[property]; // // 1. 移除多余的复合属性 // while (scadaProps.size() > val.size()) { // QtProperty* delScadaProp = scadaProps.takeLast(); // QList<QtProperty*>& fieldProps = d->m_scadaToFields[delScadaProp]; // for (QtProperty* fieldProp : fieldProps) { // d->m_fieldToScada.remove(fieldProp); // d->m_fieldToMember.remove(fieldProp); // delete fieldProp; // } // d->m_scadaToDevice.remove(delScadaProp); // d->m_scadaToFields.remove(delScadaProp); // d->m_scadaToKey.remove(delScadaProp); // delete delScadaProp; // } // // 2. 定义 Scada 元属性(名称+显示标签) // QList<QPair<QString, QString>> memberList; // memberList.append(QPair<QString, QString>("code", "代码")); // memberList.append(QPair<QString, QString>("domain", "域名")); // memberList.append(QPair<QString, QString>("type", "类型")); // memberList.append(QPair<QString, QString>("substation", "厂站")); // memberList.append(QPair<QString, QString>("tableName", "参数库表名")); // memberList.append(QPair<QString, QString>("realTableName", "实时库表名")); // memberList.append(QPair<QString, QString>("deviceId", "设备ID")); // memberList.append(QPair<QString, QString>("deviceCode", "设备代码")); // // 3. 遍历 ScadaHash,创建/更新复合属性和字段 // int scadaIdx = 0; // for (auto hashIt = val.begin(); hashIt != val.end(); ++hashIt) { // Graphics::ScadaKey scadaKey = hashIt.key(); // Graphics::ScadaPtr scadaPtr = hashIt.value(); // QtProperty* scadaProp = nullptr; // // 复用或创建复合属性(参数X) // if (scadaIdx < scadaProps.size()) { // scadaProp = scadaProps[scadaIdx]; // // 核心:复合属性的“值列”显示 ScadaKey(code + tableName) // scadaProp->setPropertyName(QString("参数%1").arg(scadaIdx + 1)); // scadaProp->setToolTip(QString("code: %1, tableName: %2").arg(scadaKey.code).arg(scadaKey.tableName)); // } else { // scadaProp = d->m_groupPropertyManager->addProperty(); // scadaProp->setPropertyName(QString("参数%1").arg(scadaIdx + 1)); // scadaProp->setToolTip(QString("code: %1, tableName: %2").arg(scadaKey.code).arg(scadaKey.tableName)); // scadaProps.append(scadaProp); // d->m_scadaToDevice[scadaProp] = property; // d->m_scadaToKey[scadaProp] = scadaKey; // property->addSubProperty(scadaProp); // } // // 4. 处理元属性字段(LineEdit) // QList<QtProperty*>& fieldProps = d->m_scadaToFields[scadaProp]; // while (fieldProps.size() > memberList.size()) { // QtProperty* delFieldProp = fieldProps.takeLast(); // d->m_fieldToScada.remove(delFieldProp); // d->m_fieldToMember.remove(delFieldProp); // delete delFieldProp; // } // // 创建/更新字段 // for (int fieldIdx = 0; fieldIdx < memberList.size(); ++fieldIdx) { // QString memberName = memberList[fieldIdx].first; // QString memberLabel = memberList[fieldIdx].second; // QtProperty* fieldProp = nullptr; // if (fieldIdx < fieldProps.size()) { // fieldProp = fieldProps[fieldIdx]; // fieldProp->setPropertyName(memberLabel); // } else { // fieldProp = d->m_stringPropertyManager->addProperty(); // fieldProp->setPropertyName(memberLabel); // fieldProps.append(fieldProp); // d->m_fieldToScada[fieldProp] = scadaProp; // d->m_fieldToMember[fieldProp] = memberName; // scadaProp->addSubProperty(fieldProp); // } // // 设置字段值(从 ScadaPtr 读取) // QString fieldValue; // if (scadaPtr) { // if (memberName == "code") fieldValue = scadaPtr->getCode(); // else if (memberName == "domain") fieldValue = scadaPtr->getDomain(); // else if (memberName == "type") fieldValue = QString::number(scadaPtr->getType()); // else if (memberName == "substation") fieldValue = scadaPtr->getSubstation(); // else if (memberName == "tableName") fieldValue = scadaPtr->getTableName(); // else if (memberName == "realTableName") fieldValue = scadaPtr->getRealTableName(); // else if (memberName == "deviceId") fieldValue = scadaPtr->getDeviceId(); // else if (memberName == "deviceCode") fieldValue = scadaPtr->getDeviceCode(); // } // d->m_stringPropertyManager->setValue(fieldProp, fieldValue); // } // scadaIdx++; // } // emit propertyChanged(property); // emit valueChanged(property, val); } QString CustomDevicesManager::valueText(const QtProperty* property) const { Q_D(const CustomDevicesManager); const auto it = d->m_values.constFind(property); if (it == d->m_values.constEnd()) return QString(); // 主属性显示:ScadaHash 数据量概览 const Graphics::ScadaHash& scadaHash = it.value(); int totalFieldCount = scadaHash.size() * 8; // 每个 Scada 8 个字段 return QString("数据点配置(%1个数据点,共%2个字段)").arg(scadaHash.size()).arg(totalFieldCount); } void CustomDevicesManager::initializeProperty(QtProperty* property) { Q_D(CustomDevicesManager); if (!d->m_values.contains(property)) { d->m_values[property] = Graphics::ScadaHash(); d->m_propertyToScadas[property] = QList<QtProperty*>(); } } void CustomDevicesManager::uninitializeProperty(QtProperty* property) { Q_D(CustomDevicesManager); QList<QtProperty*>& scadaProps = d->m_propertyToScadas[property]; for (QtProperty* scadaProp : scadaProps) { QList<QtProperty*>& fieldProps = d->m_scadaToFields[scadaProp]; for (QtProperty* fieldProp : fieldProps) { d->m_fieldToScada.remove(fieldProp); d->m_fieldToMember.remove(fieldProp); delete fieldProp; } d->m_scadaToDevice.remove(scadaProp); d->m_scadaToFields.remove(scadaProp); d->m_scadaToKey.remove(scadaProp); delete scadaProp; } d->m_propertyToScadas.remove(property); d->m_values.remove(property); } 我是用qtdesigner的源码相关的属性编辑器,加了自定义的属性,结果,我现在每次setValue都会导致私有类定义的数据结构里面的个数都增加1
最新发布
12-04
分析编译错误:/home/shz/Project/appHDQt6/parammanager.cpp:96: error: no match for ‘operator==’ (operand types are ‘const ParamMetaData’ and ‘const T’ {aka ‘const ParamMetaData’}) In file included from ../../Qt6/6.7.3/gcc_64/include/QtCore/QMap:1, from ../appHDQt6/parammanager.h:5, from ../appHDQt6/parammanager.cpp:1: ../../Qt6/6.7.3/gcc_64/include/QtCore/qmap.h: In instantiation of ‘QMapData<AMap>::valueIsEqualTo(const T&) [with AMap = std::map<QString, ParamMetaData, std::less<QString>, std::allocator<std::pair<const QString, ParamMetaData> > >; QMapData<AMap>::T = ParamMetaData]::<lambda(const auto:29&)> [with auto:29 = std::pair<const QString, ParamMetaData>]’: /usr/include/c++/9/bits/predefined_ops.h:283:11: required from ‘bool __gnu_cxx::__ops::_Iter_pred<_Predicate>::operator()(_Iterator) [with _Iterator = std::_Rb_tree_const_iterator<std::pair<const QString, ParamMetaData> >; _Predicate = QMapData<AMap>::valueIsEqualTo(const T&) [with AMap = std::map<QString, ParamMetaData, std::less<QString>, std::allocator<std::pair<const QString, ParamMetaData> > >; QMapData<AMap>::T = ParamMetaData]::<lambda(const auto:29&)>]’ /usr/include/c++/9/bits/stl_algo.h:104:42: required from ‘_InputIterator std::__find_if(_InputIterator, _InputIterator, _Predicate, std::input_iterator_tag) [with _InputIterator = std::_Rb_tree_const_iterator<std::pair<const QString, ParamMetaData> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<QMapData<AMap>::valueIsEqualTo(const T&) [with AMap = std::map<QString, ParamMetaData, std::less<QString>, std::allocator<std::pair<const QString, ParamMetaData> > >; QMapData<AMap>::T = ParamMetaData]::<lambda(const auto:29&)> >]’ /usr/include/c++/9/bits/stl_algo.h:161:23: required from ‘_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = std::_Rb_tree_const_iterator<std::pair<const QString, ParamMetaData> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<QMapData<AMap>::valueIsEqualTo(const T&) [with AMap = std::map<QString, ParamMetaData, std::less<QString>, std::allocator<std::pair<const QString, ParamMetaData> > >; QMapData<AMap>::T = ParamMetaData]::<lambda(const auto:29&)> >]’ /usr/include/c++/9/bits/stl_algo.h:3969:28: required from ‘_IIter std::find_if(_IIter, _IIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<std::pair<const QString, ParamMetaData> >; _Predicate = QMapData<AMap>::valueIsEqualTo(const T&) [with AMap = std::map<QString, ParamMetaData, std::less<QString>, std::allocator<std::pair<const QString, ParamMetaData> > >; QMapData<AMap>::T = ParamMetaData]::<lambda(const auto:29&)>]’ ../../Qt6/6.7.3/gcc_64/include/QtCore/qmap.h:83:30: required from ‘QMapData<AMap>::Key QMapData<AMap>::key(const T&, const Key&) const [with AMap = std::map<QString, ParamMetaData, std::less<QString>, std::allocator<std::pair<const QString, ParamMetaData> > >; QMapData<AMap>::Key = QString; QMapData<AMap>::T = ParamMetaData]’ ../../Qt6/6.7.3/gcc_64/include/QtCore/qmap.h:353:40: required from ‘Key QMap<Key, T>::key(const T&, const Key&) const [with Key = QString; T = ParamMetaData]’ ../appHDQt6/parammanager.cpp:96:43: required from here ../../Qt6/6.7.3/gcc_64/include/QtCore/qmap.h:78:58: error: no match for ‘operator==’ (operand types are ‘const ParamMetaData’ and ‘const T’ {aka ‘const ParamMetaData’}) 78 | return [&value](const auto &v) { return v.second == value; }; | ~~~~~~~~~^~~~~~~~
06-08
<think>嗯,用户遇到了C++编译错误,具体是关于在Qt6环境下重载QMap的operator==时出现的类型匹配问题。看起来是在使用自定义类型ParamMetaData作为QMap的键时,编译器找不到匹配的operator==重载。用户的问题描述得很专业,直接指出了核心错误"nomatchforoperator=="。这说明用户对C++有相当基础,而且已经定位到了问题大致范围。不过从报错内容看,用户可能忽略了自定义类型作为关联容器键时需要满足严格的条件。我记得Qt的关联容器和STL容器类似,要求键类型必须可比较。而用户使用的ParamMetaData类型显然没有定义相等运算符。虽然用户尝试重载operator==,但似乎没有正确定义在正确的命名空间或格式。这里的关键点在于:-QMap的底层实现要求键类型支持operator<-但使用qEquals或直接比较两个QMap时,要求键值对中的键和值都支持operator==-特别是当键类型为用户自定义类型时,必须明确定义operator==用户可能没有意识到,当自定义类型用在QMap中时,需要同时提供operator<和operator==。而Qt的文档确实强调了这一点,在QMap的运算符重载页面有明确说明。另外注意到用户提到"constParamMetaData",说明比较操作涉及const对象,所以重载版本必须带有const修饰符。这个细节很容易被忽略,特别是对C++常量正确性理解不够深入的情况下。我上次回答时给出了三种解决方案:成员函数、友元函数、qHash方案。但这次需要更强调Qt容器的特殊要求,特别是新版Qt6中对哈希容器的变动。因为Qt6废弃了QVector改用QList,可能影响某些类型的哈希计算。用户的问题描述很清晰,但缺少代码片段。如果能提供ParamMetaData的定义会更好。不过作为帮助解决问题,我可以先给出典型场景下的修正方案。重点要强调重载的常量正确性和参数传递方式(建议const引用以避免拷贝)。</think> 关于您在C++/Qt6中遇到的`QMap`的`operator==`重载错误"**no match for operator== const ParamMetaData**",这是由于Qt容器要求其元素类型必须支持相等性比较导致的。以下是完整解决方案: ### 问题原因 1. **Qt容器要求**:`QMap`在比较两个容器(`qEquals(qmap1, qmap2)`)时,会尝试比较键值对 2. **类型约束**:`ParamMetaData`作为键类型未实现合法的`operator==` 3. **错误场景**: ```cpp QMap<ParamMetaData, QString> map1, map2; if(map1 == map2) // 触发错误! ``` ### 解决方案(3选1) #### 1. 在类内重载相等运算符(推荐) ```cpp class ParamMetaData { public: // 必须包含的成员 bool operator==(const ParamMetaData& other) const { // 注意const修饰符 return this->id == other.id // 比较关键字段 && this->name == other.name; } private: int id; QString name; }; ``` #### 2. 通过友元函数实现(复杂结构适用) ```cpp class ParamMetaData { friend bool operator==(const ParamMetaData& a, const ParamMetaData& b); // ... 成员定义 }; // 全局作用域定义 bool operator==(const ParamMetaData& a, const ParamMetaData& b) { return a.id == b.id && a.typeHash == b.typeHash; // 自定义比较逻辑 } ``` #### 3. Qt特有方法(C++17前使用) ```cpp // 在ParamMetaData类定义后添加 Q_DECLARE_TYPEINFO(ParamMetaData, Q_MOVABLE_TYPE); // 声明为可移动类型 // 注册相等操作符(qHash可选) inline bool operator==(const ParamMetaData& lhs, const ParamMetaData& rhs) noexcept { return lhs.key() == rhs.key(); // 示例比较逻辑 } ``` ### 关键注意事项 1. **常量正确性**:必须添加`const`修饰符(错误中明确提示`const ParamMetaData`) ```cpp bool operator==(const ParamMetaData&) const; // ✔️ bool operator==(ParamMetaData&); // ❌ 缺少const ``` 2. **比较逻辑**:需定义所有关键字段的匹配规则 3. **Qt6特性**:从Qt 5.15开始支持通过`qEquals()`比较容器[^qt-container-comparison] ### 编译验证 在类定义后添加以下测试代码: ```cpp static_assert(std::is_equality_comparable_v<ParamMetaData>, "ParamMetaData必须支持=="); // C++17编译期检查 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangzhangkeji

谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值