c++ - 如何在qt中像PC开始菜单一样在状态栏中创建菜单

标签 c++ qt statusbar

在我的 qt 应用程序中,我设计了带有几个图标的状态栏。在状态栏的左侧,我添加了菜单图标 (QPixmap),当我单击该图标时,我需要显示一个类似于 PC 开始菜单的菜单。我搜索了很多,但没有找到 Qwidget。

这是我的qt应用程序窗口

根据我最近的评论,我在下面添加了我编辑过的代码,因为我无法在评论部分添加代码,请提出解决方案

//Menu Button
    menuBtn->setIcon(QPixmap(":/new/prefix1/ic_menu_black.png"));
    statusBar()->addWidget(menuBtn);
    connect(menuBtn,SIGNAL(clicked(bool)),this,SLOT(showPopupMenu()));

void MainWindow::showPopupMenu(){


    QMenu qMenuStart;

    QAction qCmdStart1(QString::fromUtf8("Product Details"), &qMenuStart);
    qMenuStart.addAction(&qCmdStart1);

    QAction qCmdStart2(QString::fromUtf8("Memory Status"), &qMenuStart);
    qMenuStart.addAction(&qCmdStart2);

    QObject::connect(&qCmdStart1, &QAction::triggered,[](bool){
        qDebug() << "Product Details triggered"; }
    );
    QObject::connect(&qCmdStart2, &QAction::triggered,[](bool){
        qDebug() << "Memory Status triggered"; }
    );

    qMenuStart.exec();

    menuBtn->setMenu(&qMenuStart);

    qMenuStart.show();
    qMenuStart.popup(mapToGlobal(pos() - QPoint(0, qMenuStart.height())));

    qDebug()<<"Menu Clicked!";

}

点击菜单按钮弹出菜单

最佳答案

我采用了您的示例代码并对其进行了更改以说明我在最新评论中描述的内容:

MainWindow声明中添加一个成员变量:

QMenu *menuStart;

修改后的示例代码:

// configure start menu:
menuStart = new QMenu(menuBtn);
menuStart->addAction(QString::fromUtf8("Product Details"),
  [](bool){
    qDebug() << "Product Details triggered"; }
  );
menuStart->addAction(QString::fromUtf8("Memory Status"),
  [](bool){
    qDebug() << "Memory Status triggered"; }
  );
//Menu Button
menuBtn->setIcon(QPixmap(":/new/prefix1/ic_menu_black.png"));
menuBtn->setMenu(menuStart);
statusBar()->addWidget(menuBtn);
connect(menuBtn,SIGNAL(clicked(bool)),this,SLOT(showPopupMenu()));

注意:

我将 menuBtn 设置为 menuStart 的父级。因此,menuBtn 应在 menuStart 自行销毁时管理其销毁。

信号处理程序分别变得更短:

void MainWindow::showPopupMenu()
{
  menuStart->show(); // <-- trick to force layout of the menu before height() is called
  // position menu relative to menuBtn at popup
  menuStart->popup(
    mapToGlobal(menuBtn->pos() - QPoint(0, menuStart->height())));

  qDebug()<<"Menu Clicked!";
}

我仔细做了,但无法测试(因为它不是 MCVE)。所以,请对此持“保留态度”。

注意:

我刚刚意识到您使用“pre-Qt5”风格的连接信号处理程序。 Qt5 引入了一个不错的extension to its signals支持函数指针和方法指针。因此,我能够简单地执行信号处理程序 lambdas . (lambda 是这些 [](bool){/*...*/> 我连接到操作槽。我一直对这些新的 lambda 持怀疑态度,直到我意识到它们是一个很好的工具为信号处理程序编写非常简单的适配器以及制作非常紧凑的示例代码。)

关于 Lambdas 的更新:

方括号 [] 可用于将变量添加到 lambda 的环境(或上下文)。如果它是空的(如我所用),则只能使用全局变量和函数。使用 [this] 意味着当前的 this 指针被添加到环境中。因此,lambda 可以访问当前类实例的成员变量。

当我第一次认识 lambda 时,我经常看到 [=] 表示 lambda 获取调用函数的当前上下文(例如,每个局部函数变量的拷贝)。我个人认为这是危险的,尤其是对于信号处理程序。我将详细说明这一点:

lambda 的环境允许访问 lambda 主体中的“外部变量”。变量可以按值或按引用添加。如果一个变量是通过引用提供的,它可以在 lambda 主体中访问,但它不会保证“外部”变量的生命周期足够长。 (如果不是,它会导致“悬空引用”,具有与悬空指针相同的未定义行为。)它是否有助于完全防止引用?不。它对原始类型(例如 intfloat)没问题,但对对象来说可能效率低下(甚至语义错误)。使用指向对象的指针与使用引用一样危险。因此,应小心使用 lambda 环境。

根据经验,我个人使用以下方法来实现 lambda:我总是从一个空环境 ([]) 开始。如果我在 lambda 中识别出我需要的变量,我会将其添加到环境中,据此我认为它有足够的生命周期(或寻找替代方案)。

更新:

因为我是 SVG 的个人粉丝,我准备了一个(类似的)菜单图标作为 SVG 文件:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
  "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  width="32" height="32">
  <title>Start Menu</title>
  <desc>Start Menu</desc>
  <rect id="line"
    x="4" y="6" width="24" height="4"
    style="stroke:none;fill:#444"/>
  <use xlink:href="#line" transform="translate(0,8)"/>
  <use xlink:href="#line" transform="translate(0,16)"/>
 </svg>

您可以将其保存在文本文件 ic_menu_black.svg 中并尝试将其加载到您的应用中。

不幸的是,Qt 的导入器对 SVG 的支持有限。因此,并不是所有在 SVG 中可行的技巧在 Qt 中都能正常工作。因此,我从我们的 Qt 应用程序中修改了一个图标的拷贝,以确保这个能够正常工作。

关于c++ - 如何在qt中像PC开始菜单一样在状态栏中创建菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44449047/

相关文章:

c++ - 动态内存分配问题

c++ - 如何在进入函数之前指定需要什么互斥锁

c++ - 用于结构指针的 priority_queue 的自定义比较函数

c++ - Qt WindowMaximize 不改变几何(C++)

android - 如何在 Android 中将状态栏背景设置为渐变色或可绘制对象?

c++ - C++ 11中的合取类型特征

qt - 通过 eventFilter 连接/断开信号

c++ - QT可调整大小的橡皮筋

java - NetBeans 平台和 StatusLineElementProvider

android - 如何像在视频播放器中一样隐藏状态栏并在触摸时显示?