将参数传递到插槽


77

我想用一堆QActions和QMenus覆盖mouseReleaseEvent ...

connect(action1, SIGNAL(triggered()), this, SLOT(onStepIncreased()));

connect(action5, SIGNAL(triggered()), this, SLOT(onStepIncreased()));

connect(action10, SIGNAL(triggered()), this, SLOT(onStepIncreased()));

connect(action25, SIGNAL(triggered()), this, SLOT(onStepIncreased()));

connect(action50, SIGNAL(triggered()), this, SLOT(onStepIncreased()));

因此,我想将参数传递给广告位onStepIncreased(您可以想象它们是1,5,10,25,50)。你知道我该怎么做吗?


2
与其传递参数,不如分析信号内部的sender()。
Pavel Radzivilovsky 2013年

Answers:


120

使用QSignalMapper。像这样:

QSignalMapper* signalMapper = new QSignalMapper (this) ;
connect (action1, SIGNAL(triggered()), signalMapper, SLOT(map())) ;
connect (action5, SIGNAL(triggered()), signalMapper, SLOT(map())) ;
connect (action10, SIGNAL(triggered()), signalMapper, SLOT(map())) ;
connect (action25, SIGNAL(triggered()), signalMapper, SLOT(map())) ;
connect (action50, SIGNAL(triggered()), signalMapper, SLOT(map())) ;

signalMapper -> setMapping (action1, 1) ;
signalMapper -> setMapping (action5, 5) ;
signalMapper -> setMapping (action10, 10) ;
signalMapper -> setMapping (action25, 25) ;
signalMapper -> setMapping (action50, 50) ;

connect (signalMapper, SIGNAL(mapped(int)), this, SLOT(onStepIncreased(int))) ;

我仍然记得时代,当Qt没有QSignalMapper时,唯一的解决方案是在连接到同一插槽的对象上设置属性并使用sender()-> property(...)
Kamil Klimek

@Kamil Klimek您不必这样做;您可能已经编写了自己的映射器:)
Piotr Dobrogost 2011年

如果我的context参数将a定位到没有任何动作的类,该如何使用呢?因此,无论如何,signalmappercontext将无法访问操作,或者如果我将Signalmapper置于同一类中,则对于连接插槽而言,这将是错误的上下文。
dhein

值得注意的是(2018,Qt5,C ++ 11)QSignalMapper已被弃用。通过链接:“该类已过时。提供该类是为了使旧的源代码正常工作。我们强烈建议不要在新代码中使用它。” 下面的@kuba答案现在是一个更好的答案。
罗宾·马查格

120

使用Qt 5和C ++ 11编译器时,惯用的方法是将仿函数赋予connect

connect(action1,  &QAction::triggered, this, [this]{ onStepIncreased(1); });
connect(action5,  &QAction::triggered, this, [this]{ onStepIncreased(5); });
connect(action10, &QAction::triggered, this, [this]{ onStepIncreased(10); });
connect(action25, &QAction::triggered, this, [this]{ onStepIncreased(25); });
connect(action50, &QAction::triggered, this, [this]{ onStepIncreased(50); });

第三个参数connect名义上是可选的。它用于设置函子将在其中执行的线程上下文。函子使用QObject实例时,总是有必要的。如果仿函数使用多个QObject实例,则它们应具有一些共同的父级来管理其生命周期,并且仿函数应引用该父级,或者应确保对象将超过仿函数。

在Windows上,此功能可在MSVC2012及更高版本中使用。


7
C ++ 11 lambda和Qt 5将函子连接到信号的能力的这种结合是一种有用但被低估的功能。
卡尔顿

我针对我的情况调整了此解决方案。但是,如果我使用SIGNAL(triggered(bool))而不是,则会引发错误&QAction::triggered。有人可以向我解释为什么吗?
Deniz

它不会“抛出”错误。编译器会抱怨,错误消息应该告诉您原因:没有QObject::connect重载,将aconst char *作为第二个参数,将函子作为第三个或第四个参数。Qt4样式的connect语法不会与新语法混合使用。如果您希望使用旧的语法,则会丧失连接​​到函子的便利(即使如果您使用的是C ++ 11编译器但使用了Qt 4,则可以近似)。
Unslander Monica's October

12

QObject::sender()函数返回指向已发出信号的对象的指针。您可以使用它来找出触发了哪个动作


2
请再说一遍?该插槽是QObject子类的成员,因此它也具有QObject :: sender()成员。只需调用sender(),您将获得一个指向您的操作的QObject *。之后,您可以使用获取的操作的objectName()或property()来收集更多信息。如果确实需要,也可以将其转换为动作对象,但是我不建议这样做。
Septagram'3

1

也许您可以使用m_increase成员变量来继承QAction。
将trigger()信号连接到新的QAction子类上的插槽,并发出带有正确参数的新信号(例如,trigger(int number))。
例如

class MyAction:public QAction  
{  
public:  
    MyAction(int increase, ...)  
        :QAction(...), m_increase(increase)
    {  
        connect(this, SIGNAL(triggered()), this, SLOT(onTriggered()));  
    }  
protected Q_SLOTS:  
    void onTriggered()  
    {  
        emit triggered(m_increase);  
    }  

Q_SIGNALS:
    void triggered(int increase);   

private:  
    int m_increase;  
};

0
QVector<QAction*> W(100);
 W[1]= action1;
 W[5]= action5;
 W[10]= action10;
 W[25]= action25;
 W[50]= action50;

for (int i=0; i<100; ++i)
{
  QSignalMapper* signalmapper = new QSignalMapper();
  connect (W[i], SIGNAL(triggered()), signalmapper, SLOT(map())) ;
  signalmapper ->setMapping (W[i], i);
  connect (signalmapper , SIGNAL(mapped(int)), this, SLOT(onStepIncreased(int)));
} 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.