2012-02-22 14 views
12

Sto lavorando in un progetto in cui ho bisogno di aprire (mostrare o popup) automaticamente gli elementi in QMenuBar.Come ripetere le azioni di un menu in Qt?

Diciamo che ho la prossima barra dei menu:

File  Edit  Help 
    -op1  -op1  -op1 
    -op2  -op2  -op2 

Per impostare un'azione (visualizza il menù asociated con quell'azione) Io uso:

menuBar->setActiveAction(mymenuactionpointer); 

Per quanto ne so, posso usare uno dei seguenti per ottenere una lista di puntatori agli elementi di QMenuBar:

QMenuBar::actions(); 

o

QList<Object*> lst1 = QMenuBar::findChildren<QObject*>(); 

QList<Object*> lst2 = QMenuBar::findChildren<QAction*>(); 

Quando uso QMenuBar::findChildren<QAction*>() o MenuBar::actions() ho ottenuto un elenco dei menu a barra dei menu, voglio dire, ho ottenuto dalla mia "File, Edit, Help" QMenuBar, la dimensione del QList in questo caso è 3.

Quando ho utilizzare QMenuBar::findChildren<QObject*>() Ho ottenuto un elenco di QObject di dimensione 6, che è il numero corretto di elementi nella barra dei menu. Tuttavia, ho tryied gettato a QAction *

QAction *a = (QAction *)lst1.at(0); 
QAction *a = qobject_cast<QAction*>(lst1.at(0)); 
QAction *a = dynamic_cast<QAction*>(lst1.at(0)); 

In tutti questi casi a non è nullo, ma quando cerco di ottenere il nome dell'azione QAction::title() che provoca sempre mi Segmentation Fault.

ho cercato e ho trovato here che dopo aver ottenuto la lista di azioni barra dei menu, si può chiedere a QAction::menu() (che restituisce un puntatore QMenu valida se l'articolo è un menu) per sapere se l'articolo è un QMenu, se sì, , si può ripetere ottenendo l'elenco delle azioni di quel menu e continuare a ripetere. Ma questo non funziona per me, mi aspettavo che per

QList<Object*> lst2 = QMenuBar::findChildren<QAction*>(); 

ogni elemento "File, Modifica Help" QAction::menu() restituisce un puntatore menù valida, così ho potuto ottenere l'elenco delle azioni di ciascun menu, ma questo fa non funziona affatto per me.

Apprezzo molto il tuo tempo e il tuo aiuto, spero che questa domanda aiuti più persone. Sto davvero avendo un momento difficile con questo.

Grazie in anticipo.

+0

io non sono sicuro circa la parte finale della tua domanda. 'QList list = menuBar() -> findChildren ();' restituisce una lista valida di 'QMenu *' s che puoi ripetere usando una funzione ricorsiva, e puoi ottenere '-> actions()'. Cosa non funziona per te? – Hossein

risposta

0

Il motivo per cui qobject_cast non funziona è che ci sono solo tre QActions con QMenuBar come genitore. Gli altri tre sono QObjects diversi (suppongo che siano i tre QMenus), quindi il cast fallisce. Le QActions associate a quei menu sono quindi in quelle, non nella root QMenuBar. Non riesco a capire perché non sia possibile creare un elenco principale di QActions ripetendo ricorsivamente attraverso QMenus.

È possibile utilizzare il puntatore QAction dalla definizione dell'interfaccia utente se si è in cerca di un menu conosciuto, che potrebbe non attivare i menu padre. Se si sta tentando di automatizzare i test, trigger() sulla QAction desiderata è probabilmente il più dettagliato possibile. Se stai provando a fare cose in risposta alle azioni dell'utente, modificare le barre degli strumenti è probabilmente un mezzo migliore di feedback contestuale, in quanto non si interrompe. Qualche altro dettaglio su ciò che stai effettivamente cercando di ottenere sarebbe d'aiuto.

6

Di seguito è come iterare attraverso ogni voce di menu nella barra dei menu, cercherà anche tutti i menu sottostanti in modo da non aver bisogno di chiamate ricorsive qui.

// assuming you have a private QActionGroup* actions; defined in the header.. 
// ...and a slot named 'onAction(QAction*)' as well... this should work: 
QList<QMenu*> lst; 
lst = ui->menuBar->findChildren<QMenu*>(); 
actions = new QActionGroup(this); 
foreach (QMenu* m, lst) 
{ 
    foreach (QAction* a, m->actions()) 
    { 
     actions->addAction(a); 
    } 
} 
connect(actions,SIGNAL(triggered(QAction*)),this,SLOT(onAction(QAction*))); 

Come si può vedere, è possibile collegare uno slot master per gestire i vari eventi un'azione potrebbe riportare (ho appena mostrato innescato qui, ma si ottiene l'idea). Spero che questo aiuti .. qualcuno ..

Note Ho usato il QActionGroup per scopi di esempio sull'utilizzo della lista da cui è possibile scorrere, ma non dovresti usarlo a meno che tu non abbia a che fare con gruppi radio poiché questo è il suo scopo. In secondo luogo, se vuoi le azioni perché hai intenzione di collegarle in un unico metodo per gestire tutti gli elementi, ti suggerisco di usare i segnali attivati ​​/ in bilico di QMenu o se hai bisogno di sapere quando un menu sta per apparire, avrai bisogno QMenuBar parla diToShow(). Non riesco a pensare ad una ragione (almeno per me) che non puoi fare ciò che ti serve in quei segnali dato che hai passato QAction * nello slot. Ma se DEVI farlo nell'altro modo, puoi farlo nel modo in cui ho mostrato sopra, potresti semplicemente non voler usare QActionGroup perché il raggruppamento radio è quello per cui è stato progettato. (È possibile lavorare in giro che non aggiungendo gli elementi che sono 'controllabile' nel gruppo

8

Il modo corretto per enumerare un QMenu è quello di utilizzare le actions() funzioni, ma c'è un problema -. Alcune delle azioni sono sottomenu, e hanno bisogno di essere iterata in modo ricorsivo infatti, ogni QMenu è associata ad un QAction, ed entrambi contengono puntatori a vicenda -. vedi QMenu::menuAction() e QAction::menu()

e 'fondamentale capire che ogni QMenu è anche associato ad una. QAzione Quindi, sapendo che, l'implementazione corretta è la seguente:

void enumerateMenu(QMenu *menu) 
{ 
    foreach (QAction *action, menu->actions()) { 
     if (action->isSeparator()) { 
      qDebug("this action is a separator"); 
     } else if (action->menu()) { 
      qDebug("action: %s", qUtf8Printable(action->text())); 
      qDebug(">>> this action is associated with a submenu, iterating it recursively..."); 
      enumerateMenu(action->menu()); 
      qDebug("<<< finished iterating the submenu"); 
     } else { 
      qDebug("action: %s", qUtf8Printable(action->text())); 
     } 
    } 
} 
+1

Grazie per la risposta. è stato utile – PeerPandit

0

questo mette tutto insieme:

template <class Function> 
class QMenuBarIterator { 
    QMenuBar *i_barP; 

    void iterate_sub(Function f, size_t tabsL, QMenu* m) { 
     foreach (QAction *action, m->actions()) { 
      f(tabsL, action); 

      if (action->menu()) { 
       iterate_sub(f, tabsL + 1, action->menu()); 
      } 
     } 
    } 

    public: 
    QMenuBarIterator(QMenuBar *barP) : i_barP(barP) {} 

    virtual void operator()(size_t levelL, QAction *actionP) { 
    } 

    void iterate(Function f) { 
     QList<QMenu *> menuBar = i_barP->findChildren<QMenu *>(); 

     foreach (QMenu* m, menuBar) { 
      f(0, m->menuAction()); 
      iterate_sub(f, 1, m); 
     } 
    } 
}; 

/***************************************************************************/ 
class CMenuLogger { 
    public: 

    void operator()(size_t tabsL, QAction *action) { 
     SuperString  tabStr(GetIndentString(tabsL)); // returns a string with tabsL tab characters in it 

     if (action->isSeparator()) { 
      qDebug("%s-------------------", tabStr.utf8Z()); 

     } else { 
      qDebug("%s%s (%s)", 
       tabStr.utf8Z(), 
       qUtf8Printable(action->text()), 
       qUtf8Printable(action->objectName())); 
     } 
    } 
}; 

poi nel vostro principale:

{ 
    QMenuBarIterator<CMenuLogger>   bar(ui->menuBar); 

    bar.iterate(CMenuLogger()); 
} 
Problemi correlati