2012-02-22 23 views
12

Im làm việc trong một dự án mà tôi cần mở (hiển thị hoặc bật lên) tự động các mục trong QMenuBar.Làm cách nào để lặp lại hành động của menu trong Qt?

Hãy nói rằng tôi có thanh menu tiếp theo:

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

Để thiết lập một hành động (hiển thị menu asociated với hành động đó) tôi sử dụng:

menuBar->setActiveAction(mymenuactionpointer); 

Như tôi biết, tôi có thể sử dụng một trong những điều sau đây để có danh sách các con trỏ tới các phần tử của QMenuBar:

QMenuBar::actions(); 

hoặc

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

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

Khi tôi sử dụng QMenuBar::findChildren<QAction*>() hoặc MenuBar::actions() tôi nhận được một danh sách các menu trong thanh menu, ý tôi là, tôi đã "File, Edit, Help" từ QMenuBar tôi, kích thước của QList trong trường hợp này là 3.

Khi tôi sử dụng QMenuBar::findChildren<QObject*>() Tôi nhận được một danh sách QObject có kích thước 6, đó là số lượng đúng các mục trong thanh trình đơn. Tuy nhiên, tôi đã tryied đúc để QAction *

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

Trong mọi trường hợp này a không phải là NULL, nhưng khi tôi cố gắng để có được tên hành động QAction::title() nó luôn gây cho tôi Segmentation Fault.

Tôi đã tìm kiếm và tìm thấy here rằng sau khi nhận danh sách tác vụ thanh thực đơn, người dùng có thể yêu cầu QAction::menu() (trả về một con trỏ QMenu hợp lệ nếu mục đó là menu) để biết mục đó có phải là QMenu hay không , người ta có thể lặp lại nhận danh sách hành động của trình đơn đó và tiếp tục lặp lại. Nhưng điều này không làm việc cho tôi, tôi mong rằng cho

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

mỗi phần tử "File, Edit Trợ giúp" QAction::menu() trả về một con trỏ đơn hợp lệ, vì vậy tôi có thể nhận được danh sách các hành động của từng đơn, nhưng điều này không không làm việc cho tôi.

Tôi thực sự đánh giá cao thời gian và sự giúp đỡ của bạn, tôi hy vọng câu hỏi này sẽ giúp nhiều người hơn. Tôi thực sự gặp khó khăn với điều này.

Xin cảm ơn trước.

+0

Tôi không chắc chắn về phần kết thúc của câu hỏi của bạn. 'QList list = menuBar() -> findChildren ();' trả về một danh sách hợp lệ của 'QMenu *' s mà bạn có thể lặp lại bằng cách sử dụng một hàm đệ quy, và bạn có thể nhận các hành động '->()' của chúng. Điều gì không hiệu quả với bạn? – Hossein

Trả lời

0

Lý do qobject_cast bị lỗi là chỉ có ba QActions với QMenuBar làm cha mẹ. Ba phần còn lại là các QObject khác nhau (tôi đoán là ba QMenus), do đó diễn viên thất bại. Các QActions được liên kết với các trình đơn đó sau đó sẽ nằm trong các trình đơn đó, không phải là QMenuBar gốc. Tôi không thấy lý do tại sao bạn không thể xây dựng một danh sách tổng thể của QActions bằng cách đệ quy lặp qua QMenus.

Bạn có thể có thể chỉ sử dụng con trỏ QAction từ định nghĩa giao diện người dùng của bạn nếu bạn sau một menu đã biết, có thể không kích hoạt menu cha. Nếu bạn đang cố gắng để tự động kiểm tra, kích hoạt() trên QAction mong muốn của bạn có lẽ là chi tiết như bạn cần. Nếu bạn đang cố gắng làm mọi thứ để đáp lại hành động của người dùng, việc sửa đổi thanh công cụ có lẽ là phương tiện phản hồi theo ngữ cảnh tốt hơn, vì nó không làm mất tập trung. Một số chi tiết khác về những gì bạn đang thực sự cố gắng thực hiện sẽ giúp ích.

6

Dưới đây là cách lặp qua tất cả các mục menu trong thanh trình đơn, nó cũng sẽ tìm kiếm bất kỳ menu bên dưới để không cần phải gọi đệ quy ở đây.

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

Như bạn thấy, bạn có thể kết nối một khe tổng thể để xử lý các sự kiện khác nhau một hành động có thể đưa lên (tôi chỉ cho thấy kích hoạt ở đây nhưng bạn sẽ có được ý tưởng). Hy vọng điều này sẽ giúp .. một người nào đó ..

Ghi chú Tôi đã sử dụng QActionGroup cho mục đích ví dụ về sử dụng danh sách bạn có thể lặp lại, nhưng bạn thực sự không nên sử dụng trừ khi bạn đang xử lý nhóm radio. Thứ hai, nếu bạn muốn các hành động vì bạn có kế hoạch liên kết chúng thành một phương thức duy nhất để xử lý tất cả các mục, tôi khuyên bạn nên sử dụng tín hiệu kích hoạt/lơ lửng của QMenu hoặc nếu bạn cần biết khi nào menu sắp bật lên, bạn sẽ cần Tín hiệu aboutToShow() của QMenuBar. Tôi không thể nghĩ ra một lý do (đối với tôi dù sao) rằng bạn không thể làm những gì bạn cần trong những tín hiệu kể từ khi bạn được thông qua QAction * trong khe. Nhưng nếu bạn PHẢI làm điều đó theo cách khác, bạn có thể làm theo cách tôi đã trình bày ở trên, bạn có thể không muốn sử dụng QActionGroup vì nhóm radio là những gì nó được thiết kế cho. (bạn có thể làm việc xung quanh điều đó bằng cách không thêm các mục có thể 'kiểm tra' vào nhóm.

8

Cách chính xác để liệt kê QMenu là sử dụng các chức năng actions(), nhưng có một số hoạt động và họ cần phải được lặp đệ quy Trong thực tế, mỗi QMenu được liên kết với một QAction, và cả hai đều giữ con trỏ với nhau -. thấy QMenu::menuAction()QAction::menu()

Điều quan trọng là phải hiểu rằng mỗi QMenu cũng được liên kết với một. Vì vậy, biết rằng, việc triển khai thích hợp là như sau:

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

Cảm ơn bạn đã trả lời. rất hữu ích. – PeerPandit

0

này đặt nó tất cả cùng nhau:

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

sau đó trong chính bạn:

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

    bar.iterate(CMenuLogger()); 
} 
Các vấn đề liên quan