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