2012-03-26 7 views
8

Caso de uso: Esto debería ser un problema bastante común. En un QMainWindow normal con QMdiArea vive un mdiChild con un QGraphicsView. Esta vista muestra un QGraphicsScene con QGraphicsItems dentro. Al hacer clic con el botón derecho en uno de estos elementos, se selecciona (enfoca) el elemento y se abre un menú contextual, que se coloca convenientemente en las coordenadas de la pantalla QGraphicsSceneMouseEvent::screenPos(). Esto está funcionando como se esperaba.Buscar posición de pantalla de un QGraphicsItem

Ahora me gustaría mostrar el mismo menú contextual cuando el usuario presiona una tecla (por ejemplo, Qt :: Key_Menu). Conozco el elemento seleccionado (enfocado), conozco la vista que muestra la escena.

Así que mi pregunta es:
Cuál es la forma correcta para obtener la posición (en global, las coordenadas de pantalla) de la representación visible de un QGraphicsItem dentro de una escena?

Aquí es lo que no funciona:

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: Si quieren saber en qué parte del puerto de vista un elemento se encuentra, puede llamar QGraphicsItem :: mapToScene() en el elemento y luego QGraphicsView: : mapFromScene() en la vista.
¿Qué es exactamente lo que estoy haciendo, verdad?


tropecé con a thread in a german forum que hace alusión a:

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

o aún mejor:

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

El uso que podrían permitir una respuesta más generalizada a mi pregunta ...

+0

Estaba a punto de publicar una respuesta, pero al volver a leer los documentos creo que estoy de acuerdo con su análisis: QGraphicsView :: mapFromScene debería dar coordenadas de la ventana gráfica (que vale la pena verificar). La única pregunta sería si hay un error latente en mapToGlobal en los widgets dentro de los hijos con MDI. –

+0

@JamesTurner Entonces, ¿cuál sería su primera suposición (que usted habría escrito en respuesta)? –

Respuesta

6

Encontré una solución de trabajo.
El QGraphicsItem debe estar visible en la pantalla. (Probablemente si no es visible porque la vista muestra algún otro punto de la escena, se podría frenar el punto de rect de vista de la vista.)

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

Es importante utilizar la ventana gráfica de la vista para el mapeo de la vista coords a coords globales.

La detección de la tecla de menú contextual (Qt :: Key_Menu) ocurre en el keyPressEvent() del QGraphicsItem "principal" (debido a la estructura de mi programa).

+1

Durante un evento, la vista de la vista se expone a la escena con 'QGraphicsSceneEvent :: widget()'. Puede usar 'QWidget :: isAncestorOf (event-> widget())' para encontrar la vista "correcta", en lugar de simplemente tomar la primera. – hmn

+0

A menos que la aplicación siempre se ejecute en pantalla completa, sería mejor mapear a 'QMainWindow' con' sendMenuEventPos = v-> viewport() -> mapTo (mainWindow, viewP); 'en lugar de usar' mapToGlobal' – vsz

1

El código parece ser correcto. Pero puede haber algún problema con la creación del menú contextual.

¿Ha establecido el elemento primario de QContextMenu en MainWindow (o algo por el estilo en su aplicación)?

Creo que ese podría ser el problema en su caso.

¡Buena suerte!

1

Solo una puñalada en la oscuridad pero eche un vistazo a este http://www.qtcentre.org/threads/36992-Keyboard-shortcut-event-not-received.

Al examinar la documentación de Qt, parece que el uso de QGraphicsView puede provocar un comportamiento excepcional con respecto a los accesos directos.

Parece que podría haber una forma normativa de lograr el resultado que desea.

Dependiendo de cómo implemente su menú contextual, accesos directos y QGraphicsView, puede que necesite establecer Qt :: ContextMenuPolicy para QGraphicsView de forma adecuada y crear y llamar al menú de manera diferente.

Estoy bastante interesado en esta pregunta, ya que tendré que hacer algo muy similar en breve!

+0

'Qt :: ActionsContextMenu' se ve * brillante *. Lo echaré un vistazo, pero no estoy muy seguro de que sea de ayuda. Mi problema general es más sobre el posicionamiento que sobre la entrada del teclado (puedo llamar a esa función desde cualquier lugar). –

+0

Supongo que depende de cómo lo haya implementado en cuanto a si es relevante o no. También encontré que la siguiente definición de función 'exec' sobrecargada en la documentación es de interés: http://doc.qt.nokia.com/4.7-snapshot/qmenu.html#exec-3. Parece un método estático impar pero alude a la posibilidad de que un QPoint no sea suficiente cuando "... el padre está incrustado en QGraphicsView". Es un poco misterioso. –

Cuestiones relacionadas