How to pass variables to slot methods in QT?
Asked Answered
M

6

11

I'm making a little chat messenger program, which needs a list of chat channels the user has joined. To represent this list graphically, I have made a list of QPushButtons, which all represent a different channel. These buttons are made with the following method, and that's where my problem kicks in:

void Messenger::addToActivePanels(std::string& channel)
{
    activePanelsContents = this->findChild<QWidget *>(QString("activePanelsContents"));
    pushButton = new QPushButton(activePanelsContents);
    pushButton->setObjectName("pushButton");
    pushButton->setGeometry(QRect(0, 0, 60, 60));
    pushButton->setText("");
    pushButton->setToolTip(QString(channel.c_str()));
    pushButton->setCheckable(true);
    pushButton->setChecked(false);
    connect(pushButton, SIGNAL(clicked()), this, SLOT(switchTab(channel)));
}

(activePanelContents is a QWidget that holds the list.)

The point is that each button should call the switchTab(string& tabname) method when clicked, including the specific channel's name as variable. This implementation doesn't work though, and I haven't been able to find out how to properly do this.

Manilla answered 7/2, 2011 at 23:20 Comment(0)
C
8

For strings and integers, you can use QSignalMapper. In your Messenger class, you would add a QSignalMapper mapper object, and your function would look like:

void Messenger::addToActivePanels(std::string& channel)
{
    activePanelsContents = this->findChild<QWidget *>(QString("activePanelsContents"));
    pushButton = new QPushButton(activePanelsContents);
    // ...
    connect(pushButton, SIGNAL(clicked()), &mapper, SLOT(map()));
    mapper.setMapping(pushButton, QString(channel.c_str()));
}

and after you have added all channels to your active panels, you call

connect(&mapper, SIGNAL(mapped(const QString &)), this, SLOT(switchTab(const QString &)));
Christen answered 8/2, 2011 at 3:11 Comment(2)
This doesn't seem to work... switchTab() simply never gets called, although no errors are given anywhere at all.Manilla
Does switchTab() take a const QString &? If it doesn't, you need to change it so it does. Qt doesn't allow you to pass std::string (or, in general, any type not registered with qRegisterMetaType) through signals and slots. Typos inside SIGNAL and SLOT are not detected until runtime, because those macros turn their arguments into strings. Chances are Qt is printing an error message to the console when it tries to make the connection to switchTab(const QString &).Christen
U
3

Use QSignalMapper to pass variables;

        QSignalMapper* signalMapper = new QSignalMapper (this) ;
        QPushButton *button = new QPushButton();


         signalMapper -> setMapping (button, <data>) ;
         connect (signalMapper, SIGNAL(mapped(QString)), this,   
                   SLOT(buttonClicked(QString))) ;

in slot i.e

void class::buttonClicked(QString data){

    //use data
    // to get sender 
    QSignalMapper *temp = (QSignalMapper *)this->sender();
    QPushButton *btn = (QPushButton *)temp->mapping(data);
    // use btn

}

Hope my ans may help you

Ugrian answered 16/10, 2012 at 11:21 Comment(1)
Thanks for this answer. I was using QSignalMapper with QTNetworkRequest and didn't know i had to use Mapper->mapping(data) to obtain the object in such a case. I was simply using qobject_cast<QObject*>(sender) which only works when you have no parameter.Kudos
C
1

Don't use the sender method unless you absolutely have to. It ties the function directly to being used only as a slot (can't be called directly). Retain the behavior of having the function accept a string and simply make a mechanism by which you can call it.

One method, among others you might find, is to leverage use of QSignalMapper. It will map objects to values and regenerate signals of the appropriate signature.

Corelative answered 8/2, 2011 at 0:39 Comment(0)
F
1

I would do it with "relay" objects:

Create TabSwitchRelay which is a sub-class of QObject with this constructor:

TabSwitchRelay::TabSwitchRelay(QObject *parent, Messanger * m, const QString & c)
: QObject(parent), m_messanger(m), m_channel(c)
{
}

It also has a slot clicked():

void TabSwitchRelay::clicked()
{
    m_messager->switchTab(m_channel);
}

Now replace the line in your code that does connect with this:

TabSwitchRelay * tabRelay = new TabSwitchRelay(pushButton, this, channel);
connect(pushButton, SIGNAL(clicked()), tabRelay, SLOT(clicked()));

It's not tested but you get teh basic idea.

Flawed answered 8/2, 2011 at 2:18 Comment(0)
B
0

You could try having your switchTab slot take no argument and use QObject::sender to get the object that sent the signal.

Messenger::switchTab()
{
  QObject* sender = this->sender();
  QPushButton* button = qobject_cast<QPushButton*>(sender);
  if(button)
  {
    // Do stuff...
  }
}
Bowerbird answered 7/2, 2011 at 23:42 Comment(2)
Be aware of the warnings before using the QObject::sender in your codeFloristic
Not sure why your post was minused, but thanks anyway. You helped a lotSlickenside
M
0

if you're using Qt5, you can do it through lambda:

connect( sender, &Sender::valueChanged,  [=](){ myMethod(5); } );

void myMethod(int value)
{
  // do stuff
}
Matthew answered 24/10, 2017 at 12:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.