Qt 5 назначает слот с параметрами для QPushButton

У меня есть приложение Qt на C++, и я хочу назначить слот QPushButton. Но я хочу передать некоторые аргументы, потому что у меня есть несколько QPushButton, выполняющих аналогичные действия, поэтому мне нужна одна функция, но с параметром в ней, но Qt продолжает говорить мне, что такого слота нет. Может кто-нибудь сказать мне, почему и как мне это сделать?

заранее спасибо

В файле .h у меня есть: (вначале он был приватным, но я изменил его в поисках проблемы)

public slots:
    void handleButton(int row, int col);

Затем в .cpp:

void fieldWindow::handleButton(int row, int col){
    cout << row << " " << col << endl;
}

И снова в том же .cpp:

connect(this->buttonsField[i][j], SIGNAL(released()), this, SLOT(handleButton(i,j)));

Это делается в двух вложенных циклах, поэтому i и j хорошо определены.

И моя ошибка:

QObject::connect: No such slot fieldWindow::handleButton(i,j) in ..\Proj1\fieldwindow.cpp:41
QObject::connect:  (receiver name: 'fieldWindow')

Я читал что-то в Интернете, что я должен сказать handleButton(int, int);, но тогда как я должен передать аргументы?


person Bankin    schedule 16.01.2014    source источник
comment
Оператор connect не принимает никаких аргументов в выражении SIGNAL(...). SIGNAL — это макрос, который инкапсулирует функцию signature в строку, которая будет передана connect.   -  person leemes    schedule 16.01.2014
comment
Так должно быть handleButton(int,int)?! Но как мне тогда передать аргументы?!   -  person Bankin    schedule 16.01.2014


Ответы (1)


К сожалению, соединение сигнал-слот Qt не принимает никаких аргументов для передачи в слот при вызове сигнала. Это работает только в том случае, если сам сигнал предоставляет эти аргументы, но вы не можете добавить их в оператор connect.

Но вы не единственный, кто хочет это сделать, поэтому в Qt есть класс, который делает почти то, что вы хотите: QSignalMapper. Экземпляр этого класса можно использовать в качестве «прокси» для соединения сигнал-слот: вы подключаете (несколько) кнопок к слоту этого класса и подключаете сигнал этого класса к вашему целевому слоту. Затем для каждого экземпляра «отправителя» (в вашем случае кнопки) вы можете указать классу, какое значение добавить в вызываемый слот. Пример:

QPushButton * button1 = ...;
QPushButton * button2 = ...;

QSignalMapper mapper;

connect(button1, SIGNAL(released()), &mapper, SLOT(map()));
mapper.setMapping(button1, 42); // Number to be passed in the slot

connect(button2, SIGNAL(released()), &mapper, SLOT(map()));
mapper.setMapping(button2, 1337); // Number to be passed in the slot

connect(&mapper, SIGNAL(mapped(int)), this, SLOT(handleButton(int)));

К сожалению, как видите, этот класс может обрабатывать только один параметр. В вашем случае вам следует выбрать другой метод (я объяснил выше на случай, если вы снова столкнетесь с похожей проблемой, но с одним параметром int).

Альтернативой, которая подходит для вашей проблемы, является использование sender() в слоте. Помните свое сопоставление в структуре данных, например

QMap<QObject*,int> rows;
QMap<QObject*,int> cols;

и получить доступ к тем в вашем слоте, которые не принимают никаких аргументов:

void fieldWindow::handleButton(){
    int row = rows[sender()];
    int col = cols[sender()];
    cout << row << " " << col << endl;
}

Конечно, при инициализации вашего пользовательского интерфейса вам необходимо указать соответствующие значения в этих картах. Или вы можете найти свою кнопку в существующем массиве buttonsField.

Еще один метод существует со времен Qt5 и C++11: вместо слота вы можете обрабатывать сигналы в лямбда-функции. Это будет выглядеть так (сигнал назван с использованием нового синтаксиса):

connect(this->buttonsField[i][j], &QPushButton::released, [=]{
    handleButton(i, j);
});

Если вам не нравится синтаксис лямбда, вы также можете использовать некоторые помощники из стандартной библиотеки для составления функтора вместо лямбда, или вы можете написать свой собственный класс функтора, но лично я нахожу лямбду очень читабельной.

person leemes    schedule 16.01.2014
comment
Большое тебе спасибо ! Я могу сократить до одного с помощью простой формулы i*count_on_row + j, поэтому я попробую первый способ, и я надеюсь, что он сработает! Большое спасибо за подробный ответ :) - person Bankin; 16.01.2014
comment
Я рад, что смог помочь. Я добавил третий метод, который хорош, если у вас есть Qt5. Обратите внимание, что если вам нужны только эти значения, чтобы получить доступ к вашему массиву кнопок для получения указателя кнопки, вы также можете просто использовать sender(), и все готово. - person leemes; 16.01.2014
comment
О, они добавили лямбду! Большой! Это сработало отлично! Большое спасибо! :) - person Bankin; 16.01.2014