【Qt图形视图框架】自定义QGraphicsItem和QGraphicsView,实现鼠标(移动、缩放)及键盘事件、右键事件

80 篇文章 2 订阅
67 篇文章 1 订阅

说明

在使用Qt的图形视图框架实现功能时,一般会在其基础上进行自定义功能实现。
如:滚轮对场景的缩放,鼠标拖动场景中的项,以及可以在场景中进行右键操作等。

示例

myitem为自定义QGraphicsItem,实现了边框、重绘事件、鼠标悬停、按键、右键菜单等功能。

myitem.h
#ifndef MYITEM_H
#define MYITEM_H

#include <QGraphicsItem>

class MyItem : public QGraphicsItem
{
public:
    MyItem();
    // 边框
    virtual QRectF boundingRect() const override;
    // 重绘事件
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
               QWidget *widget) override;
    // 设置笔刷
    inline void setColor(const QColor &color) {brushColor = color;}

protected:
    // 鼠标按下函数,设置被点击的图形项得到焦点,并改变光标外观
    virtual void keyPressEvent(QKeyEvent *event) override;
    // 键盘按下函数,判断是不是向下方向键,若是是,则向下移动图形项
    virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
    // 悬停事件函数,设置光标外观和提示
    virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
    // 右键菜单函数,为图形项添加一个右键菜单
    virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;

private:
    QColor brushColor; // 笔刷颜色
};
#endif // MYITEM_H
myitem.cpp
#include "myitem.h"
#include <QPainter>
#include <QCursor>
#include <QKeyEvent>
#include <QGraphicsSceneHoverEvent>
#include <QGraphicsSceneContextMenuEvent>
#include <QMenu>

#define WIDTH 40
#define HEIGHT 40

#define POS 20

MyItem::MyItem()
{
    brushColor = Qt::black;

    setFlag(QGraphicsItem::ItemIsFocusable);
    setFlag(QGraphicsItem::ItemIsMovable);
    setAcceptHoverEvents(true);

}

QRectF MyItem::boundingRect() const
{
    qreal adjust = 0.5; // 返回上下左右+0.5个像素
    return QRectF(-POS - adjust, -POS - adjust,
                  WIDTH + adjust, HEIGHT + adjust);
}

void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
                   QWidget *)
{
    if (hasFocus()) {
        painter->setPen(QPen(QColor(255, 255, 255)));
    } else {
        painter->setPen(QPen(QColor(100, 100, 100)));
    }
    painter->setBrush(brushColor);
    painter->drawRect(-POS, -POS, WIDTH, HEIGHT);
}

void MyItem::mousePressEvent(QGraphicsSceneMouseEvent *e)
{
    setFocus();
    // 设置光标为手握下的形状
    setCursor(Qt::ClosedHandCursor);
    QGraphicsItem::mousePressEvent(e);
}

void MyItem::keyPressEvent(QKeyEvent *event)
{
    if (Qt::Key_Down == event->key())
        moveBy(0, 10);
    else if(Qt::Key_Up == event->key())
        moveBy(0, -10);
    else if(Qt::Key_Left == event->key())
        moveBy(-10, 0);
    else if(Qt::Key_Right == event->key())
        moveBy(10, 0);
    else{

    }
    QGraphicsItem::keyPressEvent(event);
}

void MyItem::hoverEnterEvent(QGraphicsSceneHoverEvent *)
{
    // 设置光标为手张开的形状
    setCursor(Qt::OpenHandCursor);
    setToolTip("click me");
}

void MyItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    QMenu menu;
    QAction *moveAction = menu.addAction("move origin");
    QAction *selectedAction = menu.exec(event->screenPos());
    if (selectedAction == moveAction) {
        setPos(0, 0);
    }
}

myview.h

myview继承QGraphicsView,重新实现了滚轮事件,可对场景进行缩放操作

#ifndef MYVIEW_H
#define MYVIEW_H

#include <QObject>
#include <QGraphicsView>

class MyView : public QGraphicsView
{
    Q_OBJECT
public:
    explicit MyView(QWidget *parent = 0);

protected:
    // 滚轮事件:缩放
    virtual void wheelEvent(QWheelEvent *event) override;
};
#endif // MYVIEW_H

myview.cpp
#include "myview.h"

#include "myview.h"
#include <QKeyEvent>

MyView::MyView(QWidget *parent) :
    QGraphicsView(parent)
{
}

void MyView::wheelEvent(QWheelEvent *event)
{
    if(event->delta() > 0)
    {
        scale(1.1, 1.1);
    }else{
        scale(0.9, 0.9);
    }
    // 加上这个,否则在场景和图形项中就没法再接收到该事件了
    QGraphicsView::wheelEvent(event);
}


调用
main.cpp
#include <QApplication>

#include "myitem.h"
#include "myview.h"
#include <QTime>
#include <QtMath>

#include <QDebug>


int main(int argc, char* argv[ ])
{
    QApplication app(argc, argv);
    qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
    QGraphicsScene scene;
    // 设置场景尺寸,减少动态渲染
    scene.setSceneRect(-300, -225, 600, 450);
	// 创建项
    for (int i = 0; i < 5; ++i) {
        MyItem *item = new MyItem;
        item->setColor(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
        item->setPos(i * 50 - 100, -50);
        scene.addItem(item);
    }
	// 声明视图
    MyView view;
    view.setScene(&scene);
    // 设置背景刷
    view.setBackgroundBrush(QBrush(QColor(220, 220, 220)));
    view.show();

    return app.exec();
}

效果

显示效果如下:

自定义图形视图

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FreeLikeTheWind.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值