【问题标题】:Find screen position of a QGraphicsItem查找 QGraphicsItem 的屏幕位置
【发布时间】:2012-04-09 22:25:28
【问题描述】:

用例:这应该是一个相当普遍的问题。在带有 QMdiArea 的普通 QMainWindow 中,有一个带有 QGraphicsView 的 mdiChild。这个视图显示了一个 QGraphicsScene,里面有 QGraphicsItems。右键单击这些项目之一选择(聚焦)该项目并打开上下文菜单,该菜单方便地放置在屏幕坐标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

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


偶然发现a thread in a german forum 暗示:

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

甚至更好:

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

使用它可能会更概括地回答我的问题...

【问题讨论】:

  • 我正要发布回复,但重新阅读文档后我认为我同意您的分析:QGraphicsView::mapFromScene 应该提供视口坐标(值得检查)。唯一的问题是,mapToGlobal 中 MDI 子组件中的小部件上是否存在潜在错误。
  • @JamesTurner 那么你的第一个猜测是什么(你会写下来作为回应)?

标签: c++ qt position viewport qgraphicsitem


【解决方案1】:

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

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

我认为这可能是你的问题。

祝你好运!!

【讨论】:

    【解决方案2】:

    只是在黑暗中刺伤,但看看这个http://www.qtcentre.org/threads/36992-Keyboard-shortcut-event-not-received

    在查看 Qt 文档时,似乎使用 QGraphicsView 可能会导致一些关于快捷方式的异常行为。

    看起来好像有一种规范的方式可以实现你想要的结果。

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

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

    【讨论】:

    • Qt::ActionsContextMenu 看起来闪亮。我会看看它,但我不太相信它会有所帮助。我的一般问题更多是关于定位而不是键盘输入(我可以从任何地方调用该函数)。
    • 我想这取决于你如何实现它是否相关。我还在文档中发现以下重载的exec 函数定义很有趣:doc.qt.nokia.com/4.7-snapshot/qmenu.html#exec-3。这似乎是一个奇怪的静态方法,但暗示了当“......父级嵌入 QGraphicsView”时 QPoint 不够的可能性。有点神秘。
    【解决方案3】:

    我找到了一个可行的解决方案。
    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);
    }
    

    使用视图的视口将视图坐标映射到全局坐标很重要。

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

    【讨论】:

    • 在事件期间,视图的视口以QGraphicsSceneEvent::widget() 暴露给场景。您可以使用QWidget::isAncestorOf(event->widget()) 找到“正确”的视图,而不是只取第一个。
    • 除非应用程序总是全屏运行,否则最好用sendMenuEventPos = v->viewport()->mapTo(mainWindow, viewP);映射到QMainWindow而不是使用mapToGlobal
    猜你喜欢
    • 1970-01-01
    • 2011-05-31
    • 2010-09-25
    • 2011-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多