Core::IEditor
HtmlEditor
类实现了IEditor
接口。这个接口提供一个编辑器组件,用于编辑 HTML 文件。我们还需要将一个HtmlFile
实例与其关联起来:
#ifndef HTMLEDITOR_H #define HTMLEDITOR_H #include <coreplugin/editormanager/ieditor.h> struct HtmlEditorData; class QToolBar; class HtmlEditorWidget; class HtmlFile; namespace HtmlEditorConstants { const char* const C_HTMLEDITOR_MIMETYPE = "text/html"; const char* const C_HTMLEDITOR = "HTML Editor"; }; class HtmlEditor : public Core::IEditor { Q_OBJECT public: HtmlEditor(HtmlEditorWidget* editorWidget); ~HtmlEditor(); bool createNew(const QString& /*contents*/ = QString()); QString displayName() const; QString id() const { return HtmlEditorConstants::C_HTMLEDITOR; } IEditor* duplicate(QWidget* /*parent*/); bool duplicateSupported() const; Core::IFile* file(); bool isTemporary() const; const char* kind() const; bool open(const QString& fileName = QString()); bool restoreState(const QByteArray& /*state*/); QByteArray saveState() const; void setDisplayName(const QString &title); QWidget* toolBar(); QWidget* widget(); Core::Context context() const; protected slots: void slotTitleChanged(const QString& title) { setDisplayName(title); } private: HtmlEditorData* d; }; struct HtmlEditorData { HtmlEditorData() : editorWidget(0), file(0) { } HtmlEditorWidget* editorWidget; QString displayName; HtmlFile* file; Core::Context context; }; #endif // HTMLEDITOR_H
HtmlEditorData
保存一个HtmlEditorWidget
对象和一个HtmlFile
对象。displayName
属性用于显示该文档的可视化描述:
struct HtmlEditorData { HtmlEditorData() : editorWidget(0), file(0) { } HtmlEditorWidget* editorWidget; QString displayName; HtmlFile* file; Core::Context context; };
构造函数用于初始化HtmlEditorWidget
实例。同时,它还创建一个HtmlFile
实例,这样就可以将其与HtmlEditor
和 widget 关联起来:
HtmlEditor::HtmlEditor(HtmlEditorWidget* editorWidget) : Core::IEditor(editorWidget) { d = new HtmlEditorData; d->editorWidget = editorWidget; d->file = new HtmlFile(this, editorWidget); d->context = Core::Context(HtmlEditorConstants::C_HTMLEDITOR); connect(d->editorWidget, SIGNAL(contentModified()), d->file, SLOT(modified())); connect(d->editorWidget, SIGNAL(titleChanged(QString)), SLOT(slotTitleChanged(QString))); connect(d->editorWidget, SIGNAL(contentModified()), SIGNAL(changed())); }
析构函数不作任何操作,仅仅删除 d 指针:
HtmlEditor::~HtmlEditor() { delete d; }
下面是一些不需要解释的函数:
QWidget* HtmlEditor::widget() { return d->editorWidget; } Core::Context HtmlEditor::context() const { return d->context; } Core::IFile* HtmlEditor::file() { return d->file; }
createNew()
函数用于重新设置HtmlEditorWidget
的内容以及HtmlFile
对象。现在,我们只是简单地忽略contents
参数:
bool HtmlEditor::createNew(const QString& contents) { Q_UNUSED(contents); d->editorWidget->setContent(QByteArray()); d->file->setFilename(QString()); return true; }
open()
函数请求HtmlFile
打开一个给定文件名的文件。它假设filename
就是一个 HTML 文件的名字:
bool HtmlEditor::open(const QString &fileName) { return d->file->open(fileName); }
下面的函数则用于返回编辑器的“类型”:
namespace HtmlEditorConstants { const char* const C_HTMLEDITOR_MIMETYPE = "text/html"; const char* const C_HTMLEDITOR = "HTML Editor"; }; // ...... const char* HtmlEditor::kind() const { return HtmlEditorConstants::C_HTMLEDITOR; }
displayName()
函数返回的字符串用于显示在打开文件列表中。下面的函数帮助设置和获取这个显示的名字:
QString HtmlEditor::displayName() const { return d->displayName; } void HtmlEditor::setDisplayName(const QString& title) { if(d->displayName == title) return; d->displayName = title; emit changed(); }
下面几个函数仅仅是为了给出纯虚函数的一个默认实现,在我们这个简单的例子中不作任何操作:
bool HtmlEditor::duplicateSupported() const { return false; } Core::IEditor* HtmlEditor::duplicate(QWidget* parent) { Q_UNUSED(parent); return 0; } QByteArray HtmlEditor::saveState() const { return QByteArray(); } bool HtmlEditor::restoreState(const QByteArray& state) { Q_UNUSED(state); return false; } QWidget* HtmlEditor::toolBar() { return 0; } bool HtmlEditor::isTemporary() const { return false; }
Core::IEditorFactory
HtmlEditorFactory
实现了Core::IEditorFactory
接口:
#ifndef HTMLEDITORFACTORY_H #define HTMLEDITORFACTORY_H #include <coreplugin/editormanager/ieditorfactory.h> #include "HtmlEditor.h" struct HtmlEditorFactoryData; class HtmlEditorPlugin; class HtmlEditorFactory : public Core::IEditorFactory { Q_OBJECT public: HtmlEditorFactory(HtmlEditorPlugin* owner); ~HtmlEditorFactory(); QStringList mimeTypes() const; QString kind() const; Core::IEditor* createEditor(QWidget* parent); Core::IFile* open(const QString &fileName); QString id() const { return QString("HTML Editor Factory ID"); } QString displayName() const { return QString("HTML Editor Factory"); } private: HtmlEditorFactoryData* d; }; struct HtmlEditorFactoryData { HtmlEditorFactoryData() : kind(HtmlEditorConstants::C_HTMLEDITOR) { mimeTypes << QString(HtmlEditorConstants::C_HTMLEDITOR_MIMETYPE); } QString kind; QStringList mimeTypes; }; #endif // HTMLEDITORFACTORY_H
HtmlEditorFactoryData
用于保存HtmlEditorFactory
类的私有成员变量。注意,构造函数将其 mime-types 初始化为HtmlEditorConstants::C_HTMLEDITOR_MYMETYPE
;同时,我们也设置了 editor 的类型,这个类型同前面所说的HtmlEditor
的类型是一致的:
struct HtmlEditorFactoryData { HtmlEditorFactoryData() : kind(HtmlEditorConstants::C_HTMLEDITOR) { mimeTypes << QString(HtmlEditorConstants::C_HTMLEDITOR_MIMETYPE); } QString kind; QStringList mimeTypes; };
下面几个函数则无需过多解释:
HtmlEditorFactory::HtmlEditorFactory(HtmlEditorPlugin* owner) :Core::IEditorFactory(owner) { d = new HtmlEditorFactoryData; } HtmlEditorFactory::~HtmlEditorFactory() { delete d; } QStringList HtmlEditorFactory::mimeTypes() const { return d->mimeTypes; } QString HtmlEditorFactory::kind() const { return d->kind; }
还记得我们前面说过,IFile
与IEditor
是关联在一起的。open()
函数就是返回正在处理这个文件名指定的IFile
实例。如果没有,则会创建一个新的编辑器用于处理这个文件,同时将IFile
返回。如果要全部理解这个过程,可以查阅Core::EditorManager::openEditor()
函数的实现:
Core::IFile* HtmlEditorFactory::open(const QString& fileName) { Core::EditorManager* em = Core::EditorManager::instance(); Core::IEditor* iface = em->openEditor(fileName, d->kind); return iface ? iface->file() : 0; }
下面的函数用于创建和返回HtmlEditor
实例:
Core::IEditor* HtmlEditorFactory::createEditor(QWidget* parent) { HtmlEditorWidget* editorWidget = new HtmlEditorWidget(parent); return new HtmlEditor(editorWidget); }
实现插件
在前面的章节中,我们已经知道了实现插件的方法。现在我们使用和前面一样的方法实现HtmlEditorPlugin
插件类。唯一的区别是initialize()
函数的实现:
bool HtmlEditorPlugin::initialize(const QStringList& args, QString *errMsg) { Q_UNUSED(args); Core::ICore* core = Core::ICore::instance(); Core::MimeDatabase* mdb = core->mimeDatabase(); if(!mdb->addMimeTypes("text-html-mimetype.xml", errMsg)) return false; addAutoReleasedObject(new HtmlEditorFactory(this)); return true; }
最后,按照我们前面所写的过程去编译吧!
附件下载:HtmlEditor 插件文件
8 评论
你好,我想用Qt creator的plugin framework自己写一个软件,Coreplugin要自己定制,其他的功能用插件实现,但是程序不能启动,可以指点下吗,thanks!
具体也不大清楚,只能看看再说啦~
目前是否有剥离好的 plugin framework?
qt creator 采用的是 LGPL 许可,直接使用这样的源码做闭源的商业软件是否侵权?
或者,我将采用此框架的软件同样基于 LGPL 许可发布,那么为这个软件开发的插件是否可以闭源?
目前是否有剥离好的 plugin framework?
-- 没有,至少官方没有。如果需要只能自己处理,或者自己重新实现。
qt creator 采用的是 LGPL 许可,直接使用这样的源码做闭源的商业软件是否侵权?
-- “直接”使用,我是说“直接”,也就是把 LGPL 的代码直接放进你自己的闭源代码中,这是不允许的。但是,LGPL 没有那么严格,我们可以自己创建一层 wrapper,那么,只要把这层 wrapper 开源,而调用 wrapper 的闭源代码不需要开源。
你好,我在编译附件文件时遇到下面错误,不知是什么原因,麻烦给瞧下,谢谢。
HtmlEditor.cpp: In constructor 'HtmlEditor::HtmlEditor(HtmlEditorWidget*)':
HtmlEditor.cpp:11:46: error: cannot allocate an object of abstract type 'HtmlFile'
HtmlFile.h:13:7: note: because the following virtual functions are pure within 'HtmlFile':
..\..\qt-creator\src\plugins/coreplugin/ifile.h:87:18: note: virtual bool Core::IFile::save(QString*, const QString&, bool)
..\..\qt-creator\src\plugins/coreplugin/ifile.h:100:18: note: virtual bool Core::IFile::reload(QString*, Core::IFile::ReloadFlag, Core::IFile::ChangeType)
mingw32-make.exe[1]: *** [debug/HtmlEditor.o] Error 1
请注意 Qt Creator 的版本。现在 Qt Creator 的代码很不稳定。文章中使用的是 2.2.1,最新版 2.4 中就增加了新的纯虚函数。所以如果你要给其他版本的 Qt Creator 编写插件,需要自行修改相关代码。
您好,我用的QT版本是5.7。我用的QT中没有wibkit或webkitwidget。在QT5.7中应该用什么代替呢
Qt 5.7 使用的是新的 webengine 模块