Передача аргумента в слот

Я хочу переопределить mouseReleaseEvent с помощью набора QActions и QMenus...

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). Вы знаете, как я могу это сделать?


person Fatih Arslan    schedule 01.03.2011    source источник
comment
Вместо передачи параметров рассмотрите возможность анализа sender() внутри сигнала.   -  person Pavel Radzivilovsky    schedule 07.03.2013


Ответы (5)


Используйте 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))) ;
person TonyK    schedule 01.03.2011
comment
Я до сих пор помню времена, когда в Qt не было QSignalMapper, и единственным решением было установить свойство для объектов, подключенных к одному и тому же слоту, и использовать sender()->property(...) - person Kamil Klimek; 02.03.2011
comment
@Kamil Klimek Вам не нужно было; Вы могли бы написать свой собственный маппер :) - person Piotr Dobrogost; 04.03.2011
comment
Как использовать это, если мой параметр context нацелен на класс, у которого нет доступа к действиям? так что в любом случае context signalmapper не будет иметь доступа к действиям, или если бы у меня был signalmapper в том же классе, это был бы неправильный контекст для соединяющихся слотов. - person dhein; 23.06.2016
comment
Стоит отметить (2018, Qt5, C++11), что QSignalMapper устарел. Из ссылки: Этот класс устарел. Он предназначен для сохранения работоспособности старого исходного кода. Мы настоятельно не рекомендуем использовать его в новом коде. Ответ @kuba ниже теперь лучше. - person Robin Macharg; 21.06.2018

В 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 и новее.

person Kuba hasn't forgotten Monica    schedule 14.03.2014
comment
Эта комбинация лямбда-выражений C++11 и способности Qt 5 подключать функтор к сигналу — такая полезная, но недооцененная функция. - person Carlton; 15.09.2016
comment
Я адаптировал это решение к своему случаю. Однако выдает ошибку, если я использую SIGNAL(triggered(bool)) вместо &QAction::triggered. Может кто-нибудь объяснить мне, почему? - person Deniz; 01.10.2016
comment
Он не выдает ошибку. Компилятор жалуется, и в сообщении об ошибке должно быть указано, почему: нет перегрузки QObject::connect, которая принимает const char * в качестве второго аргумента и функтор в качестве третьего или четвертого аргумента. Синтаксис connect в стиле Qt4 не смешивается с новым синтаксисом. Если вы хотите использовать старый синтаксис, вы теряете простоту подключения к функторам (хотя это можно было бы приблизить, если бы у вас был компилятор C++11, но вы использовали Qt 4). - person Kuba hasn't forgotten Monica; 02.10.2016

Функция QObject::sender() возвращает указатель на объект, который передал сигнал слоту. . Вы можете использовать это, чтобы узнать, какое действие было запущено

person king_nak    schedule 01.03.2011
comment
Извините? Слот является членом подкласса QObject, поэтому он также имеет член QObject::sender(). Просто вызовите sender(), и вам будет предоставлен QObject*, указывающий на ваше действие. После этого вы можете использовать objectName() или property() полученного действия для сбора дополнительной информации. Вы также можете преобразовать его в объект действия, если хотите, но я бы не рекомендовал этого делать. - person Septagram; 01.03.2011

Возможно, вы можете создать подкласс QAction с переменной-членом m_increase.
Соедините сигнал triggered() со слотом в вашем новом подклассе QAction и выдайте новый сигнал (например, triggered(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;  
};
person Kurt Pattyn    schedule 01.03.2011

Вы можете использовать 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
}

Пример

person Andrew Pilikin    schedule 21.01.2021