【问题标题】:Passing different classes in connect() in Qt在 Qt 的 connect() 中传递不同的类
【发布时间】:2015-09-09 12:39:18
【问题描述】:

我正在开发一个图像编辑软件,其中包括一些课程。但我需要我的代码更通用。但是在连接方面,我的课程有一个大问题。

QObject::connect(actionSmartContrast, SIGNAL(triggered(bool)), effectsWindow, SLOT(addSmartContrast()));
QObject::connect(actionSaturation, SIGNAL(triggered(bool)), effectsWindow, SLOT(addSaturation()));

我有一个名为“效果”的菜单,当用户单击QActionactionSmartContrast 时,效果智能对比度将添加到我的效果窗口中。问题是,鉴于每个效果都有自己的类,我必须为每个类创建一个函数,如您在上面的代码中所见。这是非常重复的。我想通过这样做来避免这个问题:

QObject::connect(actionSmartContrast, SIGNAL(triggered(bool)), effectsWindow, SLOT(addEffect(new SmartContrast())));
QObject::connect(actionSaturation, SIGNAL(triggered(bool)), effectsWindow, SLOT(addEffect(new Saturation())));

函数addEffect() 一切正常,因为它需要一个指向 Effect 对象的指针,并且 SmartContrast 和 Saturation 都继承自 Effect。唯一的问题是不可能像这样在connect() 中传递变量。所以我想到了子类化QAction 并创建一个信号,它每次都会返回我喜欢的类,但又一次,如何告诉我的新 Action 类它应该返回什么类?如果我有一千个效果,我不会将QAction 子类化一千次!我需要创建一个函数,例如一个指向SmartContrast 对象的指针,它会猜测每次单击Action 时它都必须返回一个SmartContrast 指针。由于继承自 Effect 类,这仍然是可能的。但我真的不知道该怎么做。任何帮助将非常感激。提前致谢!

【问题讨论】:

  • 您可以在插槽中使用 sender() 来获取操作。然后你可以在比较指针时创建相应的效果。或者,如果您可以使用 lambda,您可以在自定义操作类中存储 std::function,例如 smartEffectAction = new myAction([] () { return new SmartEffect(); });然后在槽中调用这个函数来获取正确的对象。
  • 你的效果是否有一个通用的基类和虚方法,这样访问基类指针就足够了?

标签: c++ qt class inheritance slot


【解决方案1】:

看起来QSignalMapper 正是您要找的。​​p>

更新:

另一种方法是使用 lambda(如果 Qt 版本和 c++ 编译器允许):

QObject::connect(actionSmartContrast, &QAction::triggered, [effectsWindow](){ effectsWindow->addEffect(new SmartContrast()) });

【讨论】:

  • @RobinDosAnjos 你为什么这么认为?
【解决方案2】:

有多种选择。


如果有效果的基类指针就足够了,因为你使用了例如虚拟方法以下解决方案应该这样做:

你可以创建一个中间类:

class Intermediate : public QObject 
{
    Q_OBJECT
public:
    Intermediate(QObject* parent = 0) : QObject(parent){}
signals:
    void triggerEffect(Effect*);
public slots:
    void effectTriggered()
    {
        QAction* action = qobject_cast<QAction*>(QObject::sender());
        if ( action ) {
            std::map<QAction*,Effect*>::iterator it = m_mapping.find(action);
            if ( it != m_mapping.end() )
            { emit triggerEffect( it->second ); }
        }
    }
public:
    void registerActionEffectPair(QAction* action,Effect* effect)
    { m_mapping[action]=effect; }
private:
    std::map<QAction*,Effect*> m_mapping;
};

要将您的 Effect 基类用作信号和插槽的类型,您必须将其注册为元类型:

qRegisterMetaType<Effect*>();

连接它:

QObject::connect(intermediateInstancePtr, SIGNAL(triggerEffect(Effect*),
                 effectsWindow, SLOT(addEffect(Effect*)));

每个动作的联系如下:

intermediateInstancePtr->registerActionEffectPair( yourEffectAction, theEffectPtr );
QObject::connect(yourEffectAction, SIGNAL(triggered(bool)), 
                 intermediateInstancePtr, SLOT(effectTriggered()));

另一种可能是使用 QObjects 属性:

setProperty( "property", "value" )

为每个效果调用 QAction 并读取插槽“addEffect”中的属性。 该属性可以通过调用来读取

QAction* action = qobject_cast<QAction*>(QObject::sender());
if ( action ){ 
    QVariant val = action->property("property"); 
    if ( val.isValid() )
    { 
        //TODO
    }
}

因为 Object::sender 返回负责 slot 调用的发送者。

之后你可以做一个开关盒或类似的东西来区分不同的效果。

【讨论】:

  • 感谢您的快速回答!问题是我不需要事后能够区分效果。一旦将它们提供给 addEffect(),它们就只是效果!我正在寻找的是一种无需执行 if/switch 块即可从不同类创建效果的方法。我以为我可以使用指针做类似的事情..
  • 我添加了另一个选项。
【解决方案3】:

我终于解决了我的问题!我对 QAction 进行了子类化,并向我的新类添加了一个信号,该信号根据属性 text() 从我想要的类中创建新效果。如果块足够简单。谢谢大家的回答!

【讨论】:

    猜你喜欢
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    相关资源
    最近更新 更多