Найти позицию на экране QGraphicsItem - PullRequest
10 голосов
/ 26 марта 2012

Вариант использования: Это должно быть довольно распространенной проблемой.В обычном QMainWindow с QMdiArea живет mdiChild с QGraphicsView.Это представление отображает 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

В документе сказано: ЕслиВы хотите знать, где в области просмотра находится элемент, вы можете вызвать 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);

Использование этого может дать более обобщенный ответ на мой вопрос ...

Ответы [ 3 ]

8 голосов
/ 04 апреля 2013

Я нашел рабочее решение.
Элемент 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 (из-за структуры моей программы).

1 голос
/ 27 марта 2012

Просто удар в темноте, но взгляните на это http://www.qtcentre.org/threads/36992-Keyboard-shortcut-event-not-received.

При просмотре документации Qt кажется, что использование QGraphicsView может привести к исключительному поведению в отношении ярлыков.

Похоже, что существует нормативный способ достижения желаемого результата.

В зависимости от того, как вы реализуете свое контекстное меню, ярлыки и QGraphicsView, вам может потребоваться установить Qt :: ContextMenuPolicy для QGraphicsView соответствующим образом и создать и вызвать меню по-разному.

Мне очень интересен этот вопрос, так как в скором времени мне нужно будет сделать что-то похожее!

1 голос
/ 26 марта 2012

Код кажется верным.Но может быть некоторая проблема с созданием контекстного меню.

Вы установили родительский объект для QContextMenu в MainWindow (или что-то подобное в вашем приложении) ??

Я думаю, это может быть проблемой в вашем случае.

Удачи !!

...