目录
1、最终效果展示
图1.结果展示
2、应用场景与实现原理
Qt自带菜单栏方向是水平方向,在一些情况下需要用到侧边菜单导航栏,即垂直菜单栏,如上图所示的菜单栏。
本示例使用到了鼠标钩子函数、QPushButton、QDialog、QMenu、QEvent事件过滤等,从无到有写了一个垂直菜单栏。
图2.代码文件
3、运行构建环境
Win10 64Bit系统、VS2017、调试器MSVC2017 32bit
图3.Qt Creator版本
4、源代码展示
cmousehook.h
#ifndef CMOUSEHOOK_H
#define CMOUSEHOOK_H
#include <windows.h>
#include <winuser.h>
#include <QObject>
class CMouseHook : public QObject
{
Q_OBJECT
public:
enum Model
{
eNull = 0,
eKey = 1,
eMouse = 2,
eMouseKey = 3
}mModel;
static CMouseHook* instance();
void installHook(Model model);
void unInstallHook(Model model);
private:
CMouseHook();
signals:
void closeMenu();
};
#endif // CMOUSEHOOK_H
cmousehook.cpp
#include "cmousehook.h"
static HHOOK mouseHook = nullptr;
static CMouseHook *hookClass = nullptr;
LRESULT CALLBACK mouseProc(int nCode,WPARAM wParam,LPARAM lParam)
{
if(!hookClass)
return CallNextHookEx(mouseHook,nCode,wParam,lParam);
if (WM_RBUTTONDOWN == wParam || WM_LBUTTONDOWN == wParam)
{
emit hookClass->closeMenu();
}
return CallNextHookEx(mouseHook,nCode,wParam,lParam);
}
CMouseHook::CMouseHook()
:mModel(eNull)
{
}
CMouseHook *CMouseHook::instance()
{
if(!hookClass)
hookClass = new CMouseHook();
return hookClass;
}
void CMouseHook::installHook(Model model)
{
mModel = model;
if(mModel == eMouse)
mouseHook = SetWindowsHookEx(WH_MOUSE_LL,mouseProc,nullptr,0);
}
void CMouseHook::unInstallHook(Model model)
{
if(model == eMouse)
UnhookWindowsHookEx(mouseHook);
mouseHook = nullptr;
mModel = eNull;
}
verticalmenunavigationbar.h
#ifndef VERTICALMENUNAVIGATIONBAR_H
#define VERTICALMENUNAVIGATIONBAR_H
#include <QObject>
#include <QWidget>
#include <QVBoxLayout>
#include <QDialog>
#include <QPushButton>
#include <QMenu>
#include <QEvent>
class VerticalMenuNavigationBar : public QWidget
{
Q_OBJECT
public:
VerticalMenuNavigationBar(QWidget *parent);
QDialog *menuDialog;
void hideAndRefresh();
protected:
bool eventFilter(QObject *obj, QEvent *event);
private:
QVBoxLayout *vLayout;
QVBoxLayout *vLayoutDialog;
QDialog *childDialog;
QPushButton *titleButton;
struct MenuBarListNode
{
QPushButton *pushbutton;
QMenu *menu;
QString titleStr;
int secondCounts;
};
QList<MenuBarListNode*> menuBarList;
signals:
void SendIndexToMain(QString index);
};
#endif // VERTICALMENUNAVIGATIONBAR_H
verticalmenunavigationbar.cpp
#include "verticalmenunavigationbar.h"
VerticalMenuNavigationBar::VerticalMenuNavigationBar(QWidget *parent) : QWidget(parent)
{
vLayout = new QVBoxLayout(this);
vLayout->setContentsMargins(0,0,0,0);
menuDialog = new QDialog();
menuDialog->setStyleSheet("background-color:rgb(0,0,64);");
menuDialog->setWindowFlags(Qt::Tool|Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
childDialog = new QDialog();
childDialog->setStyleSheet("background-color:rgb(0,0,64);");
childDialog->setWindowFlags(Qt::Tool|Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
titleButton = new QPushButton();
titleButton->setMinimumHeight(33);
titleButton->setMinimumWidth(90);
titleButton->setMaximumHeight(33);
titleButton->setMaximumWidth(90);
titleButton->setContentsMargins(0,0,0,0);
titleButton->setStyleSheet("QPushButton{background-color:rgb(24,189,155);"
"border-image:url(:image/generic/dropdownbg-3.png);"
"color:rgb(255,255,255);"
"font:bold 14px;"
"text-align:left;"
"font-family:'Microsoft YaHei';}"
);
vLayoutDialog = new QVBoxLayout();
vLayoutDialog->setContentsMargins(0,0,0,0);
vLayoutDialog->addWidget(titleButton);
vLayoutDialog->addWidget(childDialog);
vLayoutDialog->setSpacing(0);
menuDialog->setLayout(vLayoutDialog);
for(int i=0;i<4;i++)
{
QPushButton *button = new QPushButton();
button->setStyleSheet("QPushButton{"
"color:rgb(255,255,255);"
"}");
button->setText(QString("%1").arg(i));
button->setFixedSize(33,33);
vLayout->setSpacing(0);
vLayout->addWidget(button,Qt::AlignLeft);
button->installEventFilter(this);
QMenu *menu = new QMenu();
menu->setMinimumWidth(90);
menu->setStyleSheet(
"QMenu{"
"background-color:rgb(0,0,64);"
"margin:0px;"
"}"
"QMenu::item "
"{"
"font-size:12px;"
"color:rgb(255,225,255);"
"font-family:Microsoft YaHei;"
"background-color:rgb(52,73,94,20);"
"padding:5px 5px; "
"margin:0px 0px;"
"border-bottom:1px solid rgb(52,73,94,180);"
"}"
"QMenu::item:selected "
"{"
"background-color: rgb(24,189,155);"
"font-size:12px;"
"color:rgb(0,0,0);"
"font-family:Microsoft YaHei;"
"}"
"QMenu::item:hover "
"{"
"font-size:12px;"
"color:rgb(0,0,0);"
"background-color: rgb(155,189,155);"
"font-family:Microsoft YaHei;"
"}");
menu->setParent(childDialog);
MenuBarListNode *menuBarListNode = new MenuBarListNode();
menuBarListNode->pushbutton = button;
menuBarListNode->titleStr = QString("%1").arg(i);
menuBarListNode->menu = menu;
if(i == 0 || i == 2)
{
menuBarListNode->secondCounts = 2;
for(int j=0;j<2;j++)
{
menu->addAction("ShowPag" + QString("%1").arg(i) + QString("%1").arg(j) ,[=]{
emit SendIndexToMain(QString("%1").arg(i) + QString("%1").arg(j));
hideAndRefresh();
});
}
}
else
{
menuBarListNode->secondCounts = 0;
connect(button,&QPushButton::clicked,[=]{
emit SendIndexToMain(QString("%1").arg(i));
hideAndRefresh();
});
}
menuBarList << menuBarListNode;
}
}
void VerticalMenuNavigationBar::hideAndRefresh()
{
for(int i=0;i<menuBarList.length();i++)
{
menuBarList.at(i)->pushbutton->setStyleSheet("QPushButton{"
"color:rgb(255,255,255);"
"}");
}
menuDialog->hide();
}
bool VerticalMenuNavigationBar::eventFilter(QObject *obj, QEvent *event)
{
for(int i=0;i<menuBarList.length();i++)
{
if(obj == menuBarList.at(i)->pushbutton && (event->type() == QEvent::Enter || event->type() == QEvent::MouseButtonPress))
{
menuDialog->show();
menuBarList.at(i)->pushbutton->setStyleSheet("QPushButton{"
"color:rgb(255,255,255);"
"background-color: rgb(24,189,155);"
"}");
for(int j=0;j<menuBarList.length();j++)
{
if(i==j)
{
titleButton->setText(menuBarList.at(j)->titleStr);
menuBarList.at(j)->menu->show();
}
else
{
menuBarList.at(j)->menu->hide();
menuBarList.at(j)->pushbutton->setStyleSheet("QPushButton{"
"color:rgb(255,255,255);"
"}");
}
}
childDialog->resize(90,menuBarList.at(i)->menu->rect().height());
menuDialog->resize(90,titleButton->minimumHeight() + menuBarList.at(i)->menu->rect().height());
QPoint p = menuBarList.at(i)->pushbutton->mapToGlobal(QPoint(0, 0));
menuDialog->move(QPoint(p.x()+menuBarList.at(i)->pushbutton->width(), p.y()));
if(menuBarList.at(i)->secondCounts > 1)
return true;
else
return false;
}
}
return QObject::eventFilter(obj, event);
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "verticalmenunavigationbar.h"
#include "cmousehook.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
VerticalMenuNavigationBar *menuNavigationBar;
public slots:
void receiveIndex(QString index);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->widget->setContentsMargins(0,0,0,0);
menuNavigationBar = new VerticalMenuNavigationBar(ui->widget);
connect(menuNavigationBar,&VerticalMenuNavigationBar::SendIndexToMain,this,&MainWindow::receiveIndex);
CMouseHook::instance()->installHook(CMouseHook::eMouse);
connect(CMouseHook::instance(),&CMouseHook::closeMenu,[=](){
if(!menuNavigationBar->menuDialog->isHidden() && ((QCursor::pos().x() < menuNavigationBar->menuDialog->mapToGlobal(QPoint(0,0)).x() || QCursor::pos().x() > menuNavigationBar->menuDialog->mapToGlobal(QPoint(0,0)).x() + menuNavigationBar->menuDialog->rect().width() ) || (QCursor::pos().y() < menuNavigationBar->menuDialog->mapToGlobal(QPoint(0,0)).y() || QCursor::pos().y() > menuNavigationBar->menuDialog->mapToGlobal(QPoint(0,0)).y() + menuNavigationBar->menuDialog->rect().height())))
menuNavigationBar->hideAndRefresh();
});
}
MainWindow::~MainWindow()
{
CMouseHook::instance()->unInstallHook(CMouseHook::eMouse);
delete ui;
}
void MainWindow::receiveIndex(QString index)
{
if(index == "00")
ui->stackedWidget->setCurrentWidget(ui->page);
else if(index == "01")
ui->stackedWidget->setCurrentWidget(ui->page_2);
else if(index == "1")
ui->stackedWidget->setCurrentWidget(ui->page_3);
else if(index == "20")
ui->stackedWidget->setCurrentWidget(ui->page_4);
else if(index == "21")
ui->stackedWidget->setCurrentWidget(ui->page_5);
else
ui->stackedWidget->setCurrentWidget(ui->page_6);
}
LeftMenuNavigationBar.pro文件中添加:
LIBS += $$quote(C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib\User32.Lib)