2012-03-26 4 views
8

Использование: Это должна быть довольно распространенная проблема. В обычном QMainWindow с QMdiArea живет mdiChild с QGraphicsView. В этом представлении отображается QGraphicsScene с QGraphicsItems внутри. Щелчок правой кнопкой мыши по одному из этих элементов выбирает (фокусирует) элемент и открывает контекстное меню, которое удобно размещается на координатах экрана QGraphicsSceneMouseEvent::screenPos(). Это работает как ожидалось.Найти положение экрана QGraphicsItem

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

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

+0

Я собирался опубликовать ответ, но, перечитав документы, я думаю, что согласен с вашим анализом: QGraphicsView :: mapFromScene должен указывать координаты видового экрана (стоит проверить). Вопрос только в том случае, если в mapToGlobal есть скрытая ошибка в виджетах внутри детей MDI. –

+0

@JamesTurner Итак, какова была бы ваша первая догадка (которую вы бы написали в ответ)? –

ответ

6

Я нашел рабочее решение.
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); 
} 

Важно использовать окно просмотра мнения, для отображения на вид COORDS к глобальным мерам.

Обнаружение клавиши контекстного меню (Qt :: Key_Menu) происходит в keyPressEvent() «основного» QGraphicsItem (из-за структуры моей программы).

+1

Во время события окно просмотра открывается сцене с помощью 'QGraphicsSceneEvent :: widget()'. Вы можете использовать 'QWidget :: isAncestorOf (event-> widget())', чтобы найти «правильный» вид, а не просто взять первый. – hmn

+0

Если приложение всегда запускается в полноэкранном режиме, лучше было бы сопоставить 'QMainWindow' с' sendMenuEventPos = v-> viewport() -> mapTo (mainWindow, viewP); 'вместо использования' mapToGlobal' – vsz

1

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

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

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

Удачи !!

1

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

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

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

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

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

+0

'Qt :: ActionsContextMenu' выглядит * блестящим *. Я посмотрю на это, но я не очень уверен, что это поможет. Моя общая проблема связана скорее с позиционированием, чем с клавиатурным вводом (я могу вызвать эту функцию из любого места). –

+0

Я думаю, это зависит от того, как вы его реализовали в отношении того, насколько это важно или нет. Я также нашел следующее перегруженное определение функции 'exec' в документации, представляющее интерес: http://doc.qt.nokia.com/4.7-snapshot/qmenu.html#exec-3. Это похоже на нечетный статический метод, но намекает на возможность того, что QPoint недостаточно, если «... родитель встроен в QGraphicsView». Это немного загадочно. –

Смежные вопросы