我必须在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());
}
任何关于如何改进这个解决方案的意见都是值得赞赏的!