下面,我们来开始进行 Qt Creator 的 HTML 编辑器的开发。首先来看一下我们的开发成果:
用户通过“文件->打开”菜单来选择一个 HTML 文件:
注意在打开文件对话框,我们已经可以找到 HTML 文件类型:
当我们选择一个 HTML 文件时,Qt Creator 会使用我们的编辑器进行显示:
注意,我们在编辑器底部添加了“Preview”和“Source”标签:
点击“Source”标签,则可以显示该页面的 HTML 代码:
用户可以在 source 视图编辑 HTML 文件,然后在 preview 视图预览。最后,用户可以通过保存命令将修改存盘。
为了实现上面所述功能,我们需要创建如下类:
类 | 接口/父类 | 描述 |
HtmlEditorWidget | QTabWidget | 提供具有两个标签的 tab widget,一个是 preview,一个是 source |
HtmlFile | Core::IFile | 实现IFile 接口,定义显示在HtmlEditorWidget 的文件 |
HtmlEditor | Core::IEditor | 实现IEditor 接口,用于管理HtmlEditorWidget ,同时将IFile 与HtmlEditorWidget 关联在一起 |
HtmlEditorFactory | Core::IEditorFactory | 实现IEditorFactory 接口,用于创建支持 text/html mime-type 的IEdtior 实例 |
HtmlEditorPlugin | Core::IPlugin | 实现IPlugin 接口,将上面所有的类同 Qt Creator 关联在一起 |
每一个 HTML 文件都会有一组HtmlEditorWidget
、HtmlFile
和HtmlEditor
的实例,用于实现加载文件、编辑和保存的功能。在我们的实现中,我们提供一种机制,将处理同一文件所需的各个类关联起来。
HtmlEditorWidget
默认情况下,Qt Creator 使用一个纯文本编辑器来显示 HTML 文件的内容。我们则要提供一个带有 tab 的编辑器,其中一个 tab 用于预览 HTML 文件,另一个则显示 HTML 源代码。我们的编辑器的类叫做HtmlEditorWidget
,它的声明如下:
#ifndef HTMLEDITORWIDGET_H #define HTMLEDITORWIDGET_H #include <QTabWidget> struct HtmlEditorWidgetData; class QWebView; class QPlainTextEdit; class HtmlEditorWidget : public QTabWidget { Q_OBJECT public: HtmlEditorWidget(QWidget* parent = 0); ~HtmlEditorWidget(); void setContent(const QByteArray& ba, const QString& path=QString()); QByteArray content() const; QString title() const; protected slots: void slotCurrentTabChanged(int tab); void slotContentModified(); signals: void contentModified(); void titleChanged(const QString&); private: HtmlEditorWidgetData* d; }; struct HtmlEditorWidgetData { QWebView *webView; QPlainTextEdit *textEdit; bool modified; QString path; }; #endif // HTMLEDITORWIDGET_H
构造函数的作用是使用两个类QWebView
和QPlainTextEdit
来创建不同的显示,然后将其添加到一个 tab widget 中:
HtmlEditorWidget::HtmlEditorWidget(QWidget* parent) :QTabWidget(parent) { d = new HtmlEditorWidgetData; d->webView = new QWebView; d->textEdit = new QPlainTextEdit; addTab(d->webView, tr("Preview")); addTab(d->textEdit, tr("Source")); setTabPosition(QTabWidget::South); setTabShape(QTabWidget::Triangular); d->textEdit->setFont(QFont("Courier", 12)); connect(this, SIGNAL(currentChanged(int)), SLOT(slotCurrentTabChanged(int))); connect(d->textEdit, SIGNAL(textChanged()), SLOT(slotContentModified())); connect(d->webView, SIGNAL(titleChanged(QString)), SIGNAL(titleChanged(QString))); d->modified = false; }
析构函数则什么都不做,除了将私有数据指针 d 释放掉:
HtmlEditorWidget::~HtmlEditorWidget() { delete d; }
setContent()
函数用于根据 HTML 文件设置 webView 和 textEdit 的内容:
void HtmlEditorWidget::setContent(const QByteArray& ba, const QString& path) { if(path.isEmpty()) d->webView->setHtml(ba); else d->webView->setHtml(QString(ba), QUrl("file:///" + path)); d->textEdit->setPlainText(ba); d->modified = false; d->path = path; }
content()
函数用于返回textEdit
的内容:
QByteArray HtmlEditorWidget::content() const { QString htmlText = d->textEdit->toPlainText(); return htmlText.toAscii(); }
title()
函数返回webView
的标题。这个标题将被显示在打开文件下拉框中:
QString HtmlEditorWidget::title() const { return d->webView->title(); }
我们在构造函数中使用connect()
函数关联了信号槽。第一个是使用户在点击切换 tab 的时候,预览窗口和源代码窗口能够保持同步:
connect(this, SIGNAL(currentChanged(int)), SLOT(slotCurrentTabChanged(int))); // .... void HtmlEditorWidget::slotCurrentTabChanged(int tab) { if(tab == 0 && d->modified) setContent(content(), d->path); }
第二个连接则用于保证用户编辑 HTML 源代码的时候,能够发出setContentModified()
信号。这个信号会在后面HtmlFile
类中使用到。看名字可以知道,这个信号用于通知文件内容的改变。
connect(d->textEdit, SIGNAL(textChanged()), SLOT(slotContentModified())); // .... void HtmlEditorWidget::slotContentModified() { d->modified = true; emit contentModified(); }
最后一个连接仅仅将 webView 的titleChanged()
信号转发出去。我们会在后面看到这个信号的作用。
5 评论
豆子老大,请教一下你这里的QWebView只有类的定义,类的实现在哪里?我似乎没看到,在附件里有么?
QWebView 是 QtWebKit 的一部分,使用的时候需要在 pro 文件中添加 QT += webkit 这么一行
oh,多谢,总是打扰您啊豆子老大,类似这些哪个库在哪个地方引用啥的有没有资料可以查的?除了自带的帮助外您一般上哪里查相关资料?
QtWebKit 是 Qt 自带的库,只需要配置下就可以了。至于资料,一般会去 google.com 查找,英文资料总会比中文的全一些
是,qt编程我发现的确还是英文资料更多一点