下面,我们来开始进行 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编程我发现的确还是英文资料更多一点