Git Product home page Git Product logo

qt-facilemenu's Introduction

FacileMenu

介绍

非常飘逸的 Qt 菜单控件,带有各种动画效果,用起来也十分方便。

无限层级,响应键盘、鼠标单独操作,支持单快捷键。

允许添加自定义 widget、layout,当做特殊的 QDialog 使用。

简单使用

  1. 放入源代码 将 facile_menu 文件夹放入 Qt 程序,pro 文件的 INCLUDEPATH 加上对应路径,resources 里的资源文件 sub_menu_arrow.png (子菜单箭头)也导入,前缀别名为::/icons/sub_menu_arrow(或按需修改)

  2. 包含头文件 #include "facile_menu.h"

  3. 创建并显示菜单

    // 创建菜单
    FacileMenu* menu = new FacileMenu(this);
    
    // 添加动作
    menu->addAction(QIcon(":/icons/run"), "开始播放 (&S)", [=]{
        /* 某操作 */
    })->tip("Ctrl+S")->disable()->hide();
    
    // 显示菜单
    menu->execute(QCursor::pos());

常用操作

连续设置

menu->addAction(QIcon(":/icons/run"), "开始播放 (&S)", [=]{})
    ->tip("Ctrl+S")
    ->disable(playing/*如果满足某条件(默认true)则disable,不满足跳过,下同*/)
    ->hide(/*条件表达式*/)
    ->uncheck(false);

子菜单

auto subMenu = menu->addMenu("子菜单2");

subMenu->addAction("继续", [=]{});

subMenu3->addAction("停止", [=]{})
        ->disable(!playing);

横向菜单

方式一:一口气添加

menu->addRow([=]{
    menu->addAction("按钮1");
    menu->addAction("按钮2");
    menu->addAction("按钮3");
});

方式二:逐个添加

menu->beginRow();
menu->addAction(QIcon(":/icons/run"));
menu->addAction(QIcon(":/icons/pause"));
menu->split();
menu->addAction(QIcon(":/icons/resume"));
menu->addAction(QIcon(":/icons/stop"))->disable();
menu->endRow();

两种方式都支持横向布局 widget

添加标题

menu->addTitle("标题", -1/0/1);

一个灰色文字的 QLabel,根据参数二会选择性添加一条分割线。

-1 添加到标题上方(margin=4),0 不添加分割线,1 添加到标题下方。默认为 0,不带分割线。

添加 QAction

支持在菜单关闭时自动 delete 传入的 action,避免内存泄漏(默认关闭)

QAction* action = ...;
menu->addAction(action, true/*是否在菜单关闭时一起delete*/);

添加 Widget/Layout

添加任意 widget 至菜单中,和菜单项并存,不占 at(index)/indexOf(item) 的位置。layout 同理。

QPushButton* button = new QPushButton("外部添加的按钮", this);
menu->addWidget(button);

添加单选菜单

如果要设置为checkable,请在创建时调用一次其以下任一方法:

setCheckable(bool) / setChecked(bool) / check(bool) / uncheck(bool)

// 使用 linger() 使菜单点击后不隐藏,持续显示当前单选/多选结果
auto ac1 = subMenu2->addAction(QIcon(":/icons/run"), "带图标")->check()->linger();
auto ac2 = subMenu2->addAction("无图标")->uncheck()->linger();
auto ac3 = subMenu2->split()->addAction("全不选")->uncheck()->linger();

// 连接点击事件
ac1->triggered([=]{
    subMenu2->singleCheck(ac1); // 用于单选,表示只选中ac1
    // 这里可以用于处理其他操作
});
ac2->triggered([=]{
    subMenu2->singleCheck(ac2);
});
ac3->triggered([=]{
    subMenu2->uncheckAll(); // 全不选
});

添加多选菜单

// 假装是某一个需要多选的属性
QList<QString>* list = new QList<QString>();

for (int i = 0; i < 10; i++)
{
    auto action = subMenu5->addAction("选项"+QString::number(i))->uncheck()->linger()->autoToggle()/*点击自动切换选中状态*/;
    action->triggered([=]{
        // 自己的处理流程,例如调用某个外部的方法
        if (action->isChecked())
            list->append(action->getText());
        else
            list->removeOne(action->getText());
        qDebug() << "当前选中的有:" << *list;
    });
}

快速批量单选项

QStringList texts;
for (int i = 0; i < 10; i++)
    texts << "项目"+QString::number(i);
static int selected = 2;

menu->addOptions(texts, selected, [=](int index){
    qDebug() << "选中了:" << (selected = index) << texts.at(index);
});

快速批量多选项

监听每一项改变的结果

// 假装是某一个需要多选的属性
QList<int>* list = new QList<int>();
subMenu6->addNumberedActions("选项%1", 0, 10)
    ->setMultiCheck([=](int index, bool checked){
        if (checked)
            list->append(index);
        else
            list->removeOne(index);
        qDebug() << "当前选中的有:" << *list;
    });

极简批量多选项

直接读取多选项结果,而不是监听多选项每一项(也可以两者结合)

finished()中获取checkedItems(),即为选中项

QList<QString>* list = new QList<QString>();
subMenu7->addNumberedActions("选项%1", 0, 15)->setMultiCheck()
    ->finished([=]{
        *list = subMenu7->checkedItemTexts();
        qDebug() << "最终选中:" << *list;
    });

菜单项 API

addAction()后,可直接设置菜单项的一些属性,包括以下:

第一个参数为bool类型的,表示满足此条件才修改设置,例如:

bool needHide = false;
action->hide(needHide); // 不满足隐藏条件,即无视此语句
// 菜单项右边快捷键区域的文字
// 如果要使用,建议用:setTipArea 来额外添加设置右边空白宽度
FacileMenuItem* tip(QString sc);
FacileMenuItem* tip(bool exp, QString sc);

// 鼠标悬浮提示
FacileMenuItem* tooltip(QString tt);
FacileMenuItem* tooltip(bool exp, QString tt);

// 触发(单击、回车键)后,参数为 Lambda 表达式
FacileMenuItem* triggered(FuncType func);
FacileMenuItem* triggered(bool exp, FuncType func);

// 当参数表达式为true时生效,false时忽略,下同
FacileMenuItem* disable(bool exp = true);
FacileMenuItem* enable(bool exp = true);

FacileMenuItem* hide(bool exp = true);
FacileMenuItem* visible(bool exp = true);

FacileMenuItem* check(bool exp = true);
FacileMenuItem* uncheck(bool exp = true);
FacileMenuItem* toggle(bool exp = true);

// 设置data,一般用于单选、多选
FacileMenuItem* setData(QVariant data);
QVariant getData();

FacileMenuItem* text(bool exp, QString str);
// 当表达式为true时,设置为tru文字,否则设置为fal文字
FacileMenuItem* text(bool exp, QString tru, QString fal);

FacileMenuItem* fgColor(QColor color);
FacileMenuItem* fgColor(bool exp, QColor color);

FacileMenuItem* bgColor(QColor color);
FacileMenuItem* bgColor(bool exp, QColor color);

// 插入前缀
FacileMenuItem* prefix(bool exp, QString pfix);
FacileMenuItem* prefix(QString pfix);

// 插入后缀,参数3支持类似 "action后缀 (K)" 这样的格式
FacileMenuItem* suffix(bool exp, QString sfix, bool inLeftParenthesis = true);
FacileMenuItem* suffix(QString sfix, bool inLeftParenthesis = true);

FacileMenuItem* icon(bool ic, QIcon icon);

// 设置边界:半径、颜色
FacileMenuItem* borderR(int radius = 3, QColor co = Qt::transparent);

// 点击后是否保持菜单显示(默认点一下就隐藏菜单)
FacileMenuItem* linger();
// 点击后保持显示(同linger()),并且修改菜单项文本
FacileMenuItem* lingerText(QString textAfterClick);

// 点击后的菜单文本改变
textAfterClick(QString newText);
// 根据当前文本修改为新文本的 Lambda 表达式
// 参数示例:[=](QString s) -> QString { if (s == "xx") return "xx"; }
textAfterClick(FuncStringStringType func);

// 满足 exp 时执行 trueLambda 表达式,否则执行 falseLambda 表达式
FacileMenuItem* ifer(bool exp, trueLambda, falseLambda = nullptr);

// 逻辑控制
FacileMenuItem* ifer(bool exp); // 满足条件时才继续,下同
FacileMenuItem* elifer(bool exp);
FacileMenuItem* elser();

FacileMenuItem* switcher(int value);
FacileMenuItem* caser(int value, matchedLambda); // 匹配时执行Lambda,无需break
FacileMenuItem* caser(int value); // 结束记得breaker(允许忘掉~)
FacileMenuItem* breaker();
FacileMenuItem* defaulter();

// 取消后面所有命令(无视层级,相当于函数中return)
FacileMenuItem* exiter(bool ex = true);

注意:由于加了一些容错处理(例如caser可以不用写breaker),无法进行if/switch的多层嵌套(较多的逻辑运算不建议放在菜单中)

配置项

静态统一颜色

都是静态变量,设置一次,所有菜单都生效。

FacileMenu::normal_bg = QColor(255, 255, 255);
FacileMenu::hover_bg = QColor(128, 128, 128, 64);
FacileMenu::press_bg = QColor(128, 128, 128, 128);
FacileMenu::text_fg = QColor(0, 0, 0);
FacileMenu::blur_bg_alpha = DEFAULT_MENU_BLUR_ALPHA;

单个菜单设置

一些可选的设置项,按需加上去,也可以都不加。

FacileMenu* menu = (new FacileMenu(this))
	->setTipArea("Ctrl+Alt+P") // 设置右边的快捷键提示区域的留空宽度,建议使用最长快捷键
	->setSplitInRow(true) // 横向按钮是否使用分割线分隔
    ->setSubMenuShowOnCursor(false) // 设置子菜单是从鼠标位置出现还是右边出现
    ->setAppearAnimation(false) // 菜单出现动画
    ->setDisappearAnimation(false); // 菜单消失动画

如果多级菜单中要将这些设置项传递给子菜单。

其中仅 setTipArea 不会传递给下一级。

可以直接修改源码中这些变量的默认值,全部菜单生效。

截图

菜单

菜单栏

菜单栏

结合 FacileMenu 自定义的一个菜单栏,目前不是很完善(做着玩的,但是对这个动画效果确实挺失望的)。

具体可参考 MainWindow 中的写法:

ui->menuBar->setAnimationEnabled(false); // 开启动画
ui->menuBar->addMenu("文件", fileMenu);
ui->menuBar->addMenu("编辑", editMenu);
ui->menuBar->addMenu("查看", viewMenu);
ui->menuBar->addMenu("帮助", helpMenu);
ui->menuBar->insertMenu(2, "格式", formatMenu);

注意点

打开模态对话框可能会引起崩溃

需要在打开模态对话框之前,关闭当前 menu

menu->addAction("选择文件", [=]{
    menu->close(); // 需要这句,否则会导致崩溃
    QString path = QFileDialog::getOpenFileName(this, "选择文件", prevPath);
    // ...
});

菜单关闭导致退出程序

main.cpp 中添加以下代码,使窗口关闭后不会退出整个程序:

QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(false);

qt-facilemenu's People

Contributors

iwxyi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

qt-facilemenu's Issues

一些建议

菜单做得非常好,也非常好用,我个人有些建议:

  1. 菜单的动画是从上往下的,能不能添加从下往上的,因为有些时候按钮在底部,弹出时动画从上往下看起来效果不好.
  2. 同一个菜单按钮,重复点击的话目前是重新弹出menu,建议改成重复点击时进行弹出和关闭,参考windows的菜单按钮

期待你的更新.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.