• Qt自定义菜单


     Qt开发过程中,弹出菜单时我们一般使用QMenu,但是QMenu都是一条项固定的格式,如查想要自己的设计界面就没法使用默认的Action项了,因此我们得用自定义的QMenu。

    本篇介绍使用自定义的QMenu设计出UI。我们使用QWidget + QWidgetAction来实现。QWidgetAction继承自QAction,无法通过继承来实现一个界面,但它提供了setDefaultWidget来绑定一个界面,使用起来就更加方便了。

    首先创建一个PlayWidget带UI的类,里面添加两个按钮,然后把这个类嵌进QWidgetAction中。代码如下:

    1. #ifndef PLAYWIDGET_H
    2. #define PLAYWIDGET_H
    3. #include
    4. namespace Ui {
    5. class PlayWidget;
    6. }
    7. class PlayWidget : public QWidget
    8. {
    9. Q_OBJECT
    10. public:
    11. explicit PlayWidget(QWidget *parent = nullptr);
    12. ~PlayWidget();
    13. private:
    14. Ui::PlayWidget *ui;
    15. };
    16. #endif // PLAYWIDGET_H

    1. #include "playwidget.h"
    2. #include "ui_playwidget.h"
    3. PlayWidget::PlayWidget(QWidget *parent) :
    4. QWidget(parent),
    5. ui(new Ui::PlayWidget)
    6. {
    7. ui->setupUi(this);
    8. }
    9. PlayWidget::~PlayWidget()
    10. {
    11. delete ui;
    12. }
    1. void CustomMenu::initData()
    2. {
    3. QString strLineEditStyle = QString("QLineEdit{background-color:#E9E9EA;color:#6D6E6B;border-radius:8px;}"
    4. "QLineEdit:hover{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
    5. "QLineEdit:focus{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
    6. "QLineEdit:disabled{background-color:#F0F0F0;border-radius:8px;}");
    7. QFont font = qApp->font();
    8. font.setPixelSize(12);
    9. QLineEdit *pLineEdit = new QLineEdit(this);
    10. pLineEdit->setFont(font);
    11. pLineEdit->setMaximumSize(QSize(86, 24));
    12. pLineEdit->setMinimumSize(QSize(86, 24));
    13. pLineEdit->setStyleSheet(strLineEditStyle);
    14. //播放项
    15. QWidgetAction *pWdtAction = new QWidgetAction(this);
    16. //播放项界面,继承自QWidget的类
    17. PlayWidget *playWdt = new PlayWidget(this);
    18. playWdt->setMinimumSize(QSize(200, 50));
    19. pWdtAction->setDefaultWidget(playWdt);
    20. //创建一个包含声音调整控件的界面项
    21. QWidgetAction *pVoice = new QWidgetAction(this);
    22. QWidget *pVoiceWdt = new QWidget(this);
    23. QSlider *pSlider = new QSlider(Qt::Horizontal);
    24. QHBoxLayout *layout = new QHBoxLayout(pVoiceWdt);
    25. layout->addWidget(pSlider);
    26. layout->addWidget(pLineEdit);
    27. pVoiceWdt->setLayout(layout);
    28. pVoice->setDefaultWidget(pVoiceWdt);
    29. //生成菜单栏
    30. if(m_menu == nullptr) {
    31. m_menu = new QMenu(this);
    32. m_menu->addAction(pWdtAction);
    33. m_menu->addSeparator();
    34. m_menu->addAction(pVoice);
    35. m_menu->addAction(QStringLiteral("显示歌词"));
    36. m_menu->addAction(QStringLiteral("锁定歌词"));
    37. m_menu->addSeparator();
    38. m_menu->addAction(QStringLiteral("选项设置"));
    39. m_menu->addSeparator();
    40. m_menu->addAction(QStringLiteral("登陆"));
    41. m_menu->addAction(QStringLiteral("退出"));
    42. }
    43. }
    44. void CustomMenu::initConnect()
    45. {
    46. connect(ui->btnCreateMenu, SIGNAL(clicked()), this, SLOT(slotCreateMenu()));
    47. }
    48. void CustomMenu::slotCreateMenu()
    49. {
    50. QPoint point = ui->btnCreateMenu->pos();
    51. point.setY(point.y() + 50);
    52. m_menu->popup(this->mapToGlobal(point));
    53. //ui->btnCreateMenu->setMenu(m_menu);
    54. }

     运行效果

    这是使用QMenu的方式,还有一个直接使用QWidget的方式,把属性设置为

    setWindowFlags(Qt::FramelessWindowHint|Qt::Popup);

    这样弹出菜单后,点击其他地方会自动关闭此Widget,达到与弹出菜单一样的效果。

    完整代码如下:

    1. #ifndef PROVINCEWIDGET_H
    2. #define PROVINCEWIDGET_H
    3. #include
    4. class QLineEdit;
    5. class QListView;
    6. class ProvinceWidget : public QWidget
    7. {
    8. Q_OBJECT
    9. public:
    10. explicit ProvinceWidget(QWidget *parent = nullptr);
    11. void initView();
    12. void initConnect();
    13. void setClearFocus();
    14. signals:
    15. void signalChangeScale(int scale);
    16. protected:
    17. void paintEvent(QPaintEvent *event) override;
    18. public slots:
    19. void slotReturnPressed();
    20. void slotEditingFinished();
    21. void slotClicked(const QModelIndex &index);
    22. private:
    23. QListView *m_listView;
    24. QLineEdit *m_lineEdit;
    25. };
    26. #endif // PROVINCEWIDGET_H

    1. #include "provincewidget.h"
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. ProvinceWidget::ProvinceWidget(QWidget *parent)
    14. : QWidget{parent}
    15. ,m_listView(new QListView(this))
    16. ,m_lineEdit(new QLineEdit(this))
    17. {
    18. setWindowFlags(Qt::FramelessWindowHint|Qt::Popup);
    19. initView();
    20. initConnect();
    21. }
    22. void ProvinceWidget::initView()
    23. {
    24. QString strLineEditStyle = QString("QLineEdit{background-color:#E9E9EA;color:#6D6E6B;padding-left:20px;border-radius:8px;}"
    25. "QLineEdit:hover{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
    26. "QLineEdit:focus{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
    27. "QLineEdit:disabled{background-color:#F0F0F0;border-radius:8px;}");
    28. QFont font = qApp->font();
    29. font.setPixelSize(14);
    30. m_lineEdit->setFont(font);
    31. m_lineEdit->setMaximumSize(QSize(108, 24));
    32. m_lineEdit->setMinimumSize(QSize(108, 24));
    33. m_lineEdit->setStyleSheet(strLineEditStyle);
    34. // 使用QListView显示一个简单的列表
    35. QStringListModel* model = new QStringListModel();
    36. model->setStringList({QStringLiteral("广东"), QStringLiteral("广西"), QStringLiteral("海南"),QStringLiteral("云南"), QStringLiteral("浙江"), QStringLiteral("江西"),QStringLiteral("北京"), QStringLiteral("黑龙江")});
    37. m_listView->setModel(model);
    38. //margin item离外边框的间距 padding 内容与item项的边框
    39. QString listViewStyle = QString("QListView{color:#6D6E6B; background-color:white;border:none;outline:none;}"
    40. "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;}"
    41. "QListView::item:hover{background:#2F89FC;color:#ffffff;border-radius:4px;border:none;outline:none;}"
    42. "QListView::item:selected{background:white;color:#ff0000;border:none;outline:none;}"
    43. "QListView::item:selected:!active{background:white;color:#00ff00;border:none;outline:none;}"
    44. "QListView::item:selected:active{background:white;color:#0000ff;border:none;outline:none;}");
    45. QString listViewStyle2 = QString("QListView{color:#6D6E6B; background-color:white;border:none;outline:none;}"
    46. "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;}"
    47. "QListView::item:hover{background:#2F89FC;color:#ffffff;border-radius:4px;border:none;outline:none;}"
    48. "QListView::item:selected{background:white;color:#ff0000;border:none;outline:none;}"
    49. "QListView::item:selected:!active{background:white;color:#00ff00;border:none;outline:none;}"
    50. "QListView::item:selected:active{background:white;color:#0000ff;border:none;outline:none;}");
    51. m_listView->setStyleSheet(listViewStyle2);
    52. QVBoxLayout *layout = new QVBoxLayout();
    53. layout->setContentsMargins(0, 1, 0, 0);
    54. layout->setSpacing(1);
    55. layout->addWidget(m_listView);
    56. layout->addWidget(m_lineEdit);
    57. setLayout(layout);
    58. }
    59. void ProvinceWidget::initConnect()
    60. {
    61. connect(m_lineEdit, SIGNAL(returnPressed()), this, SLOT(slotReturnPressed()));
    62. connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(slotEditingFinished()));
    63. connect(m_listView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(slotClicked(const QModelIndex &)));
    64. }
    65. void ProvinceWidget::setClearFocus()
    66. {
    67. m_listView->clearFocus();
    68. m_listView->clearSelection();
    69. m_lineEdit->clearFocus();
    70. }
    71. void ProvinceWidget::paintEvent(QPaintEvent *event)
    72. {
    73. Q_UNUSED(event);
    74. // QPainterPath path;
    75. // path.setFillRule(Qt::WindingFill);
    76. // path.addRoundedRect(5, 5, this->width() - 5 * 2, this->height() - 5 * 2, 3, 3);
    77. // painter.fillPath(path, QBrush(Qt::red));
    78. //绘制样式
    79. QStyleOption opt;
    80. opt.initFrom(this);
    81. QPainter p(this);
    82. style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);//绘制样式
    83. QBitmap bmp(this->size());
    84. bmp.fill();
    85. QPainter painter(&bmp);
    86. painter.setPen(Qt::NoPen);
    87. painter.setBrush(Qt::black);
    88. painter.setRenderHint(QPainter::Antialiasing);
    89. //设置边框为圆角12px
    90. painter.drawRoundedRect(bmp.rect(), 8, 8);
    91. setMask(bmp);
    92. //再画颜色块
    93. QRect tmpRect = QRect(0, 0, this->width(), this->height());
    94. QBrush brush = QBrush(QColor("#ffffff"));
    95. p.setPen(Qt::NoPen); //去掉边框线
    96. p.setBrush(brush);
    97. p.drawRect(tmpRect);
    98. // QColor color(Qt::gray);
    99. // for (int i = 0; i < 5; i++)
    100. // {
    101. // QPainterPath path;
    102. // path.setFillRule(Qt::WindingFill);
    103. // path.addRoundedRect(5 - i, 5 - i, this->width() - (5 - i) * 2, this->height() - (5 - i) * 2, 3 + i, 3 + i);
    104. // color.setAlpha(80 - qSqrt(i) * 40);
    105. // painter.setPen(color);
    106. // painter.drawPath(path);
    107. // }
    108. }
    109. void ProvinceWidget::slotReturnPressed()
    110. {
    111. int scale = m_lineEdit->text().toInt();
    112. qDebug() << "slotReturnPressed===========================" << scale;
    113. emit signalChangeScale(scale);
    114. }
    115. void ProvinceWidget::slotEditingFinished()
    116. {
    117. int scale = m_lineEdit->text().toInt();
    118. qDebug() << "slotEditingFinished===========================" << scale;
    119. }
    120. void ProvinceWidget::slotClicked(const QModelIndex &index)
    121. {
    122. QString data = index.data().toString();
    123. int scale = data.left(data.size() - 1).toInt();
    124. qDebug() << "PopupScaleList::slotClicked==========data======" << data << data.size() << scale;
    125. emit signalChangeScale(scale);
    126. }

    1. #ifndef CUSTOMMENU_H
    2. #define CUSTOMMENU_H
    3. #include
    4. #include "provincewidget.h"
    5. class QMenu;
    6. QT_BEGIN_NAMESPACE
    7. namespace Ui { class CustomMenu; }
    8. QT_END_NAMESPACE
    9. class CustomMenu : public QMainWindow
    10. {
    11. Q_OBJECT
    12. public:
    13. CustomMenu(QWidget *parent = nullptr);
    14. ~CustomMenu();
    15. void initData();
    16. void initConnect();
    17. public slots:
    18. void slotCreateMenu();
    19. void slotPopupMenu();
    20. void slotTriggered(QAction *action);
    21. private:
    22. Ui::CustomMenu *ui;
    23. ProvinceWidget *provinceWidget{nullptr};
    24. QMenu *m_menu{nullptr};
    25. };
    26. #endif // CUSTOMMENU_H

    1. #include "custommenu.h"
    2. #include "ui_custommenu.h"
    3. #include "playwidget.h"
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. CustomMenu::CustomMenu(QWidget *parent)
    11. : QMainWindow(parent)
    12. , ui(new Ui::CustomMenu)
    13. {
    14. ui->setupUi(this);
    15. initData();
    16. initConnect();
    17. }
    18. CustomMenu::~CustomMenu()
    19. {
    20. delete ui;
    21. }
    22. void CustomMenu::initData()
    23. {
    24. provinceWidget = new ProvinceWidget(this);
    25. provinceWidget->setObjectName(QString::fromUtf8("provinceWidget"));
    26. provinceWidget->setMinimumSize(QSize(108, 280));
    27. provinceWidget->setMaximumSize(QSize(108, 280));
    28. QString strLineEditStyle = QString("QLineEdit{background-color:#E9E9EA;color:#6D6E6B;border-radius:8px;}"
    29. "QLineEdit:hover{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
    30. "QLineEdit:focus{background-color:#E9E9EA;border-radius:8px;border:2px solid rgba(47, 137, 252, 1);}"
    31. "QLineEdit:disabled{background-color:#F0F0F0;border-radius:8px;}");
    32. QFont font = qApp->font();
    33. font.setPixelSize(12);
    34. QLineEdit *pLineEdit = new QLineEdit(this);
    35. pLineEdit->setFont(font);
    36. pLineEdit->setMaximumSize(QSize(86, 24));
    37. pLineEdit->setMinimumSize(QSize(86, 24));
    38. pLineEdit->setStyleSheet(strLineEditStyle);
    39. //播放项
    40. QWidgetAction *pWdtAction = new QWidgetAction(this);
    41. //播放项界面,继承自QWidget的类
    42. PlayWidget *playWdt = new PlayWidget(this);
    43. playWdt->setMinimumSize(QSize(200, 50));
    44. pWdtAction->setDefaultWidget(playWdt);
    45. //创建一个包含声音调整控件的界面项
    46. QWidgetAction *pVoice = new QWidgetAction(this);
    47. QWidget *pVoiceWdt = new QWidget(this);
    48. QSlider *pSlider = new QSlider(Qt::Horizontal);
    49. QHBoxLayout *layout = new QHBoxLayout(pVoiceWdt);
    50. layout->addWidget(pSlider);
    51. layout->addWidget(pLineEdit);
    52. pVoiceWdt->setLayout(layout);
    53. pVoice->setDefaultWidget(pVoiceWdt);
    54. //生成菜单栏
    55. if(m_menu == nullptr) {
    56. m_menu = new QMenu(this);
    57. m_menu->addAction(pWdtAction);
    58. m_menu->addSeparator();
    59. m_menu->addAction(pVoice);
    60. m_menu->addAction(QStringLiteral("显示歌词"));
    61. m_menu->addAction(QStringLiteral("锁定歌词"));
    62. m_menu->addSeparator();
    63. m_menu->addAction(QStringLiteral("选项设置"));
    64. m_menu->addSeparator();
    65. m_menu->addAction(QStringLiteral("登陆"));
    66. m_menu->addAction(QStringLiteral("退出"));
    67. }
    68. }
    69. void CustomMenu::initConnect()
    70. {
    71. connect(ui->btnCreateMenu, SIGNAL(clicked()), this, SLOT(slotCreateMenu()));
    72. connect(ui->btnPopupMenu, SIGNAL(clicked()), this, SLOT(slotPopupMenu()));
    73. connect(m_menu, SIGNAL(triggered(QAction *)), this, SLOT(slotTriggered(QAction *)));
    74. }
    75. void CustomMenu::slotCreateMenu()
    76. {
    77. QPoint point = ui->btnCreateMenu->pos();
    78. point.setY(point.y() + 50);
    79. m_menu->popup(this->mapToGlobal(point));
    80. //ui->btnCreateMenu->setMenu(m_menu);
    81. }
    82. void CustomMenu::slotPopupMenu()
    83. {
    84. QPoint point = ui->btnPopupMenu->pos();
    85. point.setY(point.y() + 50);
    86. QPoint mapPoint = mapToGlobal(point);
    87. provinceWidget->setClearFocus();
    88. provinceWidget->move(mapPoint);
    89. provinceWidget->show();
    90. }
    91. void CustomMenu::slotTriggered(QAction *action)
    92. {
    93. qDebug() << "slotCreateMenu====================" << action->text();
    94. }
    1. #include "custommenu.h"
    2. #include
    3. #include
    4. int main(int argc, char *argv[])
    5. {
    6. QApplication a(argc, argv);
    7. QFont defaultFont = qApp->font();
    8. defaultFont.setFamily("Microsoft YaHei");
    9. qApp->setFont(defaultFont);
    10. CustomMenu w;
    11. w.show();
    12. return a.exec();
    13. }

    运行效果:

     

    参考:

    https://www.cnblogs.com/lingluotianya/p/3789245.html
    https://blog.csdn.net/yyz_1987/article/details/130986313

  • 相关阅读:
    ThreadPoolExecutor BlockingQueue讲解
    通过minikube搭建k8s单机环境
    Rancher - 更换Linux发行版
    【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
    面试题-C++多线程打印的问题
    Spring基于Annotation装配Bean
    【JavaScript 18】属性描述对象 获取 自身全部属性名 定义or修改属性 判断可遍历性 元属性 存取器
    WebGL笔记:WebGL的基本绘图原理
    前端—— 分层模型和应用协议
    camunda_05_integrity_architect
  • 原文地址:https://blog.csdn.net/chenyijun/article/details/133386092