开源地址:https://github.com/SeriousAlexej/TabToolbar
该库的使用方式有两种:
项目是使用Qt和CMake管理的,并且在开发的时候使用的是Qt6,我实测通过更改CMake的配置文件,在Qt6中也是可以使用的。这一部分修改省略

这里我主要想探索一下,这个开源库的使用

在文件结构中的位置如上图。
tt::Builder ttb(this);
ttb.SetCustomWidgetCreator("textEdit", []() { return new QTextEdit(); });
ttb.SetCustomWidgetCreator("checkBox", []() { return new QCheckBox(); });
ttb.SetCustomWidgetCreator("pushButton", []() { return new QPushButton(); });
tt::TabToolbar* tabToolbar = ttb.CreateTabToolbar(":/tt/tabtoolbar.json");
addToolBar(Qt::TopToolBarArea, tabToolbar);
ttb["customTextEdit"]->setMaximumWidth(100);
((QCheckBox*)ttb["customCheckBox"])->setText("点击");
QPushButton* btn = (QPushButton*)ttb["customEditButton"];
btn->setText("Edit");
static bool kek = true;
tt::Page* editPage = (tt::Page*)ttb["Edit"];
QObject::connect(btn, &QPushButton::clicked, [editPage]()
{
if(kek)
editPage->hide();
else
editPage->show();
kek = !kek;
});
QObject::connect(tabToolbar, &tt::TabToolbar::SpecialTabClicked, this, [this]()
{
QMessageBox::information(this, "Kek", "Cheburek");
});
//create buttons for each style
tt::Group* stylesGroup = (tt::Group*)ttb["Styles"];
stylesGroup->AddSeparator();
QStringList styles = tt::GetRegisteredStyles();
for(int i=0; i<styles.size(); i++)
{
const QString styleName = styles.at(i);
QPushButton* btn = new QPushButton(styleName, this);
QObject::connect(btn, &QPushButton::clicked, [styleName, tabToolbar]() { tabToolbar->SetStyle(styleName); });
stylesGroup->AddWidget(btn);
}
tt::RegisterStyle("NoStyle", []()
{
tt::StyleParams* params = new tt::StyleParams();
params->UseTemplateSheet = false;
params->AdditionalStyleSheet = "";
return params;
});
btn = (QPushButton*)ttb["nativeStyleButton"];
btn->setText("No Style");
QObject::connect(btn, &QPushButton::clicked, [tabToolbar]() { tabToolbar->SetStyle("NoStyle"); });
btn = (QPushButton*)ttb["defaultStyleButton"];
btn->setText("Default");
QObject::connect(btn, &QPushButton::clicked, [tabToolbar]() { tabToolbar->SetStyle(tt::GetDefaultStyle()); });
{
"groupHeight": 75,
"groupRowCount": 3,
"specialTab": true,
"cornerActions": [
"actionHelp"
],
"menus": [
{
"name": "dummyMenu",
"actions": [
"actionDummy",
"separator",
"actionHelp"
]
}
],
"tabs": [
{
"displayName": "文件",
"name": "File",
"groups": []
},
{
"displayName": "编辑",
"name": "Edit",
"groups": [
{
"displayName": "样式",
"name": "Styles",
"content": [
{
"itemType": "subgroup",
"aligned": true,
"name": "stylesSubgroup1",
"content": [
{
"itemType": "pushButton",
"name": "nativeStyleButton"
},
{
"itemType": "pushButton",
"name": "defaultStyleButton"
}
]
}
]
}
]
},
{
"displayName": "视图",
"name": "View",
"groups": [
{
"displayName": "分组1",
"name": "Group 1",
"content": [
{
"itemType": "action",
"type": "delayedPopup",
"name": "actionOpen"
},
{
"itemType": "separator"
},
{
"itemType": "action",
"type": "delayedPopup",
"name": "actionSave"
},
{
"itemType": "action",
"type": "delayedPopup",
"name": "actionSaveAs"
}
]
},
{
"displayName": "分组2",
"name": "Group 2",
"content": [
{
"itemType": "action",
"type": "instantPopup",
"name": "actionPolypaint",
"menu": "dummyMenu"
},
{
"itemType": "action",
"type": "instantPopup",
"name": "actionScale",
"menu": "dummyMenu"
},
{
"itemType": "separator"
},
{
"itemType": "textEdit",
"name": "customTextEdit"
},
{
"itemType": "subgroup",
"name": "group2Subgroup",
"aligned": true,
"content": [
{
"itemType": "action",
"type": "delayedPopup",
"name": "actionUndo"
},
{
"itemType": "action",
"type": "delayedPopup",
"name": "actionRedo"
},
{
"itemType": "action",
"type": "instantPopup",
"name": "actionClose",
"menu": "dummyMenu"
}
]
}
]
},
{
"displayName": "分组3",
"name": "Group 3",
"content": [
{
"itemType": "action",
"type": "menuButtonPopup",
"name": "actionSettings",
"menu": "dummyMenu"
},
{
"itemType": "subgroup",
"name": "group3Subgroup1",
"aligned": true,
"content": [
{
"itemType": "horizontalActions",
"actions": [
{
"type": "delayedPopup",
"name": "actionSave"
},
{
"type": "instantPopup",
"name": "actionPolypaint",
"menu": "dummyMenu"
},
{
"type": "menuButtonPopup",
"name": "actionSettings",
"menu": "dummyMenu"
}
]
},
{
"itemType": "horizontalActions",
"actions": [
{
"type": "delayedPopup",
"name": "actionUndo"
},
{
"type": "delayedPopup",
"name": "actionRedo"
},
{
"type": "instantPopup",
"name": "actionClose",
"menu": "dummyMenu"
}
]
},
{
"itemType": "checkBox",
"name": "customCheckBox"
}
]
},
{
"itemType": "separator"
},
{
"itemType": "subgroup",
"name": "group3Subgroup2",
"aligned": false,
"content": [
{
"itemType": "pushButton",
"name": "customEditButton"
},
{
"itemType": "action",
"type": "delayedPopup",
"name": "actionSaveAs"
}
]
}
]
}
]
},
{
"displayName": "帮助",
"name": "Help",
"groups": [
{
"displayName": "",
"name": "HelpGroup",
"content": [
{
"displayName": "帮助",
"itemType": "action",
"type": "delayedPopup",
"name": "actionHelp"
},
{
"itemType": "action",
"type": "delayedPopup",
"name": "actionAbout"
}
]
}
]
}
]
}
分析一下
1.创建对象
tt::Builder ttb(this);
"itemType": "textEdit"字段就行。 ttb.SetCustomWidgetCreator("textEdit", []() { return new QTextEdit(); });
ttb.SetCustomWidgetCreator("checkBox", []() { return new QCheckBox(); });
ttb.SetCustomWidgetCreator("pushButton", []() { return new QPushButton(); });
tt::TabToolbar* tabToolbar = ttb.CreateTabToolbar(":/tt/tabtoolbar.json");
addToolBar(Qt::TopToolBarArea, tabToolbar);
ttb["customTextEdit"]->setMaximumWidth(100);
((QCheckBox*)ttb["customCheckBox"])->setText("点击");
QPushButton* btn = (QPushButton*)ttb["customEditButton"];
btn->setText("Edit");
static bool kek = true;
tt::Page* editPage = (tt::Page*)ttb["Edit"];
QObject::connect(btn, &QPushButton::clicked, [editPage]()
{
if(kek)
editPage->hide();
else
editPage->show();
kek = !kek;
});
QObject::connect(tabToolbar, &tt::TabToolbar::SpecialTabClicked, this, [this]()
{
QMessageBox::information(this, "Kek", "Cheburek");
});
//create buttons for each style
tt::Group* stylesGroup = (tt::Group*)ttb["Styles"];
stylesGroup->AddSeparator();
QStringList styles = tt::GetRegisteredStyles();
for(int i=0; i<styles.size(); i++)
{
const QString styleName = styles.at(i);
QPushButton* btn = new QPushButton(styleName, this);
QObject::connect(btn, &QPushButton::clicked, [styleName, tabToolbar]() { tabToolbar->SetStyle(styleName); });
stylesGroup->AddWidget(btn);
}
tt::RegisterStyle("NoStyle", []()
{
tt::StyleParams* params = new tt::StyleParams();
params->UseTemplateSheet = false;
params->AdditionalStyleSheet = "";
return params;
});
btn = (QPushButton*)ttb["nativeStyleButton"];
btn->setText("No Style");
QObject::connect(btn, &QPushButton::clicked, [tabToolbar]() { tabToolbar->SetStyle("NoStyle"); });
btn = (QPushButton*)ttb["defaultStyleButton"];
btn->setText("Default");
QObject::connect(btn, &QPushButton::clicked, [tabToolbar]() { tabToolbar->SetStyle(tt::GetDefaultStyle()); });
再开一下json文件的内容
分别指定组的高度,每组容纳的最多行数,是否启用特殊标签,然后就是角落的action,然后是定义菜单栏的情况,最后是定义tab标签。
{
"groupHeight": 75,
"groupRowCount": 3,
"specialTab": true,
"cornerActions": [
...
],
"menus": [
...
],
"tabs": [
...
]
首先看一下代码,
using namespace tt;
TabToolbar* tt = new TabToolbar(this, 75, 3);
addToolBar(Qt::TopToolBarArea, tt);
QMenu* menu = new QMenu(this);
menu->setObjectName("dummyMenu");
menu->addActions({ui->actionDummy});
tt->AddPage("File");
static bool kek = true;
Page* editPage = tt->AddPage("Edit");
Page* viewPage = tt->AddPage("View");
Group* g1 = viewPage->AddGroup("Group 1");
Group* g2 = viewPage->AddGroup("Group 2");
Group* g3 = viewPage->AddGroup("Group 3");
g1->AddAction(QToolButton::DelayedPopup, ui->actionOpen);
g1->AddSeparator();
g1->AddAction(QToolButton::DelayedPopup, ui->actionSave);
g1->AddAction(QToolButton::DelayedPopup, ui->actionSaveAs);
g2->AddAction(QToolButton::InstantPopup, ui->actionPolypaint, menu);
g2->AddAction(QToolButton::InstantPopup, ui->actionScale, menu);
g2->AddSeparator();
QTextEdit* te = new QTextEdit();
g2->AddWidget(te);
te->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
te->setMaximumWidth(100);
SubGroup* g2s = g2->AddSubGroup(SubGroup::Align::Yes);
g2s->AddAction(QToolButton::DelayedPopup, ui->actionUndo);
g2s->AddAction(QToolButton::DelayedPopup, ui->actionRedo);
g2s->AddAction(QToolButton::InstantPopup, ui->actionClose, menu);
g3->AddAction(QToolButton::MenuButtonPopup, ui->actionSettings, menu);
SubGroup* g3s = g3->AddSubGroup(SubGroup::Align::Yes);
g3s->AddHorizontalButtons({{QToolButton::DelayedPopup, ui->actionSave},
{QToolButton::InstantPopup, ui->actionPolypaint, menu},
{QToolButton::MenuButtonPopup, ui->actionSettings, menu}});
g3s->AddHorizontalButtons({{QToolButton::DelayedPopup, ui->actionUndo},
{QToolButton::DelayedPopup, ui->actionRedo},
{QToolButton::InstantPopup, ui->actionClose, menu}});
QCheckBox* ch = new QCheckBox("Check 1");
g3s->AddWidget(ch);
g3->AddSeparator();
SubGroup* g3ss = g3->AddSubGroup(SubGroup::Align::No);
QPushButton* btn = new QPushButton("Edit");
g3ss->AddWidget(btn);
g3ss->AddAction(QToolButton::DelayedPopup, ui->actionSaveAs);
QObject::connect(btn, &QPushButton::clicked, [editPage]()
{
if(kek)
editPage->hide();
else
editPage->show();
kek = !kek;
});
tt->AddPage("Help");
tt->SetSpecialTabEnabled(true);
tt->AddCornerAction(ui->actionHelp);
QObject::connect(tt, &TabToolbar::SpecialTabClicked, this, [this]()
{
QMessageBox::information(this, "Kek", "Cheburek");
});
然后我们来分析一下,这是怎么使用的
using namespace tt; //使用库的名字空间
TabToolbar* tt = new TabToolbar(this, 75, 3); //初始化
addToolBar(Qt::TopToolBarArea, tt); //添加TabToolbar到tool工具栏
//创建案例并绑定ui设计器里面的action
QMenu* menu = new QMenu(this);
menu->setObjectName("dummyMenu");
menu->addActions({ui->actionDummy});
//添加tab页
tt->AddPage("File");
static bool kek = true;
Page* editPage = tt->AddPage("Edit");//添加tab页,并获取对象
Page* viewPage = tt->AddPage("View");
Group* g1 = viewPage->AddGroup("Group 1"); //再tab页里面添加组
Group* g2 = viewPage->AddGroup("Group 2");
Group* g3 = viewPage->AddGroup("Group 3");
//各组控件的设置
g1->AddAction(QToolButton::DelayedPopup, ui->actionOpen);
g1->AddSeparator();
g1->AddAction(QToolButton::DelayedPopup, ui->actionSave);
g1->AddAction(QToolButton::DelayedPopup, ui->actionSaveAs);
g2->AddAction(QToolButton::InstantPopup, ui->actionPolypaint, menu);
g2->AddAction(QToolButton::InstantPopup, ui->actionScale, menu);
g2->AddSeparator();
QTextEdit* te = new QTextEdit();
g2->AddWidget(te);
te->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
te->setMaximumWidth(100);
SubGroup* g2s = g2->AddSubGroup(SubGroup::Align::Yes);
g2s->AddAction(QToolButton::DelayedPopup, ui->actionUndo);
g2s->AddAction(QToolButton::DelayedPopup, ui->actionRedo);
g2s->AddAction(QToolButton::InstantPopup, ui->actionClose, menu);
g3->AddAction(QToolButton::MenuButtonPopup, ui->actionSettings, menu);
SubGroup* g3s = g3->AddSubGroup(SubGroup::Align::Yes);
g3s->AddHorizontalButtons({{QToolButton::DelayedPopup, ui->actionSave},
{QToolButton::InstantPopup, ui->actionPolypaint, menu},
{QToolButton::MenuButtonPopup, ui->actionSettings, menu}});
g3s->AddHorizontalButtons({{QToolButton::DelayedPopup, ui->actionUndo},
{QToolButton::DelayedPopup, ui->actionRedo},
{QToolButton::InstantPopup, ui->actionClose, menu}});
QCheckBox* ch = new QCheckBox("Check 1");
g3s->AddWidget(ch);
g3->AddSeparator();
SubGroup* g3ss = g3->AddSubGroup(SubGroup::Align::No);
QPushButton* btn = new QPushButton("Edit");
g3ss->AddWidget(btn);
g3ss->AddAction(QToolButton::DelayedPopup, ui->actionSaveAs);
QObject::connect(btn, &QPushButton::clicked, [editPage]()
{
if(kek)
editPage->hide();
else
editPage->show();
kek = !kek;
});
tt->AddPage("Help");
tt->SetSpecialTabEnabled(true);
tt->AddCornerAction(ui->actionHelp); //绑定action
QObject::connect(tt, &TabToolbar::SpecialTabClicked, this, [this]()//绑定action
{
QMessageBox::information(this, "Kek", "Cheburek");
});
TabToolbar* tt = new TabToolbar(); // 构造tabtoolbaraddToolBar(Qt::TopToolBarArea, tt); // 添加对象到mainwindowsPage* editPage = tt->AddPage(“Edit”);//添加tab页,并获取对象Group* g1 = editPage ->AddGroup(“Group 1”); //tab页里面添加组AddAction(QToolButton::DelayedPopup, ui->actionOpen); // 添加actionAddSeparator();// 添加分割器在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q
目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭6年前。Improvethisquestion是否有任何用Ruby或Python编写的生产就绪的开源Twitter克隆?我对功能丰富的实现更感兴趣,而不仅仅是简单的Twitter消息(例如:API、FBconnect、通知等)谢谢!
文章目录写在前面1、下载与安装(windows)1.1、idea中配置gradle2、基础知识(Gradle6.9为例)2.1、Gradle脚本语法2.1.1、dependsOn2.1.2、创建动态任务2.1.3、增加任务行为2.1.4、参数2.1.5、Ant任务2.1.6、方法2.1.7、默认任务2.1.6、依赖任务的不同输出3、java项目中使用3.1、在已有项目中构建gradle3.2、在新建项目时构建gradle(idea)3.3、gradle项目目录结构3.4、build.gradle3.4.1、plugins3.4.2、repositories3.4.3、dependencies3
Iparking停车收费管理系统-可商用介绍Iparking是一款基于springBoot的停车收费管理系统,支持封闭车场和路边车场,支持微信支付宝多种支付渠道,支持多种硬件,涵盖了停车场管理系统的所有基础功能。技术栈Springboot,MybatisPlus,Beetl,Mysql,Redis,RabbitMQ,UniApp功能云端功能序号模块功能描述1系统管理菜单管理配置系统菜单2系统管理组织管理管理组织机构3系统管理角色管理配置系统角色,包含数据权限和功能权限配置4系统管理用户管理管理后台用户5系统管理租户管理多租户管理6系统管理公众号配置租户公众号配置7系统管理操作日志审计日志8系统
我有兴趣了解使用nosql将如何影响rails应用程序的架构/设计/代码。有人知道使用nosql持久性的开源rails应用程序的一个好例子吗?谢谢 最佳答案 看看这些项目:卡桑德拉用法atDigg。卡桑德拉用法atTwitter。Friendly用法atFetLife(nsfw)。最后,MyNoSQL是一个提供nosql相关信息的好网站。 关于ruby-on-rails-有没有很好的引用(开源)RailsNoSQL应用程序?,我们在StackOverflow上找到一个类似的问题:
内容来自Qt样式表之QSS语法介绍-3YL的博客Qt样式表是一个可以自定义部件外观的十分强大的机制,可以用来美化部件。Qt样式表的概念、术语和语法都受到了HTML的层叠样式表(CascadingStyleSheets, CSS教程)的启发,不过与CSS不同的是,Qt样式表应用于部件的世界。类型选择器QPushButton匹配QPushButton及其子类的实例ID选择器QPushButton#okButton匹配所有objectName为okButton的QPushButton实例。 CSS常用样式1CSS文字属性注:px:相对长度单位,像素(Pixel)。pt:绝对长度单位,点(Point
QT串口调试工具第一节虚拟串口工具安装第二节QT创建一个基于QWidget的项目第三节UI界面设计第三节项目头文件widget.h第四节项目实现文件widget.cpp第五节main函数第六节编译结果重点第七节使用QT打包程序,不安装QT的电脑可使用第一节虚拟串口工具安装-----------------------------------------下载所需工具---------------------------------------------------------------------链接:https://pan.baidu.com/s/1QkT36S4EnH2HEAhZ1TZ8
关闭。这个问题不符合StackOverflowguidelines。它目前不接受答案。要求我们推荐或查找书籍、工具、软件库、教程或其他场外资源的问题对于StackOverflow来说是偏离主题的,因为它们往往会吸引自以为是的答案和垃圾邮件。相反,请描述问题以及迄今为止为解决该问题所做的工作。关闭8年前。Improvethisquestion在过去的4个月左右的时间里,我一直在使用rubyonrails,我真的很喜欢开源的整个概念。我知道它不是ruby/rails独有的,但来自Windows编程,这是我第一次真正接触它。我想尽我所能“回馈”,但我觉得我无法贡献任何有值(value
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭7年前。Improvethisquestion我是一名RubyonRails开发人员,手头有一些时间。我想利用这段时间通过为开源项目做贡献来回馈和学习。我不是一流的程序员,想从小做起。在哪里可以找到Ruby或Rails中的小型开源项目?我该如何贡献?亚历克斯