手把手教Qt Creator插件开发-QT运行计时器
手把手教Qt Creator插件-QT运行计时器
QT Creator是QT官方的C++开发IDE,灵活的插件框架,助你方便的拓展想要的功能。本例环境:
qt-creator 版本 : qt-creator-opensource-src-4.3.1
QT库 :Qt5.9.1/5.9.1/
编译器:mingw53_32
功能需求:
1. 保存用户Setting
2. 实现Core::IOptionsPage,加到OptionPage(Tools->Option),
实现 Core::ActionManager::createMenu,加到Tools菜单项中,
3. 实现QWidget,放置具体的设置页,实现交互的GUI
插件生存期:QT插件具有良好的启动和关闭生存期,当应用启动,所有的插件按照依赖加载到队列中(依赖于哪些插件)。然后,开启每一个插件第一阶段的初始化流程
- 按照queue中顺序,调用Plugin构造函数
- 按照queue中顺序,调用Initialize()- 被依赖的插件应先初始化
- 按照相反的顺序,调用extensionsInitialized() – 这样可以访问已初始化的依赖的那些插件
- Core::ICore发送coreAboutToOpen()信号
经过上面过程,QT Creator UI就显示在界面上了。接着第二部分初始化流程开始
- Core::ICore发送coreOpened()信号
- 按照相反的顺序,调用delayedInitialize(),初始化都间隔一定的时间,这种不重要的初始化可以减少QT Creator的加载时间
- PluginManager 发送initializationDone()信号
经过以上步骤,插件完成初始化。关闭应用有相似的处理过程。
- Core::ICore发送coreAboutToClose()信号
- 按照queue中顺序调用aboutToShutdown()
- 返回SynchronousShutdown通知终止
- 返回AsynchronousShutdown让Creator等待直到发送asynchronousShutdownFinished()信号
- ~Plugin()按照queue逆序析构
简单的例子:
1. 环境配置
下载 库Qt5.9.1
下载qt-creator源码:qt-creator-opensource-src-4.3.1
在qt-creator同级目录下新建build文件夹,存放qt-creator源码编译结果
打开QT命令行环境,输入如下命令,在bin目录下得到编译后的QtCreator可执行文件
qmake ../qt-creator-opensource-src-4.3.1/qtcreator.pro -spec win32-g++ "CONFIG+=debug" "QT_PRIVATE_HEADERS=C:/Qt/Qt5.9.1/5.9.1/mingw53_32/include"
mingw32-make -debug
note: 如果按照debug方式编译出的执行档,插件得相应选择debug方式编译。因为插件编译使用的库文件,依赖于相应方式release/debug编译出的dll文件。否则,将无法通过编译。
2. 创建插件工程
qtctimer.pro – qmake 工程文件
qtctimerplugin.h/.cpp – 插件类文件
QtCTimer.json.in – 存储插件信息
如果想在Windows下看debug log 信息:设置QT_DEBUG_PLUGINS = 1 并打开dbgview64监控
工程中设置编译环境如下:
插件代码实现:
插件类-头文件
插件类-实现文件
设置类-头文件
设置类-实现文件
选项页-头文件
选项页-实现文件
https://www.devbean.net/2011/10/qtcreator-plugin-develop-6/
摘自剖析架构
“如果一个插件有实现了这样的接口的对象,那么这个对象就应该被暴露出来。例如,一个插件中的某个类实现了INavigationWidgetFactory接口,并且暴露出来,那么 Core 就会自动把这个类提供的组件当做导航组件显示出来”
注意,在initialize()函数中,我们创建了一个INavigationWidgetFactory实现的实例,然后将其添加到对象池中。一旦对象被添加到对象池,ExtensionSystem::PluginManager就会发出objectAdded()信号;该信号由 Qt Creator 核心监听。一旦核心获得这个信号,它就会利用我们提供的INavigationWidgetFactory接口的实现,将其添加到导航器面板。
qt plugin
https://blog.csdn.net/libaineu2004/article/details/89407333?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param
https://blog.csdn.net/libaineu2004/article/details/89439772
http://blog.davidecoppola.com/2019/12/how-to-create-a-qt-creator-plugin/
git clone git://code.qt.io/qt-creator/qt-creator.git
在Qt5中,导出plugin使用Q_PLUGIN_METADATA宏,
How to Create Qt Plugins
1. 写一个插件的步骤:
(1)定义一个接口类,使用Q_DECLARE_INTERFACE宏来告诉Qt元系统存在这么个接口;
注:Qt文档中说用于继承的基类接口必须为接口类(只包含纯虚函数),但是试了一下,同时包含虚函数和纯虚函数的抽象类也是可以作为基类的...大概是因为基类中的虚函数也可以实现用基类的指针调用子类中重写的这个函数,如果是普通函数,应该也可以在接口中存在,毕竟抽象类中也是可以有普通函数的,但是就没什么作用了,因为应用程序使用的是插件中重写的方法,而非基类本身的方法,但是为了尊重文档,这里统一叫做接口类。
(2)声明一个插件类,该插件类继承自QObject和上一步定义的接口类;
(3)使用Q_INTERFACES宏将该接口类告诉Qt元系统;
(4)使用Q_PLUGIN_METADATA宏导出该插件类;
(5)生成dll;
INCLUDEPATH *= \
$$PWD/cpp/
bool firecat_ToolbarPlugin::initialize(const QStringList &arguments, QString *errorString)
{
// Register objects in the plugin manager's object pool
// Load settings
// Add actions to menus
// Connect to other plugins' signals
// In the initialize function, a plugin can be sure that the plugins it
// depends on have initialized their members.
Q_UNUSED(arguments)
Q_UNUSED(errorString)
//我们把RunWithoutDeploy这个方法提携到工具栏,方便使用
const char id1[] = "ProjectExplorer.RunWithoutDeploy";//这个id对应的是Qt Creator源码的const char RUNWITHOUTDEPLOY[]
QAction *act1 = Core::ActionManager::command(id1)->action();//对应Qt Creator源码的m_runWithoutDeployAction
if (act1 == NULL)
{
return false;
}
const Utils::Icon CLASSIC1(":/image/mode_run.png");//32位图片,34*34像素
const Utils::Icon FLAT1({{":/image/mode_run_mask.png", Utils::Theme::IconsRunToolBarColor}});//8位图片,34*34像素
const Utils::Icon FLAT_ACTIVE1({{":/image/mode_run_mask.png", Utils::Theme::IconsModeWelcomeActiveColor}});
act1->setIcon(Utils::Icon::modeIcon(CLASSIC1, FLAT1, FLAT_ACTIVE1));
//act1->setIcon(Utils::Icon::sideBarIcon(CLASSIC1, FLAT1));
act1->setVisible(true);
Core::ModeManager::addAction(act1, 130);
//我们把DebugWithoutDeploy这个方法提携到工具栏,方便使用
const char id2[] = "Debugger.DebugWithoutDeploy";
QAction *act2 = Core::ActionManager::command(id2)->action();//对应Qt Creator源码的m_debugWithoutDeployAction
if (act2 == NULL)
{
return false;
}
const Utils::Icon CLASSIC2(":/image/mode_debug.png");
const Utils::Icon FLAT2({{":/image/mode_debug_mask.png", Utils::Theme::IconsRunToolBarColor}});
const Utils::Icon FLAT_ACTIVE2({{":/image/mode_debug_mask.png", Utils::Theme::IconsModeWelcomeActiveColor}});
act2->setIcon(Utils::Icon::modeIcon(CLASSIC2, FLAT2, FLAT_ACTIVE2));
//act2->setIcon(Utils::Icon::sideBarIcon(CLASSIC2, FLAT2));
act2->setVisible(true);
Core::ModeManager::addAction(act2, 120);
//我们把微软计算器提携到工具栏,方便使用
#if defined(Q_OS_WIN32)
QAction *act3 = new QAction(tr("calc"), this);
const Utils::Icon CLASSIC3(":/image/mode_calc.png");
const Utils::Icon FLAT3({{":/image/mode_calc_mask.png", Utils::Theme::IconsRunToolBarColor}});
const Utils::Icon FLAT_ACTIVE3({{":/image/mode_calc_mask.png", Utils::Theme::IconsModeWelcomeActiveColor}});
act3->setIcon(Utils::Icon::modeIcon(CLASSIC3, FLAT3, FLAT_ACTIVE3));
//act3->setIcon(Utils::Icon::sideBarIcon(CLASSIC3, FLAT3));
act3->setVisible(true);
//QStandardPaths::standardLocations(QStandardPaths::DesktopLocation);//Qt自身没有提供System32的路径
wchar_t szPath[MAX_PATH] ={0};
GetSystemDirectory(szPath, MAX_PATH);
QString path = QString::fromWCharArray(szPath);
connect(act3, &QAction::triggered, this, [=]() {
QProcess *poc = new QProcess;
poc->start(path + "\\calc.exe");//即"C:\\Windows\\system32\\calc.exe"
});
Core::ModeManager::addAction(act3, 150);
#endif
// 因为Qt Creator源码有定义位置摆放的优先级
// Action priorities
//const int P_ACTION_RUN = 100;
//const int P_ACTION_BUILDPROJECT = 80;
//const int P_ACTION_DEBUG = 90; // Priority for the modemanager.
//ModeManager::addAction(cmd->action(), Constants::P_ACTION_RUN);
return true;