Qt 检测QGraphicsSiteMgroup上的单击

Qt 检测QGraphicsSiteMgroup上的单击,qt,qgraphicsview,qgraphicsscene,Qt,Qgraphicsview,Qgraphicsscene,我一直在组装一个图像滑块,根据一些按钮为图像设置动画。作为我想要的效果的示例,请参见本页顶部() 我成功地将QObject/QGraphicsSiteMgroup子类化(在imageSlider.h和imageSlider.cpp中编码)并向其添加动画,从而完成了这部分过程。该代码可能对尝试类似操作的其他人有用 接下来,我想添加单击imageSlider的功能,它将发出clicked()信号,从而可以查询所选图像并根据该选择执行某些任务。听起来很容易 尝试1: 我的第一个,可能是最明显的尝试,是

我一直在组装一个图像滑块,根据一些按钮为图像设置动画。作为我想要的效果的示例,请参见本页顶部()

我成功地将QObject/QGraphicsSiteMgroup子类化(在imageSlider.h和imageSlider.cpp中编码)并向其添加动画,从而完成了这部分过程。该代码可能对尝试类似操作的其他人有用

接下来,我想添加单击imageSlider的功能,它将发出clicked()信号,从而可以查询所选图像并根据该选择执行某些任务。听起来很容易

尝试1:

我的第一个,可能是最明显的尝试,是在imageSlider中重新实现一个mouseReleaseEvent处理程序来捕捉鼠标点击。但是,此函数从未被调用

尝试2:

imageSlider添加到QGraphicscene,然后通过QGraphicsView查看。也许QGraphicsView正在处理鼠标点击,因此根本无法访问imageSlider,这是有道理的。因此,我将QGraphicsView子类化,以创建一个名为clickableQGraphicsView的类,该类具有一个重新实现的mouseReleaseEvent这确实有效。虽然我可以使用此方法继续,但为了美观起见,我想将与imageSlider交互所需的所有代码封装到imageSlider代码本身中。如果我使用这个方法,它需要两个类

尝试5:(尝试3和4没有成功)

我认为可以将常规QGraphicsView检测到的事件传递给imageSlider中的事件处理程序。这意味着我可以使用标准的QGraphicsView 类并具有在imageSlider中检测自身鼠标单击的能力。我安装了事件过滤器。imageSlider中的此事件处理程序在QGraphicsView中的任何鼠标移动时都会被调用,因此过滤器似乎可以工作。然而奇怪的是,没有检测到鼠标点击事件

那么,问题是:

我想你一定想知道我为什么不闭嘴,用第二次尝试。然而,我很好奇,我很想知道尝试1和尝试5不起作用的原因

最简单的测试方法是从下载项目代码: pro文件位于TestGUI文件夹中

可以通过更改imageSlider.h顶部的#define来编译各种尝试。如果所有定义都被注释掉,则不启用单击检测。可以通过取消注释相应的#define行来测试每个尝试

如果首选,受影响的代码将粘贴在下面


imageSlider.h代码如下所示:

    class imageSlider: public QObject, public QGraphicsItemGroup
{
    Q_OBJECT
    Q_PROPERTY(QPointF pos READ pos WRITE setPos)   /// these property access functions don't have to be reimplemented as they are implemented in QObject. Just declare them.

public:
    imageSlider(QGraphicsItem *parent = 0);
    ~imageSlider();

    virtual void addToGroup(QGraphicsItem *item);   // /virtual function is used so that the function can be reimplemented but using the same signature (name, arguments, etc)
    virtual void removeFromGroup(QGraphicsItem *item);
    void moveImage(int numImages);
    void setTransitionDuration(uint ms);
    void setEasingCurve(uint curveNum); //see the help file for QEasingCurve to see what the integers stand for

private:
    QList <QGraphicsItem*> items;   /// holds the images themselves
    uint transitionDuration; /// The duration of the transition in ms
    int currentImageIndex; /// The index of the currently displayed image
    QMutex animationMutexLock;  /// So that an animation cannot be called while the previous one is ongoing
    QEasingCurve::Type easingCurveType; /// the type of easing curve for the animation.

    int getXPosChange(int numImages);   /// Get the amount the position has to change by to slide by numImages images
    void animate(int xPosChange);   /// Move the images along by the number of pixels in xPosChange

public slots:
    void unlockMutex();

signals:
    void clicked(); /// Parent process can be connected to this. When clicked the getCurrentImageIndex() function can be called and a response carried out (like running a process, opening a link, etc).

    //*******************
    // TEST CODE
    //*******************
#ifdef MOUSECLICKDETECTATTEMPT1
public slots:
    void mouseReleaseEvent(QGraphicsSceneMouseEvent * event);
#endif
#ifdef MOUSECLICKDETECTATTEMPT5
protected:
    bool eventFilter(QObject *target, QEvent *event);
#endif

};
类图像滑块:公共QObject,公共QGraphicsSiteMgroup
{
Q_对象
Q_属性(QPointF pos READ pos WRITE setPos)///这些属性访问函数不必重新实现,因为它们是在QObject中实现的。只需声明它们即可。
公众:
imageSlider(QGraphicsItem*parent=0);
~imageSlider();
virtual void addToGroup(QGraphicsItem*item);///使用虚拟函数可以重新实现该函数,但使用相同的签名(名称、参数等)
虚拟void removeFromGroup(QGraphicsItem*项);
无效移动图像(整数图像);
无效设置转换持续时间(uint-ms);
void setEasingCurve(uint curveenum);//请参阅QEasingCurve的帮助文件以了解整数代表什么
私人:
QList items;///保存图像本身
uint transitionDuration;///转换的持续时间(毫秒)
int currentImageIndex;///当前显示图像的索引
QMutex animationMutexLock;///以便在上一个动画正在进行时无法调用该动画
QEasingCurve::类型easingCurveType;///动画的缓和曲线类型。
int getXPosChange(int numImages);///获取按numImages图像滑动所需的位置更改量
void animate(int-xPosChange);///按xPosChange中的像素数移动图像
公众时段:
void unlockMutex();
信号:
void clicked();///父进程可以连接到此。单击时,可以调用getCurrentImageIndex()函数并执行响应(如运行进程、打开链接等)。
//*******************
//测试代码
//*******************
#ifdef mouseclickdetetettempt1
公众时段:
无效mouseReleaseEvent(QGraphicsSceneMouseEvent*事件);
#恩迪夫
#ifdef mouseclickdetetettempt5
受保护的:
bool事件过滤器(QObject*目标,QEvent*事件);
#恩迪夫
};
图像滑块.cpp是:

#include "imageSlider.h"

/**
  * Constructor for image slider.
  */
imageSlider::imageSlider(QGraphicsItem *parent) :
    QObject(0),
    QGraphicsItemGroup(parent),
    transitionDuration(500),
    currentImageIndex(0),
    easingCurveType(QEasingCurve::Linear)
{
}

/**
  * Deconstructor for image slider.
  */
imageSlider::~imageSlider()
{
    if(~items.isEmpty())
        items.clear();
}

/**
  * Add QGraphicsItems (images from QPixmaps) to the image slider.
  */
void imageSlider::addToGroup(QGraphicsItem *item){
    //change the xpos of the item before adding so that the images line up one after the other
    int xpos = 0;
    for(int i=0;i<items.count();i++)
        xpos += items.at(i)->boundingRect().width();
    item->setX(xpos);
    //add to the items and group
    items << item;
    QGraphicsItemGroup::addToGroup(item);
}

/**
  * Remove items from the imageSlider.
  */
void imageSlider::removeFromGroup(QGraphicsItem *item)
{
    items.removeAll(item);
    QGraphicsItemGroup::removeFromGroup(item);
}

/**
  * Move the imageSlider along by numImages number of images.
  * numImages can be +ve (move images left) or -ve (move images right).
  */
void imageSlider::moveImage(int numImages)
{
    if(animationMutexLock.tryLock())    //the mutex will be unlocked on receiving the finished() signal from the animation object
    {
        int xPosChange = getXPosChange(numImages);
        if(xPosChange==0)   //not going to move, so unlock the mutex here as otherwise you have to wait for a zero move animation to finish before getting the next animation. Not a bug, but not ideal for user fluidity.
            animationMutexLock.unlock();
        else
            //Do the animation
            imageSlider::animate(xPosChange);
    }
}

/**
  * Calculate the distance the QGraphicsItemGroup must slide to show the rqeuired image.
  * A positive numImages move moves the current image to the left.
  * A negative numImages move moves the current image to the right.
  */
int imageSlider::getXPosChange(int numImages)
{
    //create an incrementer that increments up or down to the requested image
    int incrementer = 1;
    if(numImages<0)
        incrementer = -1;
    int imageToGoTo = currentImageIndex + numImages;
    //check that the requested image is within the bounds of the number of images we have
    if(imageToGoTo<0)
        imageToGoTo = 0;
    if(imageToGoTo>items.count()-1)
        imageToGoTo = items.count()-1;
    //calculate the positional change
    int posChange = 0;
    int i=0;
    for(i=currentImageIndex;i!=imageToGoTo;i+=incrementer)
        posChange += items.at(i)->boundingRect().width();   //add the width of each image to skip over
    //update the current image index to the image that will be shown
    currentImageIndex = imageToGoTo;
    //if we want to move to the right, make the positional change negative
    if(incrementer==1)
        posChange = -posChange;
    return posChange;
}

/**
  * Carry out the animation from one image to another.
  */
void imageSlider::animate(int xPosChange)
{
    QPointF currPos = this->pos();
    QPointF endPos = currPos;
    endPos.setX(currPos.x()+xPosChange);

    QPropertyAnimation *animation = new QPropertyAnimation(this,"pos");
    connect(animation,SIGNAL(finished()),SLOT(unlockMutex()));
    animation->setStartValue(currPos);
    animation->setEndValue(endPos);
    animation->setDuration(this->transitionDuration);
    animation->setEasingCurve(this->easingCurveType);
    animation->start(QAbstractAnimation::DeleteWhenStopped);
}

/**
  * A slot which is called when the animation is completed to unlock the mutex.
  * This mutex stops two animations from occurring at the same time.
  */
void imageSlider::unlockMutex()
{
    this->animationMutexLock.unlock();
}

/**
  * set function for the animation transition duration.
  */
void imageSlider::setTransitionDuration(uint ms)
{
    this->transitionDuration = ms;
}

/**
  * set functionfor the easing curve enum.
  */
void imageSlider::setEasingCurve(uint curveNum)
{
    this->easingCurveType = (QEasingCurve::Type)curveNum;
}

//*******************
// TEST CODE
//*******************
#ifdef MOUSECLICKDETECTATTEMPT1
/**
  * Try reimplementing the mouseReleaseEvent for the imageSlider to catch mouse clicks.
  */
void imageSlider::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "imageSlider mouse release event detected";
    emit clicked();
}
#endif

#ifdef MOUSECLICKDETECTATTEMPT5
/**
  * Try capturing clicks on the images within the slider using a QObject event filter (imageSlider inherits from QObject and QGraphicsItemGroup.
  */
bool imageSlider::eventFilter(QObject *target, QEvent *event)
{
    if(event->type()==QEvent::MouseButtonRelease)
    {
        qDebug() << "imageSlider mouse release event detected through the eventFilter";
        emit clicked();
        return true;
    }
    return false;
}
#endif
// 
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QPropertyAnimation>
#include "../imageSlider/imageSlider.h"
#include <QGraphicsView>

namespace Ui {
class MainWindow;
}

#ifdef MOUSECLICKDETECTATTEMPT2
class clickableQGraphicsView : public QGraphicsView
{
    Q_OBJECT

public:
    clickableQGraphicsView(QWidget *parent=0);
    ~clickableQGraphicsView();
public slots:
    virtual void mouseReleaseEvent(QMouseEvent *event);
};
#endif

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void on_pushButtonRight_clicked();
    void on_pushButtonLeft_clicked();
    void on_listWidgetAnimType_currentTextChanged(const QString &currentText);
    void on_spinBoxMSAnim_valueChanged(int arg1);
    void imageGroupClicked();

private:
    Ui::MainWindow *ui;
    imageSlider *imageGroup;
    QGraphicsScene *GScene;
    void moveImageSlider(int numImages);

    //****************
    // TEST CODE
    //****************
#ifdef MOUSECLICKDETECTATTEMPT2
    clickableQGraphicsView *clickView;
#endif

};

#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qmessagebox.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //*******************
    // Set up options list
    // for animation types
    //*******************
    for(int i=0;i<41;i++)
        ui->listWidgetAnimType->addItem(QString::number(i));

    //****************
    // Graphics Scene
    //****************
    QPixmap pixmap1(":imageSwipe/images/1.png");
    QGraphicsItem *Image1 = new QGraphicsPixmapItem(pixmap1);
    QPixmap pixmap2(":imageSwipe/images/2.png");
    QGraphicsItem *Image2 = new QGraphicsPixmapItem(pixmap2);
    QPixmap pixmap3(":imageSwipe/images/3.png");
    QGraphicsItem *Image3 = new QGraphicsPixmapItem(pixmap3);
    QPixmap pixmap4(":imageSwipe/images/4.png");
    QGraphicsItem *Image4 = new QGraphicsPixmapItem(pixmap4);

    GScene = new QGraphicsScene();
    GScene->setSceneRect(QRectF(0,0,Image1->boundingRect().width(),Image1->boundingRect().height()));

    imageGroup = new imageSlider;
    imageGroup->addToGroup(Image1);
    imageGroup->addToGroup(Image2);
    imageGroup->addToGroup(Image3);
    imageGroup->addToGroup(Image4);

    GScene->addItem(imageGroup);

    ui->graphicsViewGUIInterface->setScene(GScene);
    ui->graphicsViewGUIInterface->setGeometry(0,0,Image1->boundingRect().width(),Image1->boundingRect().height());
    //*******************
    // TEST CODE
    //*******************
    connect(imageGroup,SIGNAL(clicked()),this,SLOT(imageGroupClicked()));

#ifdef MOUSECLICKDETECTATTEMPT2
    clickView = new clickableQGraphicsView(this);
    clickView->setScene(GScene);
    clickView->setGeometry(20,20,Image1->boundingRect().width(),Image1->boundingRect().height());
#endif

#ifdef MOUSECLICKDETECTATTEMPT5
    ui->graphicsViewGUIInterface->installEventFilter(imageGroup);
#endif
}

MainWindow::~MainWindow()
{
    if(imageGroup)
    {
        disconnect(imageGroup);
        delete imageGroup;
    }
    if(GScene)
        delete GScene;
    delete ui;
}

void MainWindow::on_pushButtonRight_clicked()
{
    moveImageSlider(-1);
}

void MainWindow::on_pushButtonLeft_clicked()
{
    moveImageSlider(1);
}

void MainWindow::moveImageSlider(int numImages)
{
    imageGroup->moveImage(numImages);
}

void MainWindow::on_listWidgetAnimType_currentTextChanged(const QString &currentText)
{
    imageGroup->setEasingCurve(currentText.toUInt());
}

void MainWindow::on_spinBoxMSAnim_valueChanged(int arg1)
{
    imageGroup->setTransitionDuration((uint)arg1);
}

void MainWindow::imageGroupClicked()
{
    QMessageBox msgBox;
    msgBox.setText(QString("Received index = 1"));
    msgBox.exec();
}

//***************
// TEST CODE
//***************
#ifdef MOUSECLICKDETECTATTEMPT2
/**
  * The below functions are an attempt to subclass the QGraphicsView
  * to provide a click response.
  */
clickableQGraphicsView::clickableQGraphicsView(QWidget *parent) :
    QGraphicsView(parent)
{
}

clickableQGraphicsView::~clickableQGraphicsView()
{
}

void clickableQGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->type() == QEvent::MouseButtonRelease)
        qDebug() << "QGraphicsView event dectected";

}
#endif
#包括“imageSlider.h”
/**
*图像滑块的构造函数。
*/
imageSlider::imageSlider(QGraphicsItem*父项):
QObject(0),
QGraphicsSiteMgroup(父级),
过渡期(500),
currentImageIndex(0),
测量曲线类型(QEasingCurve::Linear)
{
}
/**
*图像滑块解构器。
*/
imageSlider::~imageSlider()
{
如果(~items.isEmpty())
items.clear();
}
/**
*将QGraphicsItems(来自Qpixmap的图像)添加到图像滑块。
*/
void imageSlider::addToGroup(QGraphicsItem*项){
//在添加之前更改项目的XPO,以便图像一个接一个地排列
int xpos=0;
对于(inti=0;iboundingRect().width();
项目->setX(xpos);
//添加到项目和组中
项目pos();
QPointF endPos=当前位置;
endPos.setX(currPos.x()+xPosChange);
QPropertyAnimation*动画=新的QPropertyAnimation(此“位置”);
连接(动画、信号(finished())、插槽(unlockMutex());
动画->设置起始值(currPos);
动画->设置结束值(结束位置);
动画->设置持续时间(此->过渡持续时间);
动画->设置测量曲线(此->测量曲线类型);
动画->开始(QAbstractAnimation::DeleteWhenStopped);
}
/*