C++ 如何在qt-like PC开始菜单的状态栏中创建菜单
在我的qt应用程序中,我设计了带有几个图标的状态栏。在我的状态栏左侧,我添加了菜单图标(QPixmap),当我单击该图标时,我需要显示一个类似于PC开始菜单的菜单。我搜索了很多,但没有找到这个Qwidget 这是我的qt应用程序窗口 根据我最近的评论,我在下面添加了我编辑的代码,因为我无法在评论部分添加代码,请建议解决方案C++ 如何在qt-like PC开始菜单的状态栏中创建菜单,c++,qt,statusbar,C++,Qt,Statusbar,在我的qt应用程序中,我设计了带有几个图标的状态栏。在我的状态栏左侧,我添加了菜单图标(QPixmap),当我单击该图标时,我需要显示一个类似于PC开始菜单的菜单。我搜索了很多,但没有找到这个Qwidget 这是我的qt应用程序窗口 根据我最近的评论,我在下面添加了我编辑的代码,因为我无法在评论部分添加代码,请建议解决方案 //Menu Button menuBtn->setIcon(QPixmap(":/new/prefix1/ic_menu_black.png"));
//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!";
}
//菜单按钮
菜单->设置图标(QPixmap(:/new/prefix1/ic_menu_black.png”);
statusBar()->addWidget(菜单项);
连接(菜单项、信号(单击(bool))、此、插槽(showPopupMenu());
void主窗口::showPopupMenu(){
QMenu QMenu启动;
QAction qCmdStart1(QString::fromUtf8(“产品详细信息”),&qMenuStart);
qMenuStart.addAction(&qCmdStart1);
QAction qCmdStart2(QString::fromUtf8(“内存状态”),&qMenuStart);
qMenuStart.addAction(&qCmdStart2);
QObject::connect(&qCmdStart1,&QAction::triggered,[](bool){
qDebug()阅读您的问题,我不太确定您的实际问题是什么。不幸的是,由于我们公司的安全政策,I.stack.imgur.com
被阻止,我就在办公室。可能您的快照已经为我澄清了问题。(我可以在回家后再看一看。)
然而,出于好奇,我尝试了我的运气,想展示我所拥有的:
实际上,使用将小部件添加到状态栏非常容易
不幸的是,永久性窗口小部件被放置在右侧。如果要求(将其放置在左侧)是必要的,则可以通过将两个状态栏嵌套在彼此中来调整。(实际上,每个其他布局都应该能够,但QMainWindow::setStatusBar()
需要QStatusBar*
)
内部状态栏必须用于临时消息。为了防止重复的大小夹点产生有趣的效果,内部状态栏禁用了大小夹点(使用)
嵌套状态栏的另一个副作用是在内部状态栏的左侧和右侧显示分隔符。我认为这没那么糟糕(关于美学方面),对此并不在意
可能是,我可以简单地使用一个(而不是内部状态栏)来显示消息(失去了QStatusBar
提供的附加功能,例如自动清除消息的超时)
为了提供“开始”按钮,我最初使用了一个。记住我必须以某种方式放置“开始”菜单,我将其替换为一个,因为它可能包含一个,而它又准备好管理子菜单
当我完成这项工作时,我意识到当我设置菜单时,开始按钮上出现了一个指示灯。为了使样本尽可能短,我决定暂时使用它
在与提问者进行了一些交流之后,我添加了一个使用派生自的类的替代实现。菜单的放置必须自己完成。但最后,它没有那么复杂
如果定义了USE\u LABEL
(接近源代码开头),则激活第二个版本
我的示例testQStartBtn.cc
:
#include <QtWidgets>
#define USE_LABEL
#ifdef USE_LABEL
class StartButton: public QLabel {
private:
QMenu *_pQMenu;
public:
StartButton(QWidget *pQParent = 0): QLabel(pQParent), _pQMenu(nullptr) { }
QMenu* menu() { return _pQMenu; }
QMenu* setMenu(QMenu *pQMenu) { std::swap(_pQMenu, pQMenu); return pQMenu; }
protected:
virtual void mousePressEvent(QMouseEvent *pQEvent);
};
void StartButton::mousePressEvent(QMouseEvent *pQEvent)
{
if (_pQMenu && pQEvent->button() == Qt::LeftButton) {
if (!_pQMenu->isVisible()) {
_pQMenu->show(); // a trick to force computation of height() before
_pQMenu->popup(mapToGlobal(pos()) - QPoint(0, _pQMenu->height()));
} else _pQMenu->hide();
}
}
#endif // USE_LABEL
int main(int argc, char **argv)
{
qDebug() << "Qt Version: " << QT_VERSION_STR;
// main application
#undef qApp // undef macro qApp out of the way
QApplication qApp(argc, argv);
// setup GUI
QMainWindow qWin;
QLabel qLblCentral(QString::fromUtf8("Central\nWidget"));
qLblCentral.setAlignment(Qt::AlignCenter);
qWin.setCentralWidget(&qLblCentral);
QStatusBar qStBarLayout;
// the "Windows Start Menu" alike
#ifdef USE_LABEL
StartButton qBtnStart;
qBtnStart.setPixmap(QPixmap(
QApplication::applicationDirPath() + QString::fromLatin1("/Start.png")));
#else // (not) USE_LABEL
QToolBar qToolbarStart;
QIcon qIcnStart(
QApplication::applicationDirPath() + QString::fromLatin1("/Start.png"));
QAction qCmdStart(qIcnStart, QString::fromUtf8("Start"), &qToolbarStart);
#endif // USE_LABEL
QMenu qMenuStart;
QAction qCmdStart1(QString::fromUtf8("Command 1"), &qMenuStart);
qMenuStart.addAction(&qCmdStart1);
QAction qCmdStart2(QString::fromUtf8("Command 2"), &qMenuStart);
qMenuStart.addAction(&qCmdStart2);
QAction qCmdStart3(QString::fromUtf8("Command 3"), &qMenuStart);
qMenuStart.addAction(&qCmdStart3);
#ifdef USE_LABEL
qBtnStart.setMenu(&qMenuStart);
qStBarLayout.insertPermanentWidget(0, &qBtnStart);
#else // (not) USE_LABEL
qCmdStart.setMenu(&qMenuStart);
qToolbarStart.addAction(&qCmdStart);
qStBarLayout.insertPermanentWidget(0, &qToolbarStart);
#endif // USE_LABEL
// the rest of status bar
QStatusBar qStBar;
qStBar.showMessage(QString::fromUtf8("<- Start Menu"), 3000 /* ms */);
qStBar.setSizeGripEnabled(false);
qStBarLayout.insertPermanentWidget(1, &qStBar, 1);
qWin.setStatusBar(&qStBarLayout);
qWin.show();
// install signal handlers
QObject::connect(&qCmdStart1, &QAction::triggered,
[](bool){ qDebug() << "Command 1 triggered"; });
QObject::connect(&qCmdStart2, &QAction::triggered,
[](bool){ qDebug() << "Command 2 triggered"; });
QObject::connect(&qCmdStart3, &QAction::triggered,
[](bool){ qDebug() << "Command 3 triggered"; });
// run application
return qApp.exec();
}
#包括
#定义使用标签
#ifdef使用_标签
类StartButton:公共QLabel{
私人:
QMenu*\u pQMenu;
公众:
开始按钮(QWidget*pQParent=0):QLabel(pQParent),_pQMenu(nullptr){
QMenu*菜单(){return\u pQMenu;}
QMenu*setMenu(QMenu*pQMenu){std::swap(_pQMenu,pQMenu);返回pQMenu;}
受保护的:
虚拟void mousePressEvent(QMouseEvent*pQEvent);
};
void StartButton::MousePresseEvent(QMouseEvent*pQEvent)
{
如果(\u pQMenu&&pQEvent->button()==Qt::LeftButton){
如果(!\u pQMenu->isVisible()){
_pQMenu->show();//在
_pQMenu->弹出窗口(映射全局(位置())-QPoint(0,_pQMenu->高度());
}else(菜单->隐藏();
}
}
#endif//使用\u标签
int main(int argc,字符**argv)
{
qDebug()我获取了您的示例代码并对其进行了更改,以说明我在最新评论中所描述的内容:
将成员变量添加到main窗口
声明中:
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()));
我做得很仔细,但无法测试(因为它不是MCVE)。所以,请带上“盐粒”
注:
我刚刚意识到,您使用了连接信号处理程序的“pre-Qt5”样式。Qt5引入了一个很好的支持函数指针和方法指针。因此,我能够简单地按如下方式来处理信号处理程序。(lambda是这些[](bool){/*…*/}
我连接到操作槽。我一直怀疑这些新的lambda,直到我意识到它们是为信号处理程序编写非常简单的适配器以及制作非常紧凑的示例代码的极好工具。)
关于Lambdas的更新:
括号[]
可用于向lambda的环境(或上下文)添加变量。如果为空(如我所用),则只能使用全局变量和函数。使用[此]
表示当前此
指针被添加到环境中。因此,lambda可以访问当前类实例的成员变量
当我第一次认识LAMBDAS时,我经常看到<代码> [= ] /Cord>。这意味着lambda得到调用函数的当前上下文(例如,每个局部函数变量的副本)。我个人认为这是危险的,特别是对于信号处理程序。我将详细阐述一下:
lambda的环境允许访问lambda主体中的“外部变量”。变量可以通过值或引用进行添加。如果变量是通过引用提供的,则可以在lambda主体中访问该变量,但它不会授予“外部”变量足够长的生存期。(如果不是,则会导致“悬空引用”具有与悬空指针相同的未定义行为。)是否为h
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!";
}
<?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>