Ein Argument an einen Slot übergeben

77

Ich möchte mouseReleaseEvent mit einer Reihe von QActions und QMenus überschreiben ...

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()));

Ich möchte dem Slot ein Argument übergeben onStepIncreased(wie Sie sich vorstellen können, sind es 1,5,10,25,50). Weißt du, wie ich das machen kann?

Fatih Arslan
quelle
2
Anstatt Parameter zu übergeben, sollten Sie sender () innerhalb des Signals analysieren.
Pavel Radzivilovsky

Antworten:

120

Verwenden Sie QSignalMapper . So was:

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))) ;
TonyK
quelle
Ich erinnere mich noch an Zeiten, als Qt keinen QSignalMapper hatte und die einzige Lösung darin bestand, Eigenschaften für Objekte festzulegen, die mit demselben Steckplatz verbunden waren, und sender () -> property (...)
Kamil Klimek am
@Kamil Klimek Du musstest nicht; Du hättest deinen eigenen Mapper schreiben können :)
Piotr Dobrogost
Wie verwende ich das, wenn mein contextParameter a auf eine Klasse abzielt, die keinen Zugriff auf die Aktionen hat? In beiden Fällen hätte der contextSignalmapper keinen Zugriff auf die Aktionen, oder wenn ich den Signalmapper in derselben Klasse hätte, wäre dies der falsche Kontext für die Verbindungssteckplätze.
Dhein
Bemerkenswert (2018, Qt5, C ++ 11), dass QSignalMapper veraltet ist. Über den Link: "Diese Klasse ist veraltet. Sie wird bereitgestellt, damit der alte Quellcode funktioniert. Wir raten dringend davon ab, ihn in neuem Code zu verwenden." Die Antwort von @kuba unten ist jetzt eine bessere.
Robin Macharg
120

Mit Qt 5 und einem C ++ 11-Compiler besteht die idiomatische Möglichkeit, solche Dinge zu tun, darin, einem Funktor Folgendes zu geben 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); });

Das dritte Argument connectist nominell optional. Es wird verwendet, um den Thread-Kontext einzurichten, in dem der Funktor ausgeführt wird. Es ist immer notwendig, wenn der Funktor eine QObjectInstanz verwendet. Wenn der Funktor mehrere QObjectInstanzen verwendet, sollte er ein gemeinsames übergeordnetes Element haben, das seine Lebensdauer verwaltet, und der Funktor sollte sich auf dieses übergeordnete Element beziehen, oder es sollte sichergestellt werden, dass die Objekte den Funktor überleben.

Unter Windows funktioniert dies in MSVC2012 und höher.

Unslander Monica
quelle
7
Diese Kombination aus C ++ 11-Lambdas und der Fähigkeit von Qt 5, einen Funktor mit einem Signal zu verbinden, ist eine nützliche und dennoch unterschätzte Funktion.
Carlton
Ich habe diese Lösung an meinen Fall angepasst. Es wird jedoch ein Fehler ausgegeben, wenn ich SIGNAL(triggered(bool))anstelle von verwende &QAction::triggered. Kann mir bitte jemand erklären warum?
Deniz
Es "wirft" keinen Fehler. Der Compiler beschwert sich und die Fehlermeldung sollte Ihnen sagen, warum: Es gibt keine QObject::connectÜberladung, die ein const char *als zweites Argument und einen Funktor als drittes oder viertes Argument verwendet. Die Qt4- connectSyntax passt nicht zur neuen Syntax. Wenn Sie die alte Syntax verwenden möchten, verlieren Sie die einfache Verbindung zu Funktoren (obwohl dies angenähert werden könnte, wenn Sie einen C ++ 11-Compiler hätten, aber Qt 4 verwenden).
Unslander Monica
12

Die QObject::sender()Funktion gibt einen Zeiger auf das Objekt zurück, das dem Slot signalisiert hat. Sie können dies verwenden, um herauszufinden, welche Aktion ausgelöst wurde

king_nak
quelle
2
Ich bitte um Verzeihung? Der Slot ist Mitglied einer Unterklasse von QObject, hat also auch ein QObject :: sender () -Mitglied. Rufen Sie einfach sender () auf, und Sie erhalten ein QObject *, das auf Ihre Aktion verweist. Danach können Sie objectName () oder property () einer erfassten Aktion verwenden, um weitere Informationen zu sammeln. Sie können es auch in ein Aktionsobjekt konvertieren, wenn Sie dies wirklich möchten, aber das würde ich nicht empfehlen.
Septagramm
1

Möglicherweise können Sie QAction mit einer Mitgliedsvariablen m_increase unterordnen.
Verbinden Sie das Triggered () - Signal mit einem Steckplatz in Ihrer neuen QAction-Unterklasse und senden Sie ein neues Signal (z. B. Triggered (Int-Nummer)) mit dem richtigen Parameter aus.
z.B

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;  
};
Kurt Pattyn
quelle
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)));
} 
Jaziri Rami
quelle