求助,怎么向qgraphicsview 例子手动发送鼠标事件

如何将鼠标事件传递给被遮挡的控件_百度知道
如何将鼠标事件传递给被遮挡的控件
很高兴为您解答。
绿色的 QGraphicsItem 不接受鼠标事件即可,请继续追问:
有个建议,又可以鼠标事件透传,可以使用 QGraphicsView 来实现,不过这也是分分钟的事儿,它作为 button 的背景, button 为 2。红色的z序设置为 0 ,
绿色为 1。这样就又有遮罩效果。
需要你派生 QGraphicsItem 实现一个 button 。
如果我的回答没帮助到您您好
知道智能回答机器人
根据知道用户的观点和内容总结出特定问题的答案,为知道用户提供更好的问答体验。
其他类似问题
为您推荐:
鼠标的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁21462人阅读
编程语言(8)
应大家的要求,还是把完整的工程文件贴出来,大家省点事:/file/id_86450.htm
先看看运行效果,我用的群创7寸屏,主机是mini2440,分辨率是800*480,程序写比较粗糙,但对初学者还是有一点启发,大家一起进步。
qt中提供了QGphicsView,QGraphicsScene,QGraphicsItem,QGraphicsPixmapItem是QGraphicsItem的子类
分辨创建它们的实例:view,scene,item,然后通过各自的方法scene-&addItem(item);view-&setScene(scene);就可以达到类似下图的效果,想要进一步定制,则要继承QGraphicsItem或QGraphicsPixmapItem,然后重写paint()、boundingRect()等方法,此外如果还想要获取鼠标事件,重写mousePressEvent等事件就好了,注意,一旦重写了mousePressEvent方法,就以为了qt不会再自动处理item的任何press事件了,可以在你重写的mousePressEvent方法中最后添加QGraphicsItem::mousePressEvent(event);解决这个问题,就是说你获取到了鼠标事件,但是依然让qt处理这个鼠标事件。
程序中的item可以水平拖动,拖动的同时图标大小会渐变,中间最大,两边渐小。
下面是源程序目录结构:
mainwindow.h与main.cpp是qt自动产生的代码,我没有产生窗口ui
myscene.h与某与scene.cpp是定义了类MyScene,继承自QGraphicsScene,我的目的是要获取其鼠标事件
nodeui.h与nodeui.cpp是定义了类NodeUI,继承自QGraphicsPixmapItem,目的相当多。
下面具体的源文件:myscene.h与myscene.cpp相对简单,就实现了一个功能
#ifndef MYSCENE_H
#define MYSCENE_H
#include &QGraphicsScene&
class MyScene : public QGraphicsScene
explicit MyScene(QObject *parent = 0);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void isMoving(QPointF &pos);
public slots:
#endif // MYSCENE_H
myscene.cpp
#include &myscene.h&
#include &QGraphicsSceneMouseEvent&
#include &QPointF&
#include &QDebug&
MyScene::MyScene(QObject *parent) :
QGraphicsScene(parent)
void MyScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
//QPointF pos = event-&scenePos();
QPointF pos(event-&scenePos().x()-beforePos.x(),event-&scenePos().y()-beforePos.y());
emit isMoving(pos);
//qDebug()&&&x:&&&pos.x()&&&y:&&&pos.y();
void MyScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
beforePos = event-&scenePos();
void MyScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
releasePos = event-&scenePos();
再看nodeui.h与nodeui.cpp,在原来的QGraphicsPixmapItem基础上又假如了点自己的东西
#ifndef NODEUI_H
#define NODEUI_H
#include &QGraphicsPixmapItem&
#include &QGraphicsItem&
#include &QStyleOptionGraphicsItem&
#include &QPainter&
#include &QGraphicsSceneMouseEvent&
#include &QPointF&
class NodeUI : public QObject,public QGraphicsPixmapItem
NodeUI(QString &file,QString &text,int imagesize=80);
//setup function
void setMyPixmap(QString &file,int size);
void setMyText(QString &text);
QString getMyText();
//virtual function
QRectF boundingRect()
QPainterPath shape()
void nodeIsMoving(QPointF &pos);
void nodeIsPressed();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
//QString myI
QString myT
#endif // NODEUI_H
nideui.cpp
#include &nodeui.h&
#include &QPixmap&
#include &iostream&
#include &QDebug&
NodeUI::NodeUI()
/*note: imagesize = 80 is in the nodeui.h*/
NodeUI::NodeUI(QString &file,QString &text,int imagesize)
setMyText(text);
setMyPixmap(file,imagesize);
void NodeUI::setMyText(QString &text)
void NodeUI::setMyPixmap(QString &file,int size)
//myImage =
pixmap.load(file);
pixmap= pixmap.scaled(size,size,Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
setPixmap(pixmap);
QRectF NodeUI::boundingRect() const
QRect rect = this-&pixmap().rect();
//return QRectF(rect);
return QRectF(0,0,rect.width(),rect.width()+15);
void NodeUI::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
QPixmap pixmap = this-&pixmap();
QRect rect = pixmap.rect();
painter-&drawPixmap(rect,pixmap);
//print name,calculate the text's heigh & width for center layout
QPen pen(Qt::black);
painter-&setPen(pen);
painter-&setRenderHint(QPainter::Antialiasing);
QFont font(&Verdana&,8, QFont::Normal);
painter-&setFont(font);
painter-&drawText(QRectF(0,rect.height(),rect.width(),15),Qt::AlignCenter,myText);
if (option-&state & QStyle::State_Sunken)
QRectF rect1 = boundingRect();
//QPen pen(Qt::darkGreen);
painter-&setPen(QPen(Qt::darkGreen));
QPainterPath NodeUI::shape() const
QRectF rect = boundingRect();
path.addRoundRect(rect, 5,5);
void NodeUI::mousePressEvent(QGraphicsSceneMouseEvent *event)
emit nodeIsPressed();
qDebug()&&&pressed&;
QGraphicsItem::mousePressEvent(event);
void NodeUI::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
update(boundingRect());
QGraphicsItem::mouseReleaseEvent(event);
QString NodeUI::getMyText()
return myT
最后是scene与item的文件mainwindow.cpp,继承了QMainWindow,作用就是画一个应用程序框架
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include &QtGui/QMainWindow&
#include &QGraphicsView&
#include &QGraphicsScene&
#include &QPointF&
#include &nodeui.h&
#include &myscene.h&
#include &QMap&
class MainWindow : public QMainWindow
MainWindow(QWidget *parent = 0);
~MainWindow();
NodeUI *selectedNodeUI();
bool isNodeUiClicked();
void nodeUiSizeAdjust();
protected:
void GetScreenInfo();
QGraphicsView *
//QGraphicsScene *
//instead of (NodeUI *)&(QPointF nodeUiP)
//目前弃用,由于QMap的顺序无法人为设定,按照内部key自动升序
//QMap&NodeUI*,QPointF&nodeUiM
//NodeUI *currentNodeUI;
//nodeui pressed or released
volatile bool mP
QList&NodeUI*& nodeUiL
QList&QPointF& nodeUiPosL
QList&QPixmap& nodeUiPixmapL
QList&NodeUI*&
QList&QPointF&
QPointF nodeUiP
qint16 sceenSizeX;
qint16 sceenSizeY;
private slots:
void isMoving(QPointF &pos);
void isPressed();
void isReleased();
void selectionChanged();
void nodeUiClicked(NodeUI* node);
#endif // MAINWINDOW_H
mainwindow.cpp
#include &mainwindow.h&
#include &QDesktopWidget&
#include &QApplication&
#include &QPixmap&
#include &QGraphicsItem&
#include &QMouseEvent&
#include &QWidget&
#include &QGraphicsPixmapItem&
#include &QMessageBox&
#include &QDebug&
const qreal MY_NODEUI_POS_Y = 200;
const qreal MY_NODEUI_DIS = 110;
const qreal MY_NODEUI_STA = 90;
MYNODEUI_SIZE = 100;
MYNODEUI_SIZE_M = 20;
SCREEN_SIZE = 800;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
mPressed =
//get windows size
GetScreenInfo();
view = new QGraphicsV
scene = new MyScene();
scene-&setSceneRect(0,0,800,480);
file = QString(&:/images/home.png&);
text = QString(&Home&);
pos = QPointF(MY_NODEUI_STA,MY_NODEUI_POS_Y);
node = new NodeUI(file,text,MYNODEUI_SIZE);
node-&setPos(pos);
nodeUiLists.append(node);
nodeUiPosLists.append(pos);
nodeUiPixmapLists.append(node-&pixmap());
here cannot delete node!!!!!!!!!!!!!!!
file = QString(&:/images/securitycamera.png&);
text = QString(&Vidio&);
pos = QPointF(MY_NODEUI_STA+MY_NODEUI_DIS*1,MY_NODEUI_POS_Y);
node = new NodeUI(file,text,MYNODEUI_SIZE);
node-&setPos(pos);
nodeUiLists.append(node);
nodeUiPosLists.append(pos);
nodeUiPixmapLists.append(node-&pixmap());
//APPLICATION:3
file = QString(&:/images/application.png&);
text = QString(&Application&);
pos = QPointF(MY_NODEUI_STA+MY_NODEUI_DIS*2,MY_NODEUI_POS_Y);
node = new NodeUI(file,text,MYNODEUI_SIZE);
node-&setPos(pos);
nodeUiLists.append(node);
nodeUiPosLists.append(pos);
nodeUiPixmapLists.append(node-&pixmap());
//NETWORK:4
file = QString(&:/images/network-2.png&);
text = QString(&Network&);
pos = QPointF(MY_NODEUI_STA+MY_NODEUI_DIS*3,MY_NODEUI_POS_Y);
node = new NodeUI(file,text,MYNODEUI_SIZE);
node-&setPos(pos);
nodeUiLists.append(node);
nodeUiPosLists.append(pos);
nodeUiPixmapLists.append(node-&pixmap());
//COMPUTER:5
file = QString(&:/images/smartphone.png&);
text = QString(&Phone&);
pos = QPointF(MY_NODEUI_STA+MY_NODEUI_DIS*4,MY_NODEUI_POS_Y);
node = new NodeUI(file,text,MYNODEUI_SIZE);
node-&setPos(pos);
nodeUiLists.append(node);
nodeUiPosLists.append(pos);
nodeUiPixmapLists.append(node-&pixmap());
//CUSTOMIZE:5
file = QString(&:/images/customize.png&);
text = QString(&Setting&);
pos = QPointF(MY_NODEUI_STA+MY_NODEUI_DIS*5,MY_NODEUI_POS_Y);
node = new NodeUI(file,text,MYNODEUI_SIZE);
node-&setPos(pos);
nodeUiLists.append(node);
nodeUiPosLists.append(pos);
nodeUiPixmapLists.append(node-&pixmap());
//重新计算UiSize
nodeUiSizeAdjust();
int i = 0;
foreach(NodeUI* node_temp,nodeUiLists)
node_temp-&setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
qDebug()&&&name:&&&node_temp-&getMyText()&&nodeUiPosLists.at(i);
scene-&addItem(node_temp);
//用于按钮的单机
view-&setScene(scene);
//set drag mode
//view-&setDragMode(QGraphicsView::RubberBandDrag);
view-&setRenderHints(QPainter::Antialiasing);
view-&setContextMenuPolicy(Qt::NoContextMenu);
view-&setBackgroundBrush(QImage(&:/images/shuibo2.jpg&));
//view-&setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
//view-&setCacheMode(QGraphicsView::CacheBackground);
setCentralWidget(view);
setWindowTitle(tr(&Main Window&));
//槽,当scene鼠标拖拽是执行
//控制UI图标的水平
void MainWindow::isMoving(QPointF &pos)
if(mPressed){
foreach(NodeUI* node,nodeUiLists)
node-&setPos(nodeUiPosLists.at(i).x()+pos.x(),MY_NODEUI_POS_Y);
nodeUiSizeAdjust();
//槽,当nodeui鼠标按下时执行,调用selectedNodeUI函数,更新currentNodeUI变量
//除此之外,selectionChanged()也是一个槽,由scene调用
void MainWindow::isPressed()
selectionChanged();
mPressed =
//槽,当nodeui鼠标释放时执行
//应当设置标志位,让UI图片停止对鼠标拖动事件的响应
void MainWindow::isReleased()
mPressed =
if(isNodeUiClicked())
qDebug()&&&clicked&;
qDebug()&&&release&;
//槽,当scene的selectedItem变化时,发送同名信号到此槽
void MainWindow::selectionChanged()
int i=0,j=0;
QList&QGraphicsItem *& items = scene-&selectedItems();
if (items.count() == 1) {
//当前所选择的UI图标的坐标
QPointF pos = items.first()-&pos();
NodeUI* node_temp = dynamic_cast&NodeUI *&(items.first());
qDebug()&&&items.x:&&&pos.x()&&&items.y:&&&pos.y();
foreach(NodeUI* node,nodeUiLists)
if(node == node_temp)
foreach(QPointF ppos,nodeUiPosLists)
nodeUiPosLists[i].setX((i-j)*MY_NODEUI_DIS+pos.x());
nodeUiPosLists[i].setY(MY_NODEUI_POS_Y);
//判断是否Nodeui接收的是否是单击信号。
//判断依据是当前单击的nodeui对象的pos与存储在nodeUiPosListsd的位置比较,相等则为单击
bool MainWindow::isNodeUiClicked()
QList&QGraphicsItem *& items = scene-&selectedItems();
if (items.count() == 1) {
QPointF pos = items.first()-&pos();
NodeUI* node_temp = dynamic_cast&NodeUI *&(items.first());
if(pos ==nodeUiPosLists.at(i)){
//emit nodeUiClicked(node_temp);
QMessageBox::information(this,&New Window&,&will open : &+node_temp-&getMyText());
void MainWindow::nodeUiSizeAdjust()
quint16 i=0;
foreach(NodeUI* node,nodeUiLists)
//qDebug()&&&i= &&&i;
QPointF pos=node-&pos();
pos.setX(node-&pos().x()+MYNODEUI_SIZE/2);
//pos.setX(node-&pos().x()+node-&pixmap().width());
if(pos.x()&=0 && pos.x()&=SCREEN_SIZE/2)
//(MYNODEUI_SIZE-MYNODEUI_SIZE_M)/(SCREEN_SIZE/2)==(size-20)/pos.x()
quint16 size=pos.x()/5+20;
QPixmap pixmap = nodeUiPixmapLists.at(i);
//QPixmap pixmap = nodeUiLists.at(i)-&pixmap();
pixmap = pixmap.scaled(size,size,Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
nodeUiLists[i]-&setPixmap(pixmap);
//if(pos.x()&SCREEN_SIZE/2 && pos.x()&=SCREEN_SIZE)
if(pos.x()&SCREEN_SIZE/2 && pos.x()&=SCREEN_SIZE+10)
//(MYNODEUI_SIZE-MYNODEUI_SIZE_M)/(SCREEN_SIZE/2)==(size-20)/pos.x()
quint16 size=(SCREEN_SIZE-pos.x())/5+20;
QPixmap pixmap = nodeUiPixmapLists.at(i);
//QPixmap pixmap = nodeUiLists.at(i)-&pixmap();
pixmap = pixmap.scaled(size,size,Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
nodeUiLists[i]-&setPixmap(pixmap);
MainWindow::~MainWindow()
//获取设备分辨率的呢个信息
void MainWindow::GetScreenInfo()
QDesktopWidget* desktopWidget = QApplication::desktop();
//获取可用桌面大小
//QRect deskRect = desktopWidget-&availableGeometry();
//获取设备屏幕大小
QRect screenRect = desktopWidget-&screenGeometry();
sceenSizeX = screenRect.width();
sceenSizeY = screenRect.height();
//获取系统设置的屏幕个数(屏幕拷贝方式该值为1)
//g_nScreenCount = desktopWidget-&screenCount();
最后是main.cpp
实例化MainWindow
#include &QtGui/QApplication&
#include &mainwindow.h&
int main(int argc, char *argv[])
QApplication a(argc, argv);
w.setWindowOpacity(1);
w.setWindowFlags(Qt::FramelessWindowHint);
w.setAttribute(Qt::WA_TranslucentBackground);
//w.showFullScreen();
return a.exec();
大概都写了注解了,其实看看一个名称也该大概了解其作用,写这程序时遇到的问题都记录在了前一篇qt学习笔记(四)中,记录一下,以备不时之需
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:659297次
积分:7406
积分:7406
排名:第1558名
原创:89篇
转载:23篇
评论:580条
(1)(1)(3)(1)(2)(1)(1)(6)(8)(4)(11)(12)(2)(4)(1)(5)(5)(1)(10)(10)(9)(14)后使用快捷导航没有帐号?
您尚未登录,请登录后浏览更多内容!
查看: 13480|回复: 7
在线时间364 小时帖子精华4Qter豆2855 贡献140 毅力486 注册时间最后登录
Qter豆2855
图形视图框架(下)版权声明该文章原创于Qter开源社区(),作者yafeilinux,转载请注明出处!
环境:Windows Xp + Qt 4.8.4+QtCreator 2.6.2
目录三、场景(QGraphicsScene)(一)场景层(二)索引算法(三)边界矩形(四)图形项查找(五)事件处理和传播(六)打印四、视图(QGraphicsView)(一)缩放与旋转(二)场景边框与场景对齐方式(三)拖动模式(四)事件传递(五)背景缓存(六)OpenGL渲染(七)图形项查找与图形项组(八)打印
三、场景(QGraphicsScene)QGraphicsScene提供了图形视图框架的场景,它有以下功能:提供了一个管理大量图形项的快速接口向每个图形项传播事件管理图形项的状态,比如选择和焦点处理提供无转换的渲染功能,主要用于打印
我们新建空的Qt项目,项目名称为graphicsView03,完成后添加main.cpp文件,更改其内容如下:
#include &QtGui&
int main(int argc,char* argv[ ]){& &QApplication app(argc,argv);
& &QGraphicsS& &scene.addText(&Hello, world!&);& &QGraphicsView view(&scene);& &view.show();
& &return app.exec();}
运行程序,效果如下:
这里使用addText()函数添加了一个文本图形项。执行这条语句就相当于执行了下面两条语句:
QGraphicsTextItem*item = new QGraphicsTextItem(&Hello, world!&);scene.addItem(item);
如果要删除一个图形项我们可以调用removeItem()函数,如:scene.removeItem(item);
(一)场景层一个场景分为三个层:图形项层(ItemLayer)、前景层(ForegroundLayer)和背景层(BackgroundLayer)。场景的绘制总是从背景层开始,然后是图形项层,最后是前景层。看下面的例子:我们在上面的程序中添加代码:
scene.setForegroundBrush(QColor(255,255,255,100));scene.setBackgroundBrush(Qt::green);
运行程序,效果如下:
对于前景层,我们一般不进行设置,或者像上面这样设置为半透明的白色。对于背景层,这里设置为了绿色,当然,我们也可以将一张图片设置为背景。
scene.setBackgroundBrush(QPixmap(&../graphicsView03/yafeilinux.jpg&));
运行程序,我们可以看到,图片默认是平铺的。
如果想进一步控制前景和背景层,我们可以重新实现drawForeground()函数和drawBackground()函数。
(二)索引算法索引算法,是指在场景中进行图形项查找的算法。QGraphicsScene中提供了两种选择,它们在一个枚举变量QGraphicsScene::ItemIndexMethod中,分别是:QGraphicsSecne::BspTreeIndex :应用Binary Space Partition tree,适合于大量的静态图形项。这个是默认值。QGraphicsScene::NoIndex :不用索引,搜索场景中所有的图形项,适合于经常进行图形项的添加、移动和删除等操作的情况。
我们可以使用setItemIndexMethod()函数进行索引算法的更改。
(三)边界矩形图形项可以放到场景的任何位置,场景的大小默认是没有限制的。而场景的边界矩形仅用于场景内部进行索引的维护。因为如果没有边界矩形,场景就要搜索所有的图形项,然后确定出其边界,这是十分费时的。所以如果要操作一个较大的场景,我们应该给出它的边界矩形。设置边界矩形,可以使用setSceneRect()函数。
(四)图形项查找场景最大的优势之一就是可以快速的锁定图形项的位置,即使有上百万个图形项,items()函数也能在数毫秒的时间内锁定一个图形项的位置。items()函数有几个重载函数来方便的进行图形项的查找。但是有时在场景的一个点可能重叠着几个图形项,这时我们可以使用itemAt()函数返回最上面的一个图形项。对于这些函数的使用,我们到后面讲视图时再举例讲解。
(五)事件处理和传播场景可以传播来自视图的事件,将事件传播给该点最顶层的图形项。但是就像我们在讲图形项时所说的那样,如果一个图形项要接收键盘事件,那么它必须获得焦点。而且,如果我们在场景中重写了事件处理函数,那么在该函数的最后,必须调用场景默认的事件处理函数,只有这样,图形项才能接收到该事件。这一点我们也到后面讲视图时再细讲。
(六)打印该部分内容也放到后面和视图一起讲。
四、视图(QGraphicsView)QGraphicsView 提供了视图窗口部件,它使场景的内容可视化。你可以给一个场景关联多个视图,从而给一个数据集提供多个视口。视图部件是一个滚动区域,就是说,它可以提供一个滚动条来显示大型的场景。如果要使用OpenGL,你可以使用QGraphicsView::setViewport()函数来添加QGLWidget 。
(一)缩放与旋转我们新建空的Qt项目,项目名称为graphicsView04,然后添加main.cpp文件,再新添一个C++ 类,类名为MyView,基类为QGraphicsView,类型信息选择“继承自QWidget”。
然后在myview.h中添加头文件:#include &QtGui&
然后声明事件槽函数:
protected:& &void wheelEvent(QWheelEvent *event);voidmousePressEvent(QMouseEvent *event);
我们到myview.cpp文件中进行函数的定义:
MyView::MyView(QWidget *parent) :& &QGraphicsView(parent){& &resize(400,400);& & setBackgroundBrush(QPixmap(&../graphicsView04/01.jpg&));//其实就是设置场景的背景& &QGraphicsScene *scene = new QGraphicsScene(this);& &scene-&setSceneRect(0,0,200,200);& &QGraphicsRectItem *item = new QGraphicsRectItem(0,0,20,20);& &item-&setBrush(Qt::red);& &scene-&addItem(item);& &setScene(scene);}
void MyView::wheelEvent(QWheelEvent*event)&&//滚轮事件{& &if(event-&delta() & 0)&&//如果鼠标滚轮远离使用者,则delta()返回正值& && & scale(0.5,0.5);&&//视图缩放& &else scale(2,2);}
void MyView::mousePressEvent(QMouseEvent*event) {& &rotate(90);&&//视图旋转顺时针90度}
这里我们定义了鼠标的滚轮事件和按下事件,在滚轮事件中,利用delta()函数返回值的正负来判断滚轮的移动方向,然后我们让视图进行缩放。
最后到main.cpp文件中,更改其内容如下:
#include &myview.h&
int main(int argc,char *argv[]){& &QApplication app(argc,argv);& &MyView *view = new MyV& &view-&show();& &return app.exec();}
我们运行程序,效果如下:& &
上面四幅图分别是:正常,旋转90度后,缩小后,放大后的效果。可以看到实现视图的变换是十分简单的。
(二)场景边框与场景对齐方式我们在上面讲场景时就提到了场景边框(SceneRect),这里再说说它在视图中的作用。我们前面说过,视图是可以提供滚动条的,但是,这只是在视图窗口小于场景时才自动出现的。如果我们不定义场景边框,那么当场景中的图形项移动到视图可视窗口以外的地方时,视图就会自动出现滚动条,但是即使是图形项再次回到可视区域,滚动条也不会消失。为了解决这个问题,我们可以为场景设置边框,这样,当图形项移动到场景边框以外时,视图是不会提供额外的滚动区域的。& && & 而当整个场景都可视时,也就是说视图没有滚动条时,我们可以通过setAlignment()函数来设置场景在视图中的对齐方式,如左对齐Qt::AlignLeft ,向上对齐Qt::AlignTop ,中心对齐Qt::AlignCenter。更多的对齐方式,可以查看帮助中Qt::Alignment 关键字。默认的对齐方式是Qt::AlignCenter 。而且几种对齐方式可以通过“按位或”操作一起使用。我们在上面的程序中的myitem.cpp文件中的构造函数最后添加一行代码:
setAlignment(Qt::AlignLeft | Qt::AlignTop);
运行效果如下图所示。
(三)拖动模式在QGraphicView中提供了三种拖动模式,分别是:QGraphicsView::NoDrag :忽略鼠标事件,不可以拖动。QGraphicsView::ScrollHandDrag :光标变为手型,可以拖动场景进行移动。QGraphicsView::RubberBandDrag :使用橡皮筋效果,进行区域选择,可以选中一个区域内的所有图形项。
我们可以利用setDragMode()函数进行相应设置。下面我们更改上面的程序。在myview.cpp中的构造函数中的最后添加一行代码:
setDragMode(QGraphicsView::ScrollHandDrag);//手型拖动
并将场景外框放大一点:
scene-&setSceneRect(0,0,800,800);
这时运行程序,虽然出现了小手,但是并不能拖动场景。为什么呢?我们在mousePressEvent()函数中添加一行代码:
QGraphicsView::mousePressEvent(event);
这时再运行程序,发现已经成功了。效果如下:
我们在事件函数的最后添加了一行:QGraphicsView::mousePressEvent(event);这样程序才能执行默认的事件。这也是我们下面要说的事件传播的内容的一部分。
(四)事件传递在上面我们看到必须在事件函数的最后将event参数传递出去,才能执行默认的事件操作。其实不止上面那一种情况,在图形视图框架中,鼠标键盘等事件是从视图进入的,视图将它们传递给场景,场景再将事件传递给该点的图形项,如果该点有多个图形项,那么就传给最上面的图形项。所以要想使这个事件能一直传播下去,我们就需要在重新实现事件处理函数时,在其最后将event参数传给默认的事件处理函数。比如我们重写了场景的键盘按下事件处理函数,那么我们就在该函数的最后写上QGraphicsScene::keyPressEvent(event);一行代码。
(五)背景缓存如果场景的背景需要大量耗时的渲染,可以利用CacheBackground来缓存背景,当下次需要渲染背景时,可以快速进行渲染。它的原理就是,把整个视口先绘制到一个pixmap上。但是这个只适合较小的视口,也就是说,如果视图窗口很大,而且有滚动条,那么就不再适合缓存背景。我们可以使用setCacheMode(QGraphicsView::CacheBackground);来设置背景缓存。默认设置是没有缓存QGraphicsView::CacheNone。
(六)OpenGL渲染QGraphicsView默认使用一个QWidget作为视口部件,如果我们要使用OpenGL进行渲染,可以使用setViewport()函数来添加一个QGLWidget对象。看下面的例子。我们先在项目文件graphicsView04.pro中加入
QT += opengl
说明要使用OpenGL模块,然后在myview.cpp文件中添加头文件:
#include &QtOpenGL&
最后在构造函数中加入代码:
QGLWidget *widget =new QGLWidget(this);setViewport(widget);
这样便使用OpenGL进行渲染了。关于OpenGL,我们在后面的3D绘图部分再讲。
(七)图形项查找与图形项组在前面讲场景时,我们就涉及了图形项查找的内容,当时没有细讲,现在我们把它和图形项组放到一起来讲解。先看一个例子,然后再介绍。在myview.cpp中的构造函数里将以前那个item改名为item1,然后再加入一个item2和一个图形项组对象group。更改后构造函数的部分代码如下:
QGraphicsRectItem *item1 = newQGraphicsRectItem(0,0,20,20);item1-&setBrush(Qt::red);item1-&setPos(10,0);scene-&addItem(item1);
QGraphicsRectItem *item2 = newQGraphicsRectItem(0,0,20,20);item2-&setBrush(Qt::green);item2-&setPos(30,0);scene-&addItem(item2);
QGraphicsItemGroup *group = newQGraphicsItemG&&//新建图形项组group-&addToGroup(item1);group-&addToGroup(item2);scene-&addItem(group);
setScene(scene);qDebug() && &itemAt(10,0) :& &&itemAt(10,0); //输出(10,0)点的图形项qDebug() && &itemAt(30,0) :& &&itemAt(30,0);qDebug() &&&#################################&; //分割线
然后我们到myview.h文件中protected下声明键盘按下事件槽函数:
void keyPressEvent(QKeyEvent *event);
再到myview.cpp中定义它,如下:
void MyView::keyPressEvent(QKeyEvent*event){& &qDebug() && items();&&//输出场景中所有的图形项& &items().at(0)-&setPos(100,0);& &items().at(1)-&setPos(0,100);& &QGraphicsView::keyPressEvent(event); //执行默认的事件处理}
这时运行程序,当按下键盘上任意键后,效果如下:
下面是输出框输出的信息:
可以看到,itemAt()函数可以输出场景上任意点的图形项。而items()函数可以输出场景上所有的图形项。这里应该说明,items()函数返回的图形项列表是按栈的降序排序的,也就是说,items().at(0)返回的是最后加入场景的图形项。从上面可以看出,最后加入的图形项是item2,其实,因为我们使用了group,而item1和item2都在group里,所以我们只需将group加入场景中就可以了,前面把item1和item2也加入场景是多余的。我们可以将scene-&addItem(item1);和scene-&addItem(item2);两行代码删掉。那么这时加入场景的顺序就是,先加入group,因为item1先加入group,所以下面将item1加入场景,最后加入场景的是item2,这就是为什么items.at(0)会是item2的原因。& && & 下面再说图形项组,其实图形项组也是一个图形项,它有图形项所拥有的所有特性。其作用就是,将加入它的所有图形项作为一个整体,对这个图形项组进行操作,就相当于对齐中所有图形项进行操作。图形项组是加入它的所有图形项的父图形项,在上面的输出的parent信息中我们可以看到这一点。下面我们将程序中的代码更改如下:
void MyView::keyPressEvent(QKeyEvent*event){& &items().at(2)-&setPos(100,100);& &QGraphicsView::keyPressEvent(event); //执行默认的事件处理}
运行程序,按下键盘上任意键,效果如下:
可以看到,两个图形项是同时移动的。我们要从图形项组中移除一个图形项,可以使用removeFromGroup()函数,它可以将给定的item从group中删除,要注意这时item依然存在,它会回到group的父图形项中,如果group没有父图形项,那么item就会回到场景中。我们可以使用场景的removeItme()函数来删除group,这样也会将group中所有的图形项从场景中删除。还有一种办法是利用场景的destroyItemGroup()函数,它会删除group并销毁它,但是group中的所有图形项会回到group的父图形项中,如果它没有父图形项,那么所有图形项就会回到场景中。
(八)打印图形视图框架提供了两个打印函数render(),一个是在QGraphicsScene中,一个是在QGraphicsView中,并且它们的函数原型是一模一样的。不过它们实现的效果稍有不同。看一面的例子。我们更改鼠标按下事件槽函数的内容如下:
void MyView::mousePressEvent(QMouseEvent*event){& & rotate(90); //视图旋转顺时针90度& &QPixmap pixmap(400,400);&&//必须指定大小& &QPainter painter(&pixmap);& &render(&painter,QRectF(0,0,400,400),QRect(0,0,400,400));&&//打印视图指定区域内容& & pixmap.save(&../graphicsView04/save.png&);& &QGraphicsView::mousePressEvent(event);}
这里我们使用了视图的render()函数,其中的QRectF参数是指设备的区域,这里是指pixmap。而QRect参数是指视图上要打印的区域。我们利用QPixmap类的save()函数,将pixmap图片保存到我们项目源码目录中,文件名为“save.png”。下面是运行程序后,点击鼠标,生成的图片的效果:&&
我们每点击一次鼠标,就会旋转视图,那么生成的图片就是当前视口的截图。下面我们使用场景的打印函数,将上面的打印一行的代码改为:
scene()-&render(&painter,QRectF(0,0,400,400),QRect(0,0,400,400));//打印场景内容
查看图片效果:
这时无论视图怎样变换,生成的图片总是一样的。而且它并没有打印场景背景的图片。就像我们看到的,视图的打印函数是依据视图的坐标系进行打印的,我们看到的就是打印出来后的效果,它可以看做是程序窗口的截屏。而场景的打印函数,是依据场景的坐标系的,无论视图怎么转换,只要场景坐标系没有变换,它打印出来的图片都是一样的。
结语& && & 图形视图框架是一个非常强大而且庞杂的系统,我们教程中也只是很笼统的介绍了一些最基本最常用的内容。如果大家想系统学习该部分知识,想学习如何使用该框架轻松搭建一个游戏,可以参考的第11章,以及的第二章。
涉及到的源码:
上一篇:&&
返回: & &
本帖子中包含更多资源
才可以下载或查看,没有帐号?
在线时间40 小时帖子精华0Qter豆274 贡献25 毅力116 注册时间最后登录
Qter2级会员, 积分 141, 距离下一级还需 159 积分
在vs2010里面建立的Qt工程,怎么包含QtOpenGL模块呢,都已经建立好了工程了,我只在建立工程的时候看见可以选择模块,当时没选QtOpenGL模块,现在怎么添加进去呢
在线时间364 小时帖子精华4Qter豆2855 贡献140 毅力486 注册时间最后登录
Qter豆2855
lzyinformation 发表于
在vs2010里面建立的Qt工程,怎么包含QtOpenGL模块呢,都已经建立好了工程了,我只在建立工程的时候看见可以 ...
先在.pro文件中添加 QT += opengl
然后使用时添加相应的头文件应该就可以了。
在线时间364 小时帖子精华4Qter豆2855 贡献140 毅力486 注册时间最后登录
Qter豆2855
lzyinformation 发表于
在vs2010里面建立的Qt工程,怎么包含QtOpenGL模块呢,都已经建立好了工程了,我只在建立工程的时候看见可以 ...
使用这种方法试试。
在线时间16 小时帖子精华0Qter豆63 贡献12 毅力26 注册时间最后登录
Qter1级会员, 积分 38, 距离下一级还需 62 积分
yafei老师你好,我用的QT5.1,建立空Qt项目,基类里面没有QGraphicsView,不知道如何继承啊?
在线时间364 小时帖子精华4Qter豆2855 贡献140 毅力486 注册时间最后登录
Qter豆2855
wangxiangjun88 发表于
yafei老师你好,我用的QT5.1,建立空Qt项目,基类里面没有QGraphicsView,不知道如何继承啊? ...
手动打上去即可。
在线时间16 小时帖子精华0Qter豆63 贡献12 毅力26 注册时间最后登录
Qter1级会员, 积分 38, 距离下一级还需 62 积分
yafeilinux 发表于
手动打上去即可。
好的,已经解决了,多谢
在线时间10 小时帖子精华0Qter豆58 贡献10 毅力19 注册时间最后登录
Qter1级会员, 积分 29, 距离下一级还需 71 积分
mark可一下,提醒自己记住:
Qt OpenGL 模块已被弃用,替代它的是Qt gui模块中的相应的OpenGL类。
QGLWidget类是Qt OpenGL遗留下的一部分,应该避免在新的代码里面使用。从5.4版本开始,推荐使用QOpenGLWidget和QOpenGL类。
注册账号后积极上传头像的会员
坚持登陆,持之以恒!
积极发帖的会员
Powered by
X2.5. Theme By

我要回帖

更多关于 qgraphicsview 的文章

 

随机推荐