将参数传递给插槽

时间:2011-03-01 10:20:41

标签: qt qsignalmapper qt-slot

我想用一堆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)。你知道我怎么做吗?

6 个答案:

答案 0 :(得分:111)

使用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))) ;

答案 1 :(得分:103)

使用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&新。

答案 2 :(得分:11)

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

答案 3 :(得分:1)

也许您可以使用m_increase成员变量对QAction进行子类化 将triggered()信号连接到新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;  
};

答案 4 :(得分: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)));
} 

答案 5 :(得分:0)

您可以使用 std::bind 这是一个功能对象适配器,它允许功能对象适应给定数量的参数。

例如,您创建自己的聊天服务器。它包含两个类:ChatServer 和 ServerWorker。

ChatServer 是 QTcpServer 类,ServerWorker 是 QTcpSocket(在服务器端管理套接字)。

ServerWorker 标头中的信号:

void error();

在您的 ChatServer 标头中,您定义这些私人插槽:

void userError(ServerWorker *sender);

在 cpp 文件中创建这些对象,并在套接字连接后运行的 incomingConnection 方法中,使用 std::bind 连接插槽和信号:

void ChatServer::incomingConnection(qintptr socketDescriptor)
{
    //some code
    connect(worker, &ServerWorker::error, this, std::bind(&ChatServer::userError, this, worker));
}

std::bind 创建一个带有一些固定参数的函子。例如 connect(worker, &ServerWorker::error, this, std::bind(&ChatServer::userError, this, worker)); 将导致 this->userError(worker);每次工作人员发出错误信号时都会调用。

userErrorslot 每次连接到客户端的套接字遇到错误时都会执行。它有签名:

void ChatServer::userError(ServerWorker *sender)
{
    //some code
}

Example