从零开始学Qt(64):Graphics View程序基本结构和功能实现

为了演示Graphics View程序基本结构,本文创建一个实例,是一个以QMainWindow为基类的窗口程序,其运行时界面如图所示。

实例程序的主要功能包括以下几点。

这个实例演示了 Graphics View绘图几个类的基本使用方法,演示视图、场景和绘图项3个坐标系的关系,以及它们之间的坐标转换。

自定义图形视图组件

QGraphicsView是Qt的图形视图组件,可以在UI设计器的Display Widgets分组里可以拖放一个 QGraphicsView组件到窗口上。但是本实例中需要实现鼠标在QGraphicsView上移动时就显示当前光标的坐标,这涉及mouseMoveEvent()事件的处理。QGraphicsView没有与mouseMoveEvent()相关的信号,因而无法定义槽函数与此事件相关联。

为此,从QGraphicsView继承定义一个类 GraphicsView,实现mouseMoveEvent()事件和mousePressEvent()事件,并把鼠标事件转换为信号,这样就可以在主程序里设计槽函数响应这些鼠标事件。

新建一个文件,选择“C++”类别下的“C++ Class”,然后点击“Choose”按钮,如下图所示:

类名设置为GraphicsView,基类输入为QGraphicsView,然后点击“Next”按钮完成添加。

下面是QWGraphicsView类的定义:

class GraphicsView : public QGraphicsView
{
  Q_OBJECT
  protected:
    void mouseMoveEvent(QMouseEvent * event);
    void mousePressEvent(QMouseEvent *event);
  public:
  	GraphicsView(QWidget *parent = 0);
  signals:
  	void mouseMovePoint(QPoint point);
  	void mouseClicked(QPoint point);
  };

mouseMoveEvent()是鼠标移动事件,其实现代码如下:

void GraphicsView::mouseMoveEvent(QMouseEvent *event)
{//鼠标移动事件
  QPoint point=event->pos(); //QGraphicsView 的坐标
  emit mouseMovePoint(point); //发射信号
  QGraphicsView::mouseMoveEvent(event);
}

在此事件响应代码里,通过事件的pos()函数获取鼠标光标在视图中的坐标point,然后作为参数发射mouseMovePoint(point)信号。这样,若在其他地方编写槽函数与此信号关联,就可以对鼠标移动事件作出响应。

mousePressEvent()是鼠标按键按下的事件,其实现代码如下:

void GraphicsView::mousePressEvent(QMouseEvent *event)
{ //鼠标左键按下事件
  if (event->button()==Qt::LeftButton){
  	QPoint point=event->pos(); //QGraphicsView 的坐标
  	emit mouseClicked(point);//发射信号
  }
  QGraphicsView::mousePressEvent(event);
}

在此事件响应代码里,首先判断是否是鼠标左键按下,然后通过事件的pos()函数获取鼠标光标在视图中的坐标point,然后作为参数发射mouseClicked(point)信号。

主窗口类定义与QGraphicsView组件升级

主窗口是一个从QMainWindow继承的类,重定义了resizeEvent()事件,对窗口改变大小的事件作出响应。槽函数on_mouseMovePoint()响应鼠标在图形视图上移动的事件信号,显示视图坐标和场景坐标;槽函数on_mouseClicked()响应鼠标单击信号,显示图形项的局部坐标;iniGraphicsSystem()用于创建Graphics View结构的各个对象。

class MainWindow : public QMainWindow
{
  Q_OBJECT
  public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
  private:
    Ui::MainWindow *ui;
    QGraphicsScene *scene;
    QLabel *labViewCord;
    QLabel *labSceneCord;
    QLabel *labItemCord;
    void iniGraphicsSystem(); //创建Graphics View 的各项
  protected:
  	void resizeEvent(QResizeEvent *event);
  private slots:
    void on_mouseMovePoint(QPoint point);
    void on_mouseClicked(QPoint point);
};

主窗口是采用UI设计器进行可视化设计的。在设计界面时,先从组件面板里放一个QGraphicsView组件到窗口上。但是我们要用的是从QGraphicsView继承的自定义图形视图组件GraphicsView, 需要将 QGraphicsView 升级为 GraphicsView。

在设计的窗口上选中放置的QGraphicsView组件,单击右键,在快捷菜单中选择“Promote to...”,出现如下图的对话框。

在其中选择基类名称QGraphicsView,升级类名称输入GraphicsView, 然后单击“Add”和“Promote”按钮,就可以将窗口上的QGraphicsView组件升级为GraphicsView组件。

窗口初始化

下面是主窗口的构造函数的代码:

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  labViewCord=new QLabel ("View 坐标:");
  labViewCord->setMinimumWidth(150);
  ui->statusbar->addWidget(labViewCord);
  labSceneCord=new QLabel ("Scene 坐标:");
  labSceneCord->setMinimumWidth(150);
  ui->statusbar->addWidget(labSceneCord);
  labItemCord=new QLabel ("Item 坐标:");
  labItemCord->setMinimumWidth(150);
  ui->statusbar->addWidget(labItemCord);
  ui->View->setCursor(Qt::CrossCursor);
  ui->View->setMouseTracking(true);
  ui->View->setDragMode(QGraphicsView::RubberBandDrag);
  QObject::connect(ui->View,SIGNAL(mouseMovePoint(QPoint)), this, SLOT(on_mouseMovePoint(QPoint)));
  QObject::connect(ui->View,SIGNAL(mouseClicked(QPoint)), this, SLOT(on_mouseClicked(QPoint)));
  iniGraphicsSystem();
}

槽函数on_mouseMovePoint()响应鼠标在图形视图上移动的mouseMovePoint()信号,实现代码如下:

void MainWindow::on_mouseMovePoint(QPoint point)
{//鼠标移动事件,point是GraphicsView的坐标,物理坐标
  labViewCord->setText(QString::asprintf("View 坐标:%d,%d", point.x(),point.y()));
  QPointF pointScene=ui->View->mapToScene(point); //转换到 Scene 坐标
  labSceneCord->setText(QString::asprintf("Scene 坐标:%.0f,%.0f", pointScene.x(),pointScene.y()));
}

信号传递的参数point就是鼠标在图形视图中的坐标,使用视图组件的mapToScene()函数可以将此坐标转换为场景中的坐标,这两个坐标在状态栏上显示。

槽函数on_mouseClicked()响应鼠标在图形视图上单击的mouseClicked()信号,代码如下:

void MainWindow::on_mouseClicked(QPoint point)
{//鼠标单击事件
  QPointF pointScene=ui->View->mapToScene(point); //转换到 Scene 坐标
  QGraphicsItem *item=NULL;
  item=scene->itemAt(pointScene, ui->View->transform () ); //获取光标下的图形项
  if(item != NULL) //有图形项
  {
  	QPointF pointItem=item->mapFromScene(pointScene); //图形项局部坐标
  	labItemCord->setText(QString::asprintf("Item 坐标:%.0f,%.0f", pointItem.x(), pointItem.y()));
  }
}

信号传递的参数point就是鼠标光标在图形视图中的坐标,先使用视图组件的mapToScene() 函数将此坐标转换为场景中的坐标pointScene,然后通过场景对象的itemAt()函数获得光标下的图形项。如果鼠标光标下有图形项,就用图形项的mapFromScene()函数将pointScene转换为图形项的局部坐标pointltem,并在状态栏上显示。

另外还定义了窗口的resizeEvent()事件的响应函数,以便在窗口变化大小时,显示视图区域的大小,以及场景的大小信息。其代码如下:

void MainWindow::resizeEvent(QResizeEvent *event)
{//窗口变化大小时的事件
  ui->labViewSize->setText(QString::asprintf("Graphics View 坐标,左上角总是(0,0),宽度=%d,高度=%d",
  ui->View->width(),ui->View->height()));
  QRectF rectF=ui->View->sceneRect(); //Scene 的矩形区
  ui->labSceneRect->setText(QString::asprintf("QGraphicsView::sceneRect=(Left,Top,Width,Height)=%.0f,%.0f,%.0f,%.0f",
  		rectF.left(),rectF.top(), rectF.width(), rectF.height()));
}

Graphics View系统初始化

构造函数中调用的iniGraphicsSystem()用于创建Graphics View结构中的其他元素,包括场景和多个图形项。其代码如下:

void MainWindow::iniGraphicsSystem()
{ //构造Graphics View的各项
  QRectF rect(-200,-100,400,200);//左上角坐标,宽度,高度
  scene=new QGraphicsScene(rect); //scene 逻辑坐标系定义
  ui->View->setScene(scene);
  //画一个矩形框,大小等于scene
  QGraphicsRectItem *item=new QGraphicsRectItem(rect);
  item->setFlags(QGraphicsItem::ItemIsSelectable //设置 flags
  		| QGraphicsItem::ItemIsFocusable);
  QPen pen;
  pen.setWidth(2);
  item->setPen(pen);
  scene->addItem(item);
  //画一个位于scene中心的椭圆,测试局部坐标
  QGraphicsEllipseItem *item2=new QGraphicsEllipseItem(-100,-50,200,100);
  item2->setPos(0,0);
  item2->setBrush(QBrush(Qt::blue));
  item2->setFlags(QGraphicsItem::ItemIsMovable
  		| QGraphicsItem::ItemIsSelectable
 		 | QGraphicsItem::ItemIsFocusable);
  scene->addItem(item2);
  //画一个圆,中心位于scene的边缘
  QGraphicsEllipseItem *item3=new QGraphicsEllipseItem(-50,-50,100,100);
  item3->setPos(rect.right(),rect.bottom());
  item3->setBrush(QBrush(Qt::red));
  item3->setFlags(QGraphicsItem::ItemIsMovable
  		| QGraphicsItem::ItemIsSelectable
  		| QGraphicsItem::ItemIsFocusable);
  scene->addItem(item3);
  scene->clearSelection();
}

可视化设计窗体时,将GraphicsView类对象的名称命名为View,并且自动填充主窗口的工作区。创建场景并与View关联的代码如下:

QRectF rect(-200,-100,400,200);//左上角坐标,宽度,高度
scene=new QGraphicsScene(rect); //scene 逻辑坐标系定义
ui->View->setScene(scene);

这里用一个矩形定义了创建的场景的坐标系统,表示场景的左上角坐标是(-200, -100),场景 宽度为400,高度为200,这样,场景的中心点是(0,0),这是场景的坐标系。

创建了一个矩形框图形项item,矩形框的大小就等于创建的场景的大小,矩形框不能移动。

创建的第二个图形项item2是一个椭圆,椭圆的左上角坐标是(-100,-50),宽度200,高度100, 所以椭圆的中心是(0,0),这是图形项的局部坐标系。再采用setPos(0,0)设置椭圆在场景中的位置,若不调用setPos()函数设置图形项在场景中的位置,缺省为位置为(0,0)。椭圆设置为可移动、可选择、可以获得焦点。

创建的第三个图形项item3是一个圆,圆的左上角坐标是(-50,-50),宽度100,高度100,所 以圆的中心是(0,0),这是图形项的局部坐标系。再采用setPos()设置圆在场景中的位置。

item3->setPos(rect.right(),rect.bottom());

其中心位置是场景的右下角,圆的一部分区域是超出了场景的矩形区域的,但是整个圆还是 可以正常显示的。

从这个实例程序可以看到Graphics View结构中场景与视图的关系,如何创建图形项组件,场景,视图,图形项各自的坐标系以及坐标系之间的转换关系。

展开阅读全文

页面更新:2024-03-19

标签:坐标系   视图   坐标   函数   组件   图形   信号   场景   窗口   结构   事件   功能   程序

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top