问题描述
class ImportEntityCommand : public QUndoCommand
{
// ...
private:
QString m_importedEntityName;
Importer *m_importer;
// ...
}
redo
方法启动 QProcess:
void ImportEntityCommand::redo()
{
if (/* Import is already done before */) {
// ...
} else {
// Import finish is handled by a slot
m_importer->import(m_url);
}
}
信号槽连接由命令构造函数组成:
ImportEntityCommand::ImportEntityCommand(EditorSceneItemmodel *sceneModel,const QUrl &url) :,m_importer(new Importer(/* ... */))
{
// Importer would start a QProcess which runs asynchronously and emits a signal
// that's why I have to handle the signal by a slot
QObject::connect(m_importer,&Importer::importFinished,this,&ImportEntityCommand::handleImportFinish
);
}
进程发出的信号是这样处理的:
void ImportEntityCommand::handleImportFinish(const QString name)
{
m_importedEntityName = name;
}
但是我在编译时收到这样的错误:
C:\Qt\qt5.12.9\5.12.9\msvc2017_64\include\QtCore\qobject.h:250: error: C2664: 'QMetaObject::Connection QObject::connectImpl(const QObject *,void **,const QObject *,QtPrivate::QSlotObjectBase *,Qt::ConnectionType,const int *,const QMetaObject *)':无法将参数 3 从 'const ImportEntityCommand *' 转换为 'const QObject *'
错误点在于:
无法将参数 3 从“const ImportEntityCommand *”转换为“const QObject *”
我的 ImportEntityCommand
类继承自 QUndoCommand
,我猜它又继承自 QObject
。
问题
因此,出于某种原因,Qt 不允许我处理继承自 QUndoCommand
的命令内的信号。
解决方法
我从 QUndoCommand 继承了我的 ImportEntityCommand 类,其中 我猜是从 QObject 继承的。
QUndoCommand 不继承自 QObject 参见:
https://doc.qt.io/qt-5/qundocommand.html
例如与 QWidget 相比,它确实继承自 QObject。
https://doc.qt.io/qt-5/qwidget.html
如果你想让你的导入器处理信号和槽,你可以从 QObject 继承:
getResult({ getValue("Hello") })
并且您可以连接到 lambda,例如:
class importer: public QObject
{
Q_OBJECT
public:
...
private:
...
}
,
难道你不能只使用组合在ImportEntityCommand 中放置一个QObject 派生类实例吗?然后,您可以将信号连接到 QObject 派生类,然后该派生类将调用 ImportEntityCommand 来完成工作。
class SignalReceiver : public QObject
{
Q_OBJECT
public:
SignalReciever(ImportEntityCommand *iec) : QObject(),_iec(iec)
{}
public slot:
void handleImportFinished(QString url)
{
if (this->_iec) this->_iec->handleImportFinished(url);
}
private:
ImportEntityCommand *_iec{nullptr};
};
然后在您的 ImportEntityCommand 中,您将创建一个 SignalReceiver 并将其连接到信号:
class ImportEntityCommand : public QUndoCommand
{
// ...same as before,then
private:
QScopedPointer<SignalReceiver,QScopedPointerDeleteLater> _signalReceiver;
};
// in the ImportEntityCommand constructor
this->_signalReceiver.reset(new SignalReceiver(this));
QObject::connect(this->importer,&Importer::importFinished,this->_signalReciver.data(),&SignalReceiver::handleImportFinished);
我们无法避免将 ImportEntityCommand
的原始指针传递给 SignalReceiver
,因为 ImportEntityCommand
必须位于撤消堆栈中。另一方面,对接收器使用 QScopedPointer
可确保在撤消堆栈删除 ImportEntityCommand
实例时正确清理它。只需记住在包装 QScopedPointerDeleteLater
派生时总是指定 QObject
- 尤其是捕捉信号的派生。