在QMenu中是否有可能具有"wrap"行为?



我必须在QMenu中存储许多项。如果项目太多,QMenu将它们换行并开始一个新列,但只有当这些项目无法适应屏幕高度时才会发生这种情况。

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

我无法在QMenu中找到任何属性来实现这一点。设置maximumHeight没有结果。在深入研究QMenu源代码后,我发现"包装逻辑"是基于popupGeometry方法结果工作的。但是popupGeometry使用屏幕大小,它是私人的,所以我不知道一种方法来改变它。

由于我没有找到答案,我不得不自己实现这个控件。它是一个弹出窗口小部件,使用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());
}

任何关于如何改进这个解决方案的意见都是值得赞赏的!

相关内容

  • 没有找到相关文章

最新更新