查找QGraphicsItem的屏幕位置

Mar*_*ngs 12 c++ qt position viewport qgraphicsitem

使用案例:这应该是一个相当普遍的问题.在正常的QMainWindow中,QMdiArea与QGraphicsView一起生活在mdiChild中.此视图显示内部带有QGraphicsItems的QGraphicsScene.右键单击其中一个项目可选择(聚焦)项目并打开上下文菜单,该菜单可方便地放置在屏幕坐标处QGraphicsSceneMouseEvent::screenPos().这是按预期工作的.

现在,当用户按下某个键(例如Qt :: Key_Menu)时,我想显示相同的上下文菜单.我知道所选的(聚焦的)项目,我知道显示场景的视图.

所以我的问题是:
获取场景中QGraphicsItem的可见表示的位置(在全局,屏幕坐标中)的正确方法什么?

这是什么不起作用:

QGraphicsItem *item = ...; // is the currently selected item next to which the context menu shall be opened
QGraphicsScene *scene = ...; // is the scene that hosts the item
QGraphicsView *graphicsView = ...; // is the view displaying the scene, this inherits from QWidget

// get the position relative to the scene
QPointF sp = item->scenePos();
// or use
QPointF sp = item->mapToScene(item->pos());

// find the global (screen) position of the item
QPoint global = graphicsView->mapToGlobal(graphicsView->mapFromScene(sp));

// now
myContextMenu.exec(global);
// should open the context menu at the top left corner of the QGraphicsItem item, but it goes anywhere
Run Code Online (Sandbox Code Playgroud)

文档说: 如果你想知道项目所在的视口中的哪个位置,你可以在项目上调用QGraphicsItem :: mapToScene(),然后在视图上调用QGraphicsView :: mapFromScene().
这正是我正在做的,对吧?


刚刚在德国论坛中偶然发现了一个线索,暗示:

QGraphicsView *view = item->scene()->views().last();
Run Code Online (Sandbox Code Playgroud)

甚至更好:

QGraphicsView *view;
foreach (view,  this->scene()->views())
{
    if (view->underMouse() || view->hasFocus()) break;
}
// (use case in the forum thread:) // QMenu *menu = new QMenu(view);
Run Code Online (Sandbox Code Playgroud)

使用它可能会让我的问题得到更广泛的回答......

Mar*_*ngs 8

我找到了一个有效的解决方
QGraphicsItem必须在屏幕上可见.(可能是因为视图显示场景的其他一些点而不可见,所以可以将该点限制在视图的视口的矩形上.)

// get the screen position of a QGraphicsItem
// assumption: the scene is displayed in only one view or the first view is the one to determine the screen position for
QPoint sendMenuEventPos; // in this case: find the screen position to display a context menu at
QGraphicsItem *pFocusItem = scene()->focusItem();

if(scene() != NULL // the focus item belongs to a scene
    && !scene()->views().isEmpty() // that scene is displayed in a view...
    && scene()->views().first() != NULL // ... which is not null...
    && scene()->views().first()->viewport() != NULL // ... and has a viewport
    )
{
    QGraphicsView *v = scene()->views().first();
    QPointF sceneP = pFocusItem->mapToScene(pFocusItem->boundingRect().bottomRight());
    QPoint viewP = v->mapFromScene(sceneP);
    sendMenuEventPos = v->viewport()->mapToGlobal(viewP);
}

if(sendMenuEventPos != QPoint())
{
    // display the menu:
    QMenu m;
    m.exec(sendMenuEventPos);
}
Run Code Online (Sandbox Code Playgroud)

使用视图的视口将视图坐标映射到全局坐标非常重要.

上下文菜单键(Qt :: Key_Menu)的检测发生在keyPressEvent()"主"QGraphicsItem中(由于我的程序结构).