找到QGraphicsItem的屏幕位置。

时间:2023-02-02 00:11:35

Use case: This should be a fairly common problem. In a normal QMainWindow with QMdiArea lives an mdiChild with a QGraphicsView. This view displays a QGraphicsScene with QGraphicsItems inside. A right-click at one of these items selects (focusses) the item and opens a context menu, which is conveniently placed at the screen coordinates QGraphicsSceneMouseEvent::screenPos(). This is working as expected.

用例:这应该是一个相当普遍的问题。在QMdiArea的一个普通的QMainWindow中,使用一个QGraphicsView的mdiChild。这个视图显示一个QGraphicsScene,里面有QGraphicsItems。右键单击其中一个项目,选择(focusses)该项目并打开一个上下文菜单,该菜单被方便地放置在屏幕坐标QGraphicsSceneMouseEvent::screenPos()中。这是按预期工作的。

Now I'd like to show the same context menu when the user presses a key (e.g. Qt::Key_Menu). I know the selected (focussed) item, I know the view which displays the scene.

现在,我想在用户按下一个键时显示相同的上下文菜单(例如,Qt::Key_Menu)。我知道选中的(focussed)项,我知道显示场景的视图。

So my question is:
What is the correct way to get the position (in global, screen coordinates) of the visible representation of a QGraphicsItem within a scene?

所以我的问题是:在一个场景中,一个QGraphicsItem的可视化表示的位置(在全局、屏幕坐标)中正确的方式是什么?

Here is what's not working:

这里是不工作的:

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

The doc says: If you want to know where in the viewport an item is located, you can call QGraphicsItem::mapToScene() on the item, then QGraphicsView::mapFromScene() on the view.
Which is exactly what I'm doing, right?

doc说:如果你想知道一个项目位于viewport的哪个位置,你可以在项目上调用QGraphicsItem::mapToScene(),然后QGraphicsView::mapFromScene()在视图上。这就是我正在做的,对吧?


Just stumbled upon a thread in a german forum that hints to:

在德国的一个论坛上偶然发现了一条线索:

QGraphicsView *view = item->scene()->views().last();

or even nicer:

甚至更好的:

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

Using that might allow a more generalized answer to my question...

使用它可以使我的问题得到更普遍的答案……

3 个解决方案

#1


6  

I found a working solution.
The QGraphicsItem must be visible on the screen. (Probably if it's not visible because the view shows some other point of the scene, one could restrain the point to the view's viewport's rect.)

我找到了一个可行的解决方案。QGraphicsItem必须在屏幕上可见。(可能如果它不可见,因为视图显示了场景的其他一些点,可以限制指向视图的viewport的rect。)

// 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);
}

It is important to use the view's viewport for mapping the view coords to global coords.

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

The detection of the context menu key (Qt::Key_Menu) happens in the keyPressEvent() of the "main" QGraphicsItem (due to the structure of my program).

上下文菜单项的检测(Qt: Key_Menu)发生在“main”QGraphicsItem(由于程序结构)的keyPressEvent()中。

#2


1  

The code seems to be correct. But there might be some problem with the creation of the context menu.

代码似乎是正确的。但是,上下文菜单的创建可能存在一些问题。

Have you set the parent of the QContextMenu to MainWindow (or something of that sort in your application)??

您是否已经将QContextMenu的父元素设置为MainWindow(或应用程序中的类似内容)?

I think that might be the problem in your case.

我想这可能是你的问题所在。

Good Luck!!

祝你好运! !

#3


1  

Just a stab in the dark but have a look at this http://www.qtcentre.org/threads/36992-Keyboard-shortcut-event-not-received.

只是在黑暗中尝试一下,但是看看这个http://www.qtcentre.org/threads/36992-keyboardshortcut -not received。

On looking through the Qt documentation, it seems the use of QGraphicsView may cause some exceptional behaviour with regards to shortcuts.

在查看Qt文档时,似乎使用QGraphicsView可能会导致某些异常行为。

It looks as if there might be a normative way of achieving the result you desire.

看起来似乎有一种规范的方式来达到你想要的结果。

Depending how you are implementing your context menu, shortcuts and QGraphicsView, you might need to set the Qt::ContextMenuPolicy for the QGraphicsView appropriately and build and call the menu differently.

根据您如何实现上下文菜单、快捷方式和QGraphicsView,您可能需要设置Qt::适当的QGraphicsView的ContextMenuPolicy,并以不同的方式构建和调用菜单。

I'm quite interested in this question as I will need to do something quite similar shortly!

我对这个问题很感兴趣,因为我需要做一些类似的事情。

#1


6  

I found a working solution.
The QGraphicsItem must be visible on the screen. (Probably if it's not visible because the view shows some other point of the scene, one could restrain the point to the view's viewport's rect.)

我找到了一个可行的解决方案。QGraphicsItem必须在屏幕上可见。(可能如果它不可见,因为视图显示了场景的其他一些点,可以限制指向视图的viewport的rect。)

// 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);
}

It is important to use the view's viewport for mapping the view coords to global coords.

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

The detection of the context menu key (Qt::Key_Menu) happens in the keyPressEvent() of the "main" QGraphicsItem (due to the structure of my program).

上下文菜单项的检测(Qt: Key_Menu)发生在“main”QGraphicsItem(由于程序结构)的keyPressEvent()中。

#2


1  

The code seems to be correct. But there might be some problem with the creation of the context menu.

代码似乎是正确的。但是,上下文菜单的创建可能存在一些问题。

Have you set the parent of the QContextMenu to MainWindow (or something of that sort in your application)??

您是否已经将QContextMenu的父元素设置为MainWindow(或应用程序中的类似内容)?

I think that might be the problem in your case.

我想这可能是你的问题所在。

Good Luck!!

祝你好运! !

#3


1  

Just a stab in the dark but have a look at this http://www.qtcentre.org/threads/36992-Keyboard-shortcut-event-not-received.

只是在黑暗中尝试一下,但是看看这个http://www.qtcentre.org/threads/36992-keyboardshortcut -not received。

On looking through the Qt documentation, it seems the use of QGraphicsView may cause some exceptional behaviour with regards to shortcuts.

在查看Qt文档时,似乎使用QGraphicsView可能会导致某些异常行为。

It looks as if there might be a normative way of achieving the result you desire.

看起来似乎有一种规范的方式来达到你想要的结果。

Depending how you are implementing your context menu, shortcuts and QGraphicsView, you might need to set the Qt::ContextMenuPolicy for the QGraphicsView appropriately and build and call the menu differently.

根据您如何实现上下文菜单、快捷方式和QGraphicsView,您可能需要设置Qt::适当的QGraphicsView的ContextMenuPolicy,并以不同的方式构建和调用菜单。

I'm quite interested in this question as I will need to do something quite similar shortly!

我对这个问题很感兴趣,因为我需要做一些类似的事情。