How determine from which child a mousePressEvent came



  • Hello,
    I have a QBboxLayout in which I place a variable number of child widgets. After adding them, the user can either left- or right-click individuals in order to process the specific child that they pressed. When a child is added, its widget is created and I keep information about it in a list which reflects what is in the QVBoxLayout at any given time.

    My first attempt at determining which child is clicked was to make an explicit connect when the child is made, passing an additional parameter to a slot handling the the mousePressEvent in addition to the event itself. But this caused a different signature for the slot and I could not get it to be recognized, resulting in "no such signal" errors at run time.

    My next thought, attempted in the code below, is to try to tell which child caused the event within the handler itself. Here is an extract of the code which creates children in the first place, the handler, and finally classes for the class with the list as well as a class with the information the user desires to interact with for each child:

    void seriesSurvey::on_addSeriesButton_clicked()
    {
    imageSeries newSeries;

    for (int i = 0; i < 1; ++i) { // here there is one series at a time, however, code will also be used as template for reading in as many series' as are initiailized in the workItemListEntry
    QVBoxLayout *seriesWidget;
    QWidget *seriesThumb;

    QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        sizePolicy.setHorizontalStretch(0);
        sizePolicy.setVerticalStretch(0);
        sizePolicy.setHeightForWidth(ui->workingView->sizePolicy().hasHeightForWidth());
        QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Expanding);
    
    seriesWidget = new QVBoxLayout();
    seriesWidget->setObjectName(QStringLiteral("seriesWidget"));
    seriesWidget->setSizeConstraint(QLayout::SetFixedSize);
    seriesWidget->setContentsMargins(-1, 3, -1, -1);
    seriesThumb = new QWidget(ui->scrollAreaWidgetContents);
    seriesThumb->setObjectName(QStringLiteral("seriesThumb"));
    sizePolicy.setHeightForWidth(seriesThumb->sizePolicy().hasHeightForWidth());
    seriesThumb->setSizePolicy(sizePolicy);
    seriesThumb->setMinimumSize(QSize(0, 150));
    seriesThumb->setMaximumSize(QSize(16777215, 200));
    
    seriesWidget->addWidget(seriesThumb);
    
    ui->seriesSetBox->insertLayout(0, seriesWidget);
    
    // Earlier (now abandoned) attempts to get child-specific mouse events
    //seriesThumb->setContextMenuPolicy(Qt::CustomContextMenu);
    //connect(seriesThumb, SIGNAL(mousePressEvent(QMouseEvent *)), this, SLOT(mousePressEvent(QMouseEvent *, &seriesSet.at(0)))); 
    
    // and add this to the list for later access
    seriesSet.insert(0, newSeries);
    

    }

    // this is my attempt to determine which child it is within the handler itself, so that the signature wouldn't be changed
    void seriesSurvey::mousePressEvent(QMouseEvent *event)
    {
    // determine which one the user clicked
    for (int i=0; i < seriesSet.size(); i++) {
    if (this == seriesSet.at(i))
    break;
    }
    if (i == seriesSet.size())
    QErrorMessage *error = new QErrorMessage (this);
    error->showMessage(tr("Error: Can't find current session item."));
    return;
    }

    if (event->button() == Qt::LeftButton)
    qDebug() << seriesSet[i]->getSeriesUID() << " series selected";
    else if (event->button() == Qt::RightButton)
    qDebug() << seriesSet[i]->getSeriesUID() << " series properties";
    else
    qDebug() << "something else";
    }

    /****************************************************** SERIES PACKAGE ***************************************************************

    • The series package comprises the following related classes:
      • imageSeries:
      • seriesSurvey (in namepace Ui) (subclassed from QWidget): the main class with the series set as a whole and the methods to
    •  display and interact with it
      
      1.      imageSeries
        
    •             |
      
      1.     seriesSurvey
        

    **************************************************************************************************************************************/

    class imageSeries
    {

    public:
    imageSeries();
    imageSeries(const QString &type, const QString &UID);

    const QString getSeriesFolder() const { return seriesFolder; };
    void setSeriesFolder(QString folder) { seriesFolder = folder; };

    private:
    QString seriesFolder;
    QWidget *seriesThumb;
    };

    namespace Ui {
    class seriesSurvey;
    }

    class seriesSurvey : public QWidget
    {
    Q_OBJECT

    QList<imageSeries> seriesSet;

    public:
    explicit seriesSurvey(QWidget *parent = 0);
    ~seriesSurvey();

    QList<imageSeries> &imageSeriesSet() { return seriesSet; };
    void mousePressEvent(QMouseEvent *event);

    private slots:
    void on_addSeriesButton_clicked();

    private:
    Ui::seriesSurvey *ui;
    };


  • Qt Champions 2016

    Hi
    Im not sure 100% what you are trying but the
    QMouseEvent event
    has sender info. Its base class QObject but you can cast it.
    QPushButton
    button = dynamic_cast<QPushButton*>(sender());
    if (button) // is not null it could be cast
    else
    http://doc.qt.io/qt-5/qsignalmapper.html

    also lets you have many objects that call same SLOT and you can then find out whom called.



  • Thank you! I did try to access sender(), with an updated handler:
    void seriesSurvey::mousePressEvent(QMouseEvent event)
    {
    // determine which one the user clicked
    qDebug() << qobject_cast<const QWidget
    >(this->sender());

    int i;
    for (i=0; i < seriesSet.size(); i++) {
    if (qobject_cast<const QWidget*>(this->sender()) == seriesSet.at(i).getSeriesThumb())
    break;
    }
    if (i == seriesSet.size()) {
    QErrorMessage *error = new QErrorMessage (this);
    error->showMessage(tr("Error: Can't find current session item."));
    return;
    }

    if (event->button() == Qt::LeftButton)
    qDebug() << seriesSet[i].getSeriesUID() << " series selected";
    else if (event->button() == Qt::RightButton)
    qDebug() << seriesSet[i].getSeriesUID() << " series properties";
    else
    qDebug() << "something else";
    }

    Unfortunately, my initial qDegug() reveals that it always comes back as 0x0. Perhaps I have expressed it incorrectly?

    Additionally, I did look at QSignalMapper. I see that it says "This class collects a set of parameterless signals, and re-emits them with integer, string or widget parameters corresponding to the object that sent the signal." The part about re-emitting them with a widget sounds very much to my need, however, the fact that it only does so with parameterless signals would not be helpful; I also need which button it was that was used.

    So I am still stuck!
    Andy


  • Lifetime Qt Champion

    Hi,

    An event handler is not a slot so there's no sender. What you can use is an event filter (see installEventFilter). With it you know what object received the event and you also have the event to analyze and react on.

    On a side note, qobject_cast is to be used when cast QObject derived classes

    Hope it helps


  • Qt Champions 2016

    @buckler said:
    Sorry, my bad. Was thinking of on_addSeriesButton_clicked .
    If the child widgets are of mixed types , then as @SGaist says, eventfilter
    is the way to go.



  • mrjj and SGaist,
    Hats off to you for helping me fix this. The event handler did it. mrjj, far from "my bad", I also learned from your suggestion. In this case however - as seems often from my short experience, SGaist gets the master prize.

    Thanks to all on the forum,
    Andy



  • @buckler
    I said event handler, but meant that the event filter did it :-).


  • Qt Champions 2016

    @buckler
    Yeah, that was clear even wrong word :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.