在QGraphicsView框架中使用QGraphicsWidget

基本模式

一般来说, QGraphicsView框架是用来显示图元的, 但是有的时候我们也需要能够在View里面显示一些控件. 这个时候, QGraphicsWidget, 或者说QGraphicsProxyWidget 就派上用途了. 在大多数情况下, 它们还会需要和QGraphicsLayout配合使用, 当然也可以不用.

这种使用方式和我们使用一般的Widget控件的模式也是基本类似的:

  • 先创建一个QGraphicWidget的控件, 作为一个控件的容器, 就像我们创建一个QWidget作为容器一样.
  • 再创建一个QGraphicsLayout的具体派生类示例, 作为布局
  • 然后可以创建QGraphicsProxyWidget, 并添加到布局里面
  • 最后, 将这个widget添加到QGraphicsScene里面:

例如, 下面的模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 创建一个QEdit和QPushButton控件
QTextEdit *edit = new QTextEdit;
QPushButton *button = new QPushButton;
// 将它们绑定到QGraphicsProxyWidget上面
QGraphicsProxyWidget *buttonProxy = new QGraphicsProxyWidget;
buttonProxy->setWidget(button);
QGraphicsProxyWidget *editProxy = new QGraphicsProxyWidget;
editProxy->setWidget(edit);
// 创建一个QGraphicsWidget, 作为容器:
QGraphicsWidget *widget = new QGraphicsWidget;
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical, widget);
layout->addItem(editProxy);
layout->addItem(buttonProxy);
widget->setLayout(layout);

// 创建QGraphicsScene
QGraphicsScene scene(0, 0, 400, 300);
// 将QGraphicsWidget添加到Scene里面:
scene.addItem(widget);

// 显示:
GraphicsView view(&scene);
...

移动Widget

上面的使用方式下, 生成的QGraphicsWidget的位置是固定死的. 如果我们需要将其能够拖动, 能够改变它们的大小, 还需要做额外的工作. 这里的核心主要有几点:

  • 首先是itemChange()函数, 需要重载实现. 例如, 如果我们需要它们能够被拖动, 就需要处理QGraphicsItem::ItemPositionChangeQGraphicsItem::ItemPositionChanged.

  • 要让QGraphicsWidget的派生类处理itemChang(), 我们要设置Flag. 例如:

1
2
3
4
5
6
setFlags(QGraphicsItem::ItemIsMovable
| QGraphicsItem::ItemIsSelectable
| QGraphicsItem::ItemIsFocusable
| QGraphicsItem::ItemSendsScenePositionChanges
| QGraphicsItem::ItemSendsGeometryChanges
);
  • 最后, 我们需要相应鼠标事件, 我们需要判断应该将鼠标事件转发给谁处理. 我们需要通过QWidget::childAt()来判断, 如果鼠标按下的是QWidget的子类, 就将事件转发给QGraphicsProxyWidget, 否则, 转发给QGraphicsItem.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    void GraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
    if(event->button() == Qt::LeftButton)
    {
    if(auto wdiget = this->widget()->childAt(pos.toPoint()))
    {
    QGraphicsProxyWidget::mousePressEvent(event);
    //...
    }
    else
    {
    QGraphicsItem::mousePressEvent(event);
    //..
    }
    }
    //...
    }