0

I want to get a QTreeView widget to emit a clicked(const QModelIndex&) signal whenever a pushbutton is clicked. This is so that I can get a list of all the items that are selected within the QTreeView at the time of clicking the pushbutton. Now I thought I could connect two signals with distinct arguments (Qt Connect signals with different arguments), however when I try to call

connect(ui.pbAddVideo, SIGNAL(clicked()), ui.treeView_video, SIGNAL(clicked(const QModelIndex&)));

I get the error message:

QObject::connect: Incompatible sender/receiver arguments QPushButton::clicked() --> QTreeView::clicked(QModelIndex)

Have I misunderstood the whole signal forwarding concept?

As always, many thanks.

Community
  • 1
  • 1
Mr Squid
  • 1,196
  • 16
  • 34
  • The post you are linking is about _fewer_ arguments. What you are trying to accomplish is with _more_ arguments. – JefGli May 20 '16 at 06:29
  • I don't think it's possible in the way you expected. Why do you need a signal from the tree view, if you can get all the information from the slot connected to the button's click signal? I think you just make things much complex. – vahancho May 20 '16 at 06:50
  • @Jeffrey van de Glind So why does one case work and the other not? – Mr Squid May 20 '16 at 06:53
  • @vahancho because I want to load the video files that were selected by the user in the treeView once the pushbutton "load video" is clicked. However I can only access that data via a QModelIndex provided by the treeView. To be honest, I am also confused by the whole situation, but that is why I am here. – Mr Squid May 20 '16 at 06:54
  • @MrSquid Because then Qt needs to guess what value it should pass. And guessing can lead to undefined behaviour. – JefGli May 20 '16 at 07:10
  • @MrSquid, I think you don't need to do all these signals tricks. Below is my proposal on how to solve your problem. – vahancho May 20 '16 at 07:29

5 Answers5

3

Firtsly, what index you must send by clicking a button from your tree? Secondly, since c++11 standart you can do something like that:

connect(ui.pbAddVideo, &QPushButton::clicked, [=] { emit ui.treeView_video->clicked(ui.treeView_video->currentIndex()); });
Shtol Krakov
  • 1,260
  • 9
  • 20
  • This does solve my problem, but it seems like a workaround. I am still curious as to why forwarding the signal directly did not work. I see that the signals have different arguments, but if I just want one signal to emit when the other does I don't see why it should be a problem. – Mr Squid May 20 '16 at 06:51
  • Sender can filled by any arguments, but reciever can be or empty, or with same arguments (not in same count but in same sequence) that sender sends. So you can do this: `connect(this, SIGNAL(someSignal(int,int,QString)), SIGNAL(secondSignal(int,int)));`, but this `connect(this, SIGNAL(someSignal()), SIGNAL(secondSignal(int,int)));` will not work correctly cause you don't know what int is in reciever? So, one of solution - inherit from `QTreeView` and create signal, what you need. – Shtol Krakov May 20 '16 at 07:00
1

I would solve your problem with the following approach:

First you have to handle the button click:

connect(ui.pbAddVideo, SIGNAL(clicked()), this, SLOT(onLoadVideo()));

In the slot you need to get the list of selected items from the tree view and do something with them:

void MyClass::onLoadVideo()
{
    QItemSelectionModel *selectionModel = ui.treeView_video->selectionModel();
    QModelIndexList selectedVideos = selectionModel->selectedIndexes();
    foreach (QModelIndex *video, selectedVideos) {
        // Play the video.
    }

}
vahancho
  • 20,808
  • 3
  • 47
  • 55
0

You are connecting one SIGNAL() to another SIGNAL() which is perfectly ok but their parameters should match. In your case the second signal has a parameter(i.e QModelIndex) that the first signal does not have.

Yousuf Azad
  • 414
  • 1
  • 7
  • 17
0

Have I misunderstood the whole signal forwarding concept?

Yes.

When a signal is emitted, Qt takes the signal's arguments and passes them to the connected slot/signal.

Valid signal-slot connection

For example, suppose you connect the QSlider::valueChanged(int) signal to the QSpinBox::setValue(int) slot. When the valueChanged() signal is emitted, this is effectively how the slot gets called:

// "Emitting a signal" == "Calling the signal function"
QSlider::valueChanged(int sliderSignalValue)
{
    QSpinBox *receiver = findReceiver();
    receiver->setValue(sliderSignalValue);
}

Valid signal-signal connections

Similarly, if you connect the QSlider::valueChanged(int) signal to the QSpinBox::valueChanged(int) signal, the code behaves like this:

QSlider::valueChanged(int sliderSignalValue)
{
    QSpinBox *receiver = findReceiver();
    emit receiver->valueChanged(sliderSignalValue);
}

Now, if you want to connect in the opposite direction (connect(ui.treeView_video, SIGNAL(clicked(const QModelIndex&)), ui.pbAddVideo, SIGNAL(clicked()));, it's perfectly fine:

QTreeView::clicked(const QModelIndex& viewSignalValue)
{
    QPushButton *receiver = findReceiver();
    emit receiver->clicked(); // No problem. The viewSignalValue is simply ignored.
}

Invalid signal-slot connection

However, for the connection that you wanted to make, the code will need to behave like this:

QPushButton::clicked()
{
    QTreeView *receiver = findReceiver();
    emit receiver->clicked(/*???*/); // ERROR: You need to pass a QModelIndex value!
} 

You've got a parameter mismatch. QTreeView::clicked() requires a QModelIndex value, but QPushButton::clicked() cannot provide this. Therefore, you cannot connect these two together.

Does this make sense?

JKSH
  • 2,658
  • 15
  • 33
  • Thanks, it is all a lot clearer to me now. I'm sure this explanation will come in useful to others as well. – Mr Squid May 20 '16 at 23:28
0

Many thanks to @vahancho whose answer I have adopted. There is no point in using the "clicked()" signal from the qTreeView since I do not need to wait for this to access the data inside. Hence:

connect(ui.pbAddVideo, SIGNAL(clicked()), this, SLOT(addVideo()));

    void VigilWidget::addVideo() {

    QItemSelectionModel *selectionModel = ui.treeView_video->selectionModel();
    QModelIndexList selectedVideos = selectionModel->selectedIndexes();
    foreach (QModelIndex video, selectedVideos) {
        qDebug().nospace() << video.data(0);
    }

}

As to my question about how signal to signal connections work, thanks to everyone for taking the time to explain this :)

Mr Squid
  • 1,196
  • 16
  • 34