2016-11-16 68 views
0

我必须在QMenu中存储许多物品。如果物品太多QMenu包装它们并开始一个新的列,但只有当这些项目不适合屏幕高度时才会发生。是否有可能在QMenu中有“包装”行为?

我想有QMenu,当菜单高度达到,例如,父窗口小部件的高度或任何其他自定义值时,它包装项目。

我无法在QMenu中找到任何用于实现此目的的属性。设置maximumHeight没有给出结果。挖掘到QMenu来源后,我发现“包装逻辑”基于popupGeometry方法结果工作。但popupGeometry使用屏幕大小,它是私人的,所以我不知道改变它的方法。

回答

0

由于我没有找到答案,我必须自己实施这个控制。 这是一个弹出窗口小部件,使用QToolButton作为所有者。它可以根据项目的高度和所需的菜单高度将项目排列在网格中。

class myLabel:public QLabel 
{ 
    Q_OBJECT 
    // QObject interface 
public: 
    myLabel(QWidget* parent=0):QLabel(parent){} 
    bool event(QEvent *e) 
    { 
     if(e->type()==QEvent::MouseButtonPress) 
      emit clicked(); 
     return QLabel::event(e); 
    } 
    void setAction(QAction *a) 
    { 
     setText(a->text()); 
     _action=a; 
    } 
    QAction* action() 
    { 
     return _action; 
    } 
signals: 
    void clicked(); 
private: 
    QAction* _action; 
}; 

class myMenu: public QWidget 
{ 
    Q_OBJECT 
public: 
    myMenu(QWidget* owner,QWidget* parent=0):QWidget(parent){ 
     this->setWindowFlags(Qt::Popup); 
     l = new QGridLayout(this); 
     l->setContentsMargins(QMargins(3,3,3,3)); 
     _owner=owner; 
     QString style="QLabel:hover{background-color: white;} "; 
     setStyleSheet(style); 
    } 
    void addAction(QAction*a){_actions.append(a);} 
    QVector<QAction*> actions(){return _actions;} 
    void setItemHeight(int val){_itemHeight=val;} 
    void setHeight(int val){_height=val;} 
private: 
    QVector<QAction*> _actions; 
    QGridLayout *l ; 
    QWidget*_owner; 
    int _itemHeight=30; 
    int _height=200; 
private slots: 
    void popup() 
    { 
     clear(); 
     //move popup under toolbutton 
     QPoint p = _owner->geometry().bottomLeft(); 
     p.setY(p.y()+1); 
     this->move(_owner->parentWidget()->mapToGlobal(p)); 
     //calculate rows count 
     int rows = _height/_itemHeight; 
     //calculate cols count 
     int cols = _actions.size()/rows; 
     int d = _actions.size()%rows; 
     if(d>0) 
      cols++; 
     for(int i=0;i<rows;i++) 
      for(int j=0;j<cols;j++) 
      { 
       int index = i+j*rows; 
       if(index<_actions.size()) 
       { 
        myLabel *lb = new myLabel(this); 
        connect(lb,SIGNAL(clicked()),this,SLOT(onClick())); 
        lb->setFixedHeight(_itemHeight); 
        lb->setAction(_actions[index]); 
        l->addWidget(lb,i,j); 
       } 
      } 
     this->repaint(); 
     this->show(); 
    } 
    void clear() 
    { 
     while(l->itemAt(0)!=NULL) 
     { 
      QLayoutItem* i = l->takeAt(0); 
      if(i->widget()) 
       delete i->widget(); 
      if(i->layout()) 
       delete i->layout(); 
      delete i; 
     } 
    } 
    void onClick() 
    { 
     myLabel *g = qobject_cast<myLabel*>(sender()); 
     g->action()->trigger(); 
     close(); 
    } 
    // QWidget interface 
protected: 
    void closeEvent(QCloseEvent *) 
    { 
     qobject_cast<QToolButton*>(_owner)->setDown(false); 
    } 
signals: 
    void closed(); 
}; 

还有一个示例显示如何创建并填写myMenu以及如何接收选定的操作。

MainWindow::MainWindow(QWidget *parent) : 
QMainWindow(parent), 
ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 
    //set-up myMenu, btMyMenu is a QToolButton 
    myMenu *mMenu = new myMenu(ui->btMyMenu,this); 
    connect(ui->btMyMenu,SIGNAL(pressed()),mMenu,SLOT(popup())); 
    for(int i=0;i<20;i++) 
    { 
     QAction *a = new QAction("Action "+QString::number(i),this); 
     connect(a,SIGNAL(triggered(bool)),this,SLOT(onActSelected())); 
     mMenu->addAction(a); 
    } 
    //mMenu can be customized 
    mMenu->setHeight(100); 
    mMenu->setItemHeight(50); 
} 

void MainWindow::onActSelected() 
{ 
    QAction *a = qobject_cast<QAction*>(sender()); 
    ui->btMyMenu->setText(a->text()); 
} 

有关如何改进此解决方案的任何意见,我们将不胜感激!

+0

是否有原因不从QMenu派生并专门化? – Hayt

+0

@Hayt Um ..好吧,我不知道子类QMenu如何帮助我...你有什么想法吗? – lena

+0

不是真的,我只是会以为你使用QMenu已有的功能,而不是自己重新实现它。 QMenu中保护的列数或大小提示的功能可以被覆盖。我只是认为你已经尝试过并决定反对它。不知道你甚至没有想过。 – Hayt