有可能有一个"包装" QMenu的行为?

时间:2016-11-16 15:44:09

标签: qt qmenu

我必须在QMenu中存储多个项目。如果有太多项目QMenu包装它们,则会开始一个新列,但只有当这些项目无法适应屏幕高度时才会发生。

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

我无法在QMenu找到任何属性来实现此目的。设置maximumHeight没有结果。在深入研究QMenu来源之后,我发现了"包装逻辑"基于popupGeometry方法结果工作。但popupGeometry使用的是屏幕大小,而且它是私密的,所以我不知道改变它的方法。

1 个答案:

答案 0 :(得分: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());
}

欢迎任何有关如何改进此解决方案的评论!