Qt开发过程中,弹出菜单时我们一般使用QMenu,但是QMenu都是一条项固定的格式,如查想要自己的设计界面就没法使用默认的Action项了,因此我们得用自定义的QMenu。
本篇介绍使用自定义的QMenu设计出UI。我们使用QWidget + QWidgetAction来实现。QWidgetAction继承自QAction,无法通过继承来实现一个界面,但它提供了setDefaultWidget来绑定一个界面,使用起来就更加方便了。
首先创建一个PlayWidget带UI的类,里面添加两个按钮,然后把这个类嵌进QWidgetAction中。代码如下:
#ifndef PLAYWIDGET_H
#define PLAYWIDGET_H#include <QWidget>namespace Ui {
class PlayWidget;
}class PlayWidget : public QWidget
{Q_OBJECTpublic: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 <QWidget>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 <QGraphicsDropShadowEffect>
#include <QPainter>
#include <QtMath>
#include <QStyleOption>
#include <QBitmap>
#include <QApplication>
#include <QStringListModel>
#include <QVBoxLayout>
#include <QDebug>
#include <QListView>
#include <QLineEdit>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);//设置边框为圆角12pxpainter.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 <QMainWindow>
#include "provincewidget.h"class QMenu;QT_BEGIN_NAMESPACE
namespace Ui { class CustomMenu; }
QT_END_NAMESPACEclass CustomMenu : public QMainWindow
{Q_OBJECTpublic: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 <QWidgetAction>
#include <QMenu>
#include <QSlider>
#include <QHBoxLayout>
#include <QDebug>
#include <QLineEdit>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 <QApplication>
#include <QFont>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