2012-03-26 18 views
8

Caso di utilizzo: Questo dovrebbe essere un problema abbastanza comune. In una normale QMainWindow con QMdiArea vive un mdiChild con un QGraphicsView. Questa vista mostra una QGraphicsScene con QGraphicsItems all'interno. Un clic con il pulsante destro del mouse su uno di questi elementi seleziona (mette a fuoco) l'elemento e apre un menu di scelta rapida, posizionato opportunamente sulle coordinate dello schermo QGraphicsSceneMouseEvent::screenPos(). Funziona come previsto.Posizione dello schermo di una QGraphicsItem

Ora mi piacerebbe mostrare lo stesso menu contestuale quando l'utente preme un tasto (ad esempio Qt :: Key_Menu). Conosco l'oggetto selezionato (focalizzato), conosco la vista che mostra la scena.

Quindi la mia domanda è:
Qual è il modo corretto per ottenere la posizione (in globale, le coordinate dello schermo) della rappresentazione visibile di un QGraphicsItem all'interno di una scena?

Ecco ciò che non funziona:

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: Se volete sapere dove nel viewport un elemento si trova, è possibile chiamare QGraphicsItem :: mapToScene() sulla voce, quindi QGraphicsView: : mapFromScene() sulla vista.
Quale è esattamente quello che sto facendo, giusto?


appena imbattuto a thread in a german forum che allude a:

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

o ancora più bello:

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

Utilizzando che potrebbe consentire una risposta più generalizzato alla mia domanda ...

+0

Stavo per inviare una risposta, ma rileggendo i documenti penso di essere d'accordo con la tua analisi: QGraphicsView :: mapFromScene dovrebbe fornire le coordinate del viewport (vale la pena controllare). L'unica domanda sarebbe se c'è un bug latente in mapToGlobal sui widget all'interno dei bambini MDI. –

+0

@JamesTurner Quindi quale sarebbe la tua prima ipotesi (che avresti scritto in risposta)? –

risposta

6

Ho trovato una soluzione funzionante.
L'oggetto QGraphics deve essere visibile sullo schermo. (Probabilmente se non è visibile perché la vista mostra qualche altro punto della scena, si potrebbe frenare il punto di rect della finestra della 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); 
} 

E 'importante utilizzare finestra della vista per mappare le coordinate vista alle corde globali.

Il rilevamento del tasto del menu di scelta rapida (Qt :: Key_Menu) avviene nello keyPressEvent() del "principale" QGraphicsItem (a causa della struttura del mio programma).

+1

Durante un evento, la vista della vista viene esposta alla scena con 'QGraphicsSceneEvent :: widget()'. Puoi usare 'QWidget :: isAncestorOf (event-> widget())' per trovare la vista "corretta", invece di prendere solo la prima. – hmn

+0

A meno che l'applicazione non venga sempre eseguita a schermo intero, sarebbe meglio mappare a 'QMainWindow' con' sendMenuEventPos = v-> viewport() -> mapTo (mainWindow, viewP); 'invece di usare' mapToGlobal' – vsz

1

Il codice sembra essere corretto. Ma potrebbe esserci qualche problema con la creazione del menu di scelta rapida.

Hai impostato il genitore di QContextMenu in MainWindow (o qualcosa del genere nella tua applicazione) ??

Penso che potrebbe essere il problema nel tuo caso.

Buona fortuna !!

1

Solo una pugnalata al buio, ma dai un'occhiata a questo http://www.qtcentre.org/threads/36992-Keyboard-shortcut-event-not-received.

Osservando la documentazione Qt, sembra che l'uso di QGraphicsView possa causare un comportamento eccezionale in relazione alle scorciatoie.

Sembra che ci possa essere un modo normativo per raggiungere il risultato desiderato.

A seconda di come si sta implementando il menu di scelta rapida, i collegamenti e QGraphicsView, potrebbe essere necessario impostare Qt :: ContextMenuPolicy per QGraphicsView in modo appropriato e creare e richiamare il menu in modo diverso.

Sono abbastanza interessato a questa domanda in quanto dovrò fare qualcosa di molto simile a breve!

+0

'Qt :: ActionsContextMenu' sembra * lucido *. Ne darò un'occhiata, ma non sono molto fiducioso che possa essere d'aiuto. Il mio problema generale riguarda più il posizionamento rispetto all'input da tastiera (posso chiamare quella funzione da qualsiasi luogo). –

+0

Suppongo che dipenda da come l'hai implementato sul fatto che sia rilevante o meno. Ho trovato anche la seguente definizione di funzione 'exec' in overload nella documentazione che interessa: http://doc.qt.nokia.com/4.7-snapshot/qmenu.html#exec-3. Sembra un metodo statico dispari ma allude alla possibilità che un QPoint non sia sufficiente quando "... il genitore è incorporato in QGraphicsView". È un po 'misterioso. –

Problemi correlati