• Qt 2D绘图之六:图形视图框架的事件处理与传播


    一、简介

    图形视图框架中的事件都是首先由视图进行接收,然后传递给场景,再由场景传递给相应的图形项。而对于键盘事件,它会传递给获得焦点的图形项,可以使用QGraphicsScene类的setFocusItem()函数或者图形项自身调用setFocus()函数来设置焦点图形项。默认的,如果场景没有获得焦点,那么所有的键盘事件都会被丢弃。场景中的图形项获得了焦点,场景也会自动获得焦点。

    对于鼠标悬停效果,QGraphicsScene会调度悬停事件。如果一个图形项可以接收悬停事件,那么当鼠标进入它的区域之中时,它就会收到一个GraphicsSceneHoverEnter事件。如果鼠标继续在图形项的区域之中进行移动,那么QGraphicsScene就会向该图形项发送GraphicsSceneHoverMove事件。当鼠标离开图形项的区域时,它将会收到一个GraphicsSceneHoverLeave事件。图形项默认是无法接收悬停事件的,可 以使用QGraphicsItem类的setAcceptHoverEvents()函数使图形项可以接收悬停事件。

    所有的鼠标事件都会传递到当前鼠标抓取的图形项,一个图形项如果可以接收鼠标事件(默认可以)而且鼠标在它的上面被按下,那么它就会成为场景的鼠标抓取的图形项。


    二、实例

    下面来看一个例子。新建空的Qt项目,名称为myView。完成后先向本项目中添加一个Myltem自定 义图形项,然后在myitem.h文件中声明boundingRect()和paint()两个纯虚函数,再声明并定义一个公共的用于设置图形项填充色的函数和变量,最后添加一些事件处理函数的声明,完成后myitem.h文件内容如下:

    #ifndef MYITEM_H
    #define MYITEM_H
    
    #include <QGraphicsItem>
    
    class MyItem : public QGraphicsItem
    {
    public:
        MyItem();
    
        //返回要绘制图形项的矩形区域
        QRectF boundingRect() const;
    
        //用来执行实际的绘图操作
        void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                      QWidget *widget);
    
        //用来设置图形项填充色
        void setColor(const QColor &color) { brushColor = color; }
    
    protected:
        //鼠标按下事件处理函数,设置被点击的图形项获得焦点,并改变光标外观
        void mousePressEvent(QGraphicsSceneMouseEvent *event);
    
        //键盘按下事件处理函数,判断是否是向下方向键,如果是,则向下移动图形项
        void keyPressEvent(QKeyEvent *event);
    
        //悬停事件处理函数,设置光标外观和提示
        void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
    
        //右键菜单事件处理函数,为图形项添加一个右键菜单
        void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
    
    private:
        QColor brushColor; //画刷颜色
    
    };
    
    #endif // MYITEM_H
    

    使用了变量作为画刷的颜色,就可以动态指定图形项的填充色了,默认情况下图形项的填充色设置为红色。


    然后myitem.cpp文件修改如下:

    #include "myitem.h"
    #include <QPainter>
    #include <QCursor>
    #include <QKeyEvent>
    #include <QGraphicsSceneHoverEvent>
    #include <QGraphicsSceneContextMenuEvent>
    #include <QMenu>
    
    MyItem::MyItem()
    {
        brushColor = Qt::red;
    
        setFlag(QGraphicsItem::ItemIsFocusable);
        setFlag(QGraphicsItem::ItemIsMovable);
        setAcceptHoverEvents(true);
    }
    
    //返回要绘制图形项的矩形区域
    QRectF MyItem::boundingRect() const
    {
        qreal adjust = 0.5;
        return QRectF(-10 - adjust, -10 - adjust,
                      20 + adjust, 20 + adjust);
    }
    
    //用来执行实际的绘图操作
    void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                       QWidget *widget)
    {
        Q_UNUSED(option); //标明该参数没有使用
        Q_UNUSED(widget);
    
        //根据图形项是否获得焦点来使用不同颜色绘制图形项的轮廓
        if(hasFocus())
        {
            painter->setPen(QPen(QColor(255,255,255,200)));
        }
        else
        {
            painter->setPen(QPen(QColor(100,100,100,100)));
        }
    
        //动态指定图形项的填充色
        painter->setBrush(brushColor);
        painter->drawRect(-10, -10, 20, 20);
    }
    
    //鼠标按下事件处理函数,设置被点击的图形项获得焦点,并改变光标外观
    void MyItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
        Q_UNUSED(event);
    
        setFocus();
        setCursor(Qt::ClosedHandCursor);
    }
    
    //键盘按下事件处理函数,判断是否是向下方向键,如果是,则向下移动图形项
    void MyItem::keyPressEvent(QKeyEvent *event)
    {
        //实现视图的下移
        if(event->key() == Qt::Key_Down)
            moveBy(0, 10);
    }
    
    //悬停事件处理函数,设置光标外观和提示
    void MyItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
    {
        Q_UNUSED(event);
    
        setCursor(Qt::OpenHandCursor);
        setToolTip("I am item");
    }
    
    //右键菜单事件处理函数,为图形项添加一个右键菜单
    void MyItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
    {
        QMenu menu;
        QAction *moveAction = menu.addAction("move back");
        QAction *selectedAction = menu.exec(event->screenPos());
    
        if(selectedAction == moveAction)
        {
            setPos(0, 0);
        }
    }
    
    • 在鼠标按下事件处理函数中,为鼠标单击的图形项设置了焦点,这样当按下键盘时该图形项就会接收到按键事件。
    • 然后是键盘按下事件处理函数,如果按下了键盘的向下方向键,那么获得焦点的图形项就会向下移动,这里使用了 moVeBy(qreal dx, qreal dy)函数,它用来进行相对移动,就是相对于当前位置在水平方向移动dx,在垂直方向移动dy。在进行项目移动时,经常使用到该函数。
    • 然后是悬停事件处理函数,如果将鼠标光标移动到一个图形项上,可以看到光标外观改变了,而且出现了工具提示。
    • 然后是右键菜单事件,在一个图形项上右击,就会弹出一个菜单,如果选中该菜单,那么图形项会移动到场景原点。

    然后myview.h文件修改如下:

    #ifndef MYVIEW_H
    #define MYVIEW_H
    
    #include <QGraphicsView>
    
    class MyView : public QGraphicsView
    {
        Q_OBJECT
    public:
        explicit MyView(QWidget *parent = 0);
    
    protected:
    	//键盘按下事件处理函数
        void keyPressEvent(QKeyEvent *event);
    
    signals:
    
    public slots:
    
    };
    
    #endif // MYVIEW_H
    

    然后myview.cpp文件修改如下:

    #include "myview.h"
    #include <QKeyEvent>
    
    MyView::MyView(QWidget *parent) :
        QGraphicsView(parent)
    {
    }
    
    //键盘按下事件处理函数
    void MyView::keyPressEvent(QKeyEvent *event)
    {
        switch (event->key())
        {
            //数字“-”键
            case Qt::Key_Plus :
                scale(1.2, 1.2);
            break;
    
            //数字“+”键
            case Qt::Key_Minus :
                scale(1 / 1.2, 1 / 1.2);
            break;
    
            //右方向键
            case Qt::Key_Right :
                rotate(30);
            break;
        }
    
        QGraphicsView::keyPressEvent(event);
    }
    

    这里使用不同的按键来实现视图的缩放和旋转等操作。一定要注意,在视图的事件处理函数的最后一定要调用QGraphicsView类的keyPressEvent()函数,不然在场景或者图形项中就无法再接收到该事件了。


    最后修改main.cpp文件,并且将其内容更改如下:

    #include <QApplication>
    #include "myitem.h"
    #include "myview.h"
    #include <QTime>
    
    int main(int argc,char* argv[ ])
    {
        QApplication app(argc,argv);
    
        qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
    
        QGraphicsScene scene;
        scene.setSceneRect(-200, -150, 400, 300);
        
        for(int i = 0; i < 5; ++i) 
        {
            MyItem *item = new MyItem;
            item->setColor(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
            item->setPos(i * 50 - 90, -50);
            scene.addItem(item);
        }
    
        MyView view;
        view.setScene(&scene);
        view.setBackgroundBrush(QPixmap("../myView/background.png"));
        view.show();
    
        return app.exec();
    }
    

    这里在场景中添加了 5个图形项,分别为它们设置了随机颜色,然后将它们排成一行。可以使用键盘上的“ + ”和“-”键来放大和缩小视图,也可以使用向右方向键来旋转视图。


    三、效果

    执行程序,最初的效果如下:


    按右方向键后,旋转视图后:


    鼠标拖动图形项后:


  • 相关阅读:
    JS图片宽度自适应移动端
    SQL语句中drop、truncate和delete的用法
    C#求百分比
    JS刷新后回到页面顶部
    JS返回上一页并刷新代码整理
    jQuery 获取设置图片 src 的路径
    C#银行卡号每隔4位数字加一个空格
    input标签内容改变时触发事件
    C#的Split()方法
    数据库常见性能问题调优
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/11064518.html
Copyright © 2020-2023  润新知