13

ユースケース:これはかなり一般的な問題です。QMdiArea を持つ通常の QMainWindow には、QGraphicsView を持つ mdiChild が存在します。このビューは、内部に QGraphicsItems を含む QGraphicsScene を表示します。これらの項目の 1 つを右クリックすると、その項目が選択 (フォーカス) され、コンテキスト メニューが開きます。このメニューは、画面座標に便利に配置されています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

ドキュメントには次のように書かれています: ビューポートのどこにアイテムがあるか知りたい場合は、アイテムで QGraphicsItem::mapToScene() を呼び出してから、ビューで QGraphicsView::mapFromScene() を呼び出すことができます。
まさに私がしていることですよね?


ドイツのフォーラムで、次のことを示唆するスレッドに出くわしました。

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

それを使用すると、私の質問に対するより一般的な答えが得られる可能性があります...

4

3 に答える 3

9

私は実用的な解決策を見つけました。
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) の検出はkeyPressEvent()、「メイン」の QGraphicsItem で行われます (私のプログラムの構造による)。

于 2013-04-04T10:45:16.467 に答える
1

暗闇の中で突き刺すだけですが、これを見てください http://www.qtcentre.org/threads/36992-Keyboard-shortcut-event-not-received .

Qt のドキュメントを見ると、QGraphicsView を使用すると、ショートカットに関して例外的な動作が発生する可能性があるようです。

あなたが望む結果を達成するための規範的な方法があるかのように見えます。

コンテキスト メニュー、ショートカット、QGraphicsView の実装方法によっては、QGraphicsView の Qt::ContextMenuPolicy を適切に設定し、メニューを別の方法でビルドして呼び出す必要がある場合があります。

近いうちに非常に似たようなことをする必要があるので、この質問に非常に興味があります!

于 2012-03-27T10:40:12.537 に答える
1

コードは正しいようです。ただし、コンテキスト メニューの作成に問題がある可能性があります。

QContextMenu の親を MainWindow (またはアプリケーションでそのようなもの) に設定しましたか?

それがあなたの場合の問題かもしれないと思います。

幸運を!!

于 2012-03-26T18:17:34.240 に答える