Solved 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
-
-
imageSeries
-
-
|
-
-
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_OBJECTQList<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;
}; -
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.htmlalso 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 -
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
-
-
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 :-). -
@buckler
Yeah, that was clear even wrong word :)