一、簡介
圖形視圖框架中的事件都是首先由視圖進行接收,然后傳遞給場景,再由場景傳遞給相應的圖形項。而對於鍵盤事件,它會傳遞給獲得焦點的圖形項,可以使用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個圖形項,分別為它們設置了隨機顏色,然后將它們排成一行。可以使用鍵盤上的“ + ”和“-”鍵來放大和縮小視圖,也可以使用向右方向鍵來旋轉視圖。
三、效果
執行程序,最初的效果如下:
按右方向鍵后,旋轉視圖后:
鼠標拖動圖形項后: