Qt开发过程中,弹出菜单时我们一般使用QMenu,但是QMenu都是一条项固定的格式,如查想要自己的设计界面就没法使用默认的Action项了,因此我们得用自定义的QMenu。
本篇介绍使用自定义的QMenu设计出UI。我们使用QWidget + QWidgetAction来实现。QWidgetAction继承自QAction,无法通过继承来实现一个界面,但它提供了setDefaultWidget来绑定一个界面,使用起来就更加方便了。
首先创建一个PlayWidget带UI的类,里面添加两个按钮,然后把这个类嵌进QWidgetAction中。代码如下:
- #ifndef PLAYWIDGET_H
- #define PLAYWIDGET_H
-
- #include
-
- namespace Ui {
- class PlayWidget;
- }
-
- class PlayWidget : public QWidget
- {
- Q_OBJECT
-
- public:
- explicit PlayWidget(QWidget *parent = nullptr);
- ~PlayWidget();
-
- private:
- Ui::PlayWidget *ui;
- };
-
- #endif // PLAYWIDGET_H
- #include "playwidget.h"
- #include "ui_playwidget.h"
-
- PlayWidget::PlayWidget(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::PlayWidget)
- {
- ui->setupUi(this);
- }
-
- PlayWidget::~PlayWidget()
- {
- delete ui;
- }
- void CustomMenu::initData()
- {
- QString strLineEditStyle = QString("QLineEdit{background-color:#E9E9EA;color:#6D6E6B;border-radius:8px;}"
- "QLineEdit:hover{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
- "QLineEdit:focus{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
- "QLineEdit:disabled{background-color:#F0F0F0;border-radius:8px;}");
- QFont font = qApp->font();
- font.setPixelSize(12);
-
-
- QLineEdit *pLineEdit = new QLineEdit(this);
- pLineEdit->setFont(font);
- pLineEdit->setMaximumSize(QSize(86, 24));
- pLineEdit->setMinimumSize(QSize(86, 24));
- pLineEdit->setStyleSheet(strLineEditStyle);
- //播放项
- QWidgetAction *pWdtAction = new QWidgetAction(this);
- //播放项界面,继承自QWidget的类
- PlayWidget *playWdt = new PlayWidget(this);
- playWdt->setMinimumSize(QSize(200, 50));
- pWdtAction->setDefaultWidget(playWdt);
-
- //创建一个包含声音调整控件的界面项
- QWidgetAction *pVoice = new QWidgetAction(this);
- QWidget *pVoiceWdt = new QWidget(this);
- QSlider *pSlider = new QSlider(Qt::Horizontal);
- QHBoxLayout *layout = new QHBoxLayout(pVoiceWdt);
- layout->addWidget(pSlider);
- layout->addWidget(pLineEdit);
- pVoiceWdt->setLayout(layout);
- pVoice->setDefaultWidget(pVoiceWdt);
- //生成菜单栏
- if(m_menu == nullptr) {
- m_menu = new QMenu(this);
- m_menu->addAction(pWdtAction);
- m_menu->addSeparator();
- m_menu->addAction(pVoice);
- m_menu->addAction(QStringLiteral("显示歌词"));
- m_menu->addAction(QStringLiteral("锁定歌词"));
-
- m_menu->addSeparator();
- m_menu->addAction(QStringLiteral("选项设置"));
- m_menu->addSeparator();
- m_menu->addAction(QStringLiteral("登陆"));
- m_menu->addAction(QStringLiteral("退出"));
- }
- }
-
- void CustomMenu::initConnect()
- {
- connect(ui->btnCreateMenu, SIGNAL(clicked()), this, SLOT(slotCreateMenu()));
- }
-
-
- void CustomMenu::slotCreateMenu()
- {
- QPoint point = ui->btnCreateMenu->pos();
- point.setY(point.y() + 50);
- m_menu->popup(this->mapToGlobal(point));
- //ui->btnCreateMenu->setMenu(m_menu);
-
- }
运行效果
这是使用QMenu的方式,还有一个直接使用QWidget的方式,把属性设置为
setWindowFlags(Qt::FramelessWindowHint|Qt::Popup);
这样弹出菜单后,点击其他地方会自动关闭此Widget,达到与弹出菜单一样的效果。
完整代码如下:
- #ifndef PROVINCEWIDGET_H
- #define PROVINCEWIDGET_H
-
- #include
-
- class QLineEdit;
- class QListView;
-
- class ProvinceWidget : public QWidget
- {
- Q_OBJECT
- public:
- explicit ProvinceWidget(QWidget *parent = nullptr);
-
- void initView();
- void initConnect();
- void setClearFocus();
-
- signals:
- void signalChangeScale(int scale);
-
- protected:
- void paintEvent(QPaintEvent *event) override;
-
- public slots:
- void slotReturnPressed();
- void slotEditingFinished();
- void slotClicked(const QModelIndex &index);
-
- private:
- QListView *m_listView;
- QLineEdit *m_lineEdit;
-
-
- };
-
- #endif // PROVINCEWIDGET_H
- #include "provincewidget.h"
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- ProvinceWidget::ProvinceWidget(QWidget *parent)
- : QWidget{parent}
- ,m_listView(new QListView(this))
- ,m_lineEdit(new QLineEdit(this))
- {
- setWindowFlags(Qt::FramelessWindowHint|Qt::Popup);
- initView();
- initConnect();
- }
-
- void ProvinceWidget::initView()
- {
- QString strLineEditStyle = QString("QLineEdit{background-color:#E9E9EA;color:#6D6E6B;padding-left:20px;border-radius:8px;}"
- "QLineEdit:hover{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
- "QLineEdit:focus{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
- "QLineEdit:disabled{background-color:#F0F0F0;border-radius:8px;}");
- QFont font = qApp->font();
- font.setPixelSize(14);
- m_lineEdit->setFont(font);
- m_lineEdit->setMaximumSize(QSize(108, 24));
- m_lineEdit->setMinimumSize(QSize(108, 24));
- m_lineEdit->setStyleSheet(strLineEditStyle);
-
-
- // 使用QListView显示一个简单的列表
- QStringListModel* model = new QStringListModel();
- model->setStringList({QStringLiteral("广东"), QStringLiteral("广西"), QStringLiteral("海南"),QStringLiteral("云南"), QStringLiteral("浙江"), QStringLiteral("江西"),QStringLiteral("北京"), QStringLiteral("黑龙江")});
-
- m_listView->setModel(model);
- //margin item离外边框的间距 padding 内容与item项的边框
- QString listViewStyle = QString("QListView{color:#6D6E6B; background-color:white;border:none;outline:none;}"
- "QListView::item{height:24px;background:gray;margin-top:3px; margin-right:10px;margin-bottom:4px; margin-left:10px;padding-left:20px;padding-right:10px;color:#333333;border:none;outline:none;}"
- "QListView::item:hover{background:#2F89FC;color:#ffffff;border-radius:4px;border:none;outline:none;}"
- "QListView::item:selected{background:white;color:#ff0000;border:none;outline:none;}"
- "QListView::item:selected:!active{background:white;color:#00ff00;border:none;outline:none;}"
- "QListView::item:selected:active{background:white;color:#0000ff;border:none;outline:none;}");
-
- QString listViewStyle2 = QString("QListView{color:#6D6E6B; background-color:white;border:none;outline:none;}"
- "QListView::item{height:24px;background:white;margin-top:3px; margin-right:10px;margin-bottom:4px; margin-left:10px;padding-left:20px;padding-right:10px;color:#333333;border:none;outline:none;}"
- "QListView::item:hover{background:#2F89FC;color:#ffffff;border-radius:4px;border:none;outline:none;}"
- "QListView::item:selected{background:white;color:#ff0000;border:none;outline:none;}"
- "QListView::item:selected:!active{background:white;color:#00ff00;border:none;outline:none;}"
- "QListView::item:selected:active{background:white;color:#0000ff;border:none;outline:none;}");
-
- m_listView->setStyleSheet(listViewStyle2);
-
- QVBoxLayout *layout = new QVBoxLayout();
- layout->setContentsMargins(0, 1, 0, 0);
- layout->setSpacing(1);
- layout->addWidget(m_listView);
- layout->addWidget(m_lineEdit);
- setLayout(layout);
- }
-
- void ProvinceWidget::initConnect()
- {
- connect(m_lineEdit, SIGNAL(returnPressed()), this, SLOT(slotReturnPressed()));
- connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(slotEditingFinished()));
- connect(m_listView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(slotClicked(const QModelIndex &)));
- }
-
- void ProvinceWidget::setClearFocus()
- {
- m_listView->clearFocus();
- m_listView->clearSelection();
- m_lineEdit->clearFocus();
- }
-
-
- void ProvinceWidget::paintEvent(QPaintEvent *event)
- {
- Q_UNUSED(event);
- // QPainterPath path;
- // path.setFillRule(Qt::WindingFill);
- // path.addRoundedRect(5, 5, this->width() - 5 * 2, this->height() - 5 * 2, 3, 3);
- // painter.fillPath(path, QBrush(Qt::red));
-
- //绘制样式
- QStyleOption opt;
- opt.initFrom(this);
- QPainter p(this);
- style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);//绘制样式
- QBitmap bmp(this->size());
- bmp.fill();
- QPainter painter(&bmp);
- painter.setPen(Qt::NoPen);
- painter.setBrush(Qt::black);
- painter.setRenderHint(QPainter::Antialiasing);
- //设置边框为圆角12px
- painter.drawRoundedRect(bmp.rect(), 8, 8);
- setMask(bmp);
-
- //再画颜色块
- QRect tmpRect = QRect(0, 0, this->width(), this->height());
- QBrush brush = QBrush(QColor("#ffffff"));
- p.setPen(Qt::NoPen); //去掉边框线
- p.setBrush(brush);
- p.drawRect(tmpRect);
-
-
-
- // QColor color(Qt::gray);
- // for (int i = 0; i < 5; i++)
- // {
- // QPainterPath path;
- // path.setFillRule(Qt::WindingFill);
- // path.addRoundedRect(5 - i, 5 - i, this->width() - (5 - i) * 2, this->height() - (5 - i) * 2, 3 + i, 3 + i);
- // color.setAlpha(80 - qSqrt(i) * 40);
- // painter.setPen(color);
- // painter.drawPath(path);
- // }
-
- }
-
- void ProvinceWidget::slotReturnPressed()
- {
- int scale = m_lineEdit->text().toInt();
- qDebug() << "slotReturnPressed===========================" << scale;
- emit signalChangeScale(scale);
- }
-
- void ProvinceWidget::slotEditingFinished()
- {
- int scale = m_lineEdit->text().toInt();
- qDebug() << "slotEditingFinished===========================" << scale;
- }
-
- void ProvinceWidget::slotClicked(const QModelIndex &index)
- {
- QString data = index.data().toString();
- int scale = data.left(data.size() - 1).toInt();
- qDebug() << "PopupScaleList::slotClicked==========data======" << data << data.size() << scale;
- emit signalChangeScale(scale);
- }
- #ifndef CUSTOMMENU_H
- #define CUSTOMMENU_H
-
- #include
- #include "provincewidget.h"
-
- class QMenu;
-
- QT_BEGIN_NAMESPACE
- namespace Ui { class CustomMenu; }
- QT_END_NAMESPACE
-
- class CustomMenu : public QMainWindow
- {
- Q_OBJECT
-
- public:
- CustomMenu(QWidget *parent = nullptr);
- ~CustomMenu();
-
- void initData();
- void initConnect();
-
- public slots:
- void slotCreateMenu();
- void slotPopupMenu();
- void slotTriggered(QAction *action);
-
- private:
- Ui::CustomMenu *ui;
- ProvinceWidget *provinceWidget{nullptr};
- QMenu *m_menu{nullptr};
-
- };
- #endif // CUSTOMMENU_H
- #include "custommenu.h"
- #include "ui_custommenu.h"
- #include "playwidget.h"
- #include
- #include
- #include
- #include
- #include
- #include
-
- CustomMenu::CustomMenu(QWidget *parent)
- : QMainWindow(parent)
- , ui(new Ui::CustomMenu)
- {
- ui->setupUi(this);
-
- initData();
- initConnect();
- }
-
- CustomMenu::~CustomMenu()
- {
- delete ui;
- }
-
-
-
- void CustomMenu::initData()
- {
-
- provinceWidget = new ProvinceWidget(this);
- provinceWidget->setObjectName(QString::fromUtf8("provinceWidget"));
- provinceWidget->setMinimumSize(QSize(108, 280));
- provinceWidget->setMaximumSize(QSize(108, 280));
-
- QString strLineEditStyle = QString("QLineEdit{background-color:#E9E9EA;color:#6D6E6B;border-radius:8px;}"
- "QLineEdit:hover{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
- "QLineEdit:focus{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
- "QLineEdit:disabled{background-color:#F0F0F0;border-radius:8px;}");
- QFont font = qApp->font();
- font.setPixelSize(12);
-
-
- QLineEdit *pLineEdit = new QLineEdit(this);
- pLineEdit->setFont(font);
- pLineEdit->setMaximumSize(QSize(86, 24));
- pLineEdit->setMinimumSize(QSize(86, 24));
- pLineEdit->setStyleSheet(strLineEditStyle);
- //播放项
- QWidgetAction *pWdtAction = new QWidgetAction(this);
- //播放项界面,继承自QWidget的类
- PlayWidget *playWdt = new PlayWidget(this);
- playWdt->setMinimumSize(QSize(200, 50));
- pWdtAction->setDefaultWidget(playWdt);
-
- //创建一个包含声音调整控件的界面项
- QWidgetAction *pVoice = new QWidgetAction(this);
- QWidget *pVoiceWdt = new QWidget(this);
- QSlider *pSlider = new QSlider(Qt::Horizontal);
- QHBoxLayout *layout = new QHBoxLayout(pVoiceWdt);
- layout->addWidget(pSlider);
- layout->addWidget(pLineEdit);
- pVoiceWdt->setLayout(layout);
- pVoice->setDefaultWidget(pVoiceWdt);
- //生成菜单栏
- if(m_menu == nullptr) {
- m_menu = new QMenu(this);
- m_menu->addAction(pWdtAction);
- m_menu->addSeparator();
- m_menu->addAction(pVoice);
- m_menu->addAction(QStringLiteral("显示歌词"));
- m_menu->addAction(QStringLiteral("锁定歌词"));
-
- m_menu->addSeparator();
- m_menu->addAction(QStringLiteral("选项设置"));
- m_menu->addSeparator();
- m_menu->addAction(QStringLiteral("登陆"));
- m_menu->addAction(QStringLiteral("退出"));
- }
- }
-
- void CustomMenu::initConnect()
- {
- connect(ui->btnCreateMenu, SIGNAL(clicked()), this, SLOT(slotCreateMenu()));
- connect(ui->btnPopupMenu, SIGNAL(clicked()), this, SLOT(slotPopupMenu()));
- connect(m_menu, SIGNAL(triggered(QAction *)), this, SLOT(slotTriggered(QAction *)));
- }
-
-
- void CustomMenu::slotCreateMenu()
- {
- QPoint point = ui->btnCreateMenu->pos();
- point.setY(point.y() + 50);
- m_menu->popup(this->mapToGlobal(point));
- //ui->btnCreateMenu->setMenu(m_menu);
-
- }
-
- void CustomMenu::slotPopupMenu()
- {
- QPoint point = ui->btnPopupMenu->pos();
- point.setY(point.y() + 50);
- QPoint mapPoint = mapToGlobal(point);
- provinceWidget->setClearFocus();
- provinceWidget->move(mapPoint);
- provinceWidget->show();
- }
-
- void CustomMenu::slotTriggered(QAction *action)
- {
- qDebug() << "slotCreateMenu====================" << action->text();
- }
-
- #include "custommenu.h"
-
- #include
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- QFont defaultFont = qApp->font();
- defaultFont.setFamily("Microsoft YaHei");
- qApp->setFont(defaultFont);
- CustomMenu w;
- w.show();
- return a.exec();
- }
运行效果:
参考:
https://www.cnblogs.com/lingluotianya/p/3789245.html
https://blog.csdn.net/yyz_1987/article/details/130986313