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


80

Я хочу перевизначити 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). Ви знаєте, як я можу це зробити?


3
Замість передачі параметрів розгляньте аналіз sender () усередині сигналу.
Павло Радзивіловський

Відповіді:


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 () -> властивість (...)
Каміль Клімек,

@Kamil Klimek Вам не потрібно було; ти міг написати власного картографа :)
Пьотр Доброгост,

Як використовувати це, якщо мій contextпараметр націлений на клас, який не має доступу до дій? так чи інакше, signalmapper contextне мав би доступу до дій, або якщо б я мав signalmapper до того самого класу, це був би неправильний контекст для з'єднуючих слотів.
dhein

Варто зазначити (2018, Qt5, C ++ 11), що QSignalMapper застарілий. З посилання: "Цей клас застарілий. Він надається для збереження старого вихідного коду. Ми настійно не рекомендуємо використовувати його в новому коді." Відповідь @kuba нижче - тепер краща.
Робін Мачарг,

122

За допомогою 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 та новіших версіях.


8
Ця комбінація лямбда С ++ 11 і здатності Qt 5 підключати функтор до сигналу є такою корисною, але при цьому недооціненою функцією.
Carlton

Я адаптував це рішення до свого випадку. Однак він видає помилку, якщо я використовую SIGNAL(triggered(bool))замість &QAction::triggered. Хтось може пояснити мені, чому?
Деніз

Це не "викидає" помилку. Компілятор скаржиться, і повідомлення про помилку повинно сказати вам, чому: немає QObject::connectперевантаження, яке приймає a const char *як другий аргумент, а функтор як третій або четвертий аргумент. connectСинтаксис у стилі Qt4 не поєднується з новим синтаксисом. Якщо ви хочете використовувати старий синтаксис, ви позбавляєтеся простоти підключення до функторів (хоча це може бути наближено, якщо у вас був компілятор C ++ 11, але ви використовували Qt 4).
Куба не забув Моніку

12

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


2
Вибачте? Слот є членом підкласу QObject, отже, він також має член QObject :: sender (). Просто зателефонуйте sender (), і ви отримаєте QObject *, що вказує на вашу дію. Після цього ви можете використовувати objectName () або property () придбаної дії для збору додаткової інформації. Ви також можете перетворити його на об'єкт дії, якщо дуже хочете, але я б не рекомендував цього.
Септаграм

1

Можливо, ви можете підклас QAction за допомогою змінної члена m_increase.
Підключіть спрацьований () сигнал до слота у вашому новому підкласі QAction і випустіть новий сигнал (наприклад, спрацьовує (int номер)) з правильним параметром.
напр

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)));
} 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.