QXmlStream Bookmarks Example翻译
原创
©著作权归作者所有:来自51CTO博客作者zz_yun的原创作品,请联系作者获取转载授权,否则将追究法律责任
QXmlStream Bookmarks 例子提供一个使用QXmlStreamReader类读和使用QXmlStreamWriter写的XBEL(XML Bookmark Exchange Language)文件阅读器.
XbelWriter类定义
该类包含一个私有的QXmlStreamWriter实例,它提供一个XML写功能。XbelWriter也包含一个存储书签的QTreeWidget。
class XbelWriter
{
public:
XbelWriter(QTreeWidget *treeWidget);
bool writeFile(QIODevice *device);
private:
void writeItem(QTreeWidgetItem *item);
QXmlStreamWriter xml;
QTreeWidget *treeWidget;
};
XbelWriter类实现:
该类构造器接受一个treeWidget来初始化。我们能用他的自动格式化特性来确保断行。首行缩进被自动增加来分割元素,增加数据的可读性。
XbelWriter::XbelWriter(QTreeWidget *treeWidget)
: treeWidget(treeWidget)
{
xml.setAutoFormatting(true);
}
writeFile()函数接受一个QIODevice对象,使用setDevice()来设置。函数写 文件类型定义(DTD),开始元素,版本,treeWidget的顶层元素。
bool XbelWriter::writeFile(QIODevice *device)
{
xml.setDevice(device);
xml.writeStartDocument();
xml.writeDTD("<!DOCTYPE xbel>");
xml.writeStartElement("xbel");
xml.writeAttribute("version", "1.0");
for (int i = 0; i < treeWidget->topLevelItemCount(); ++i)
writeItem(treeWidget->topLevelItem(i));
xml.writeEndDocument();
return true;
}
writeItem()函数接受一个QTreeWidgetItem对象,写他到流中,依赖他的tagName,它既可以是一个文件夹、书签、或者分割线。
void XbelWriter::writeItem(QTreeWidgetItem *item)
{
QString tagName = item->data(0, Qt::UserRole).toString();
if (tagName == "folder") {
bool folded = !treeWidget->isItemExpanded(item);
xml.writeStartElement(tagName);
xml.writeAttribute("folded", folded ? "yes" : "no");
xml.writeTextElement("title", item->text(0));
for (int i = 0; i < item->childCount(); ++i)
writeItem(item->child(i));
xml.writeEndElement();
} else if (tagName == "bookmark") {
xml.writeStartElement(tagName);
if (!item->text(1).isEmpty())
xml.writeAttribute("href", item->text(1));
xml.writeTextElement("title", item->text(0));
xml.writeEndElement();
} else if (tagName == "separator") {
xml.writeEmptyElement(tagName);
}
}
XbelReader类定义
该类包含一个私有的QXmlStreamReader实例,QXmlStreamWriter的伴随类。XbelReader也包含一个QTreeWidget的引用,它通层次结构把书签分组。
class XbelReader
{
public:
XbelReader(QTreeWidget *treeWidget);
bool read(QIODevice *device);
QString errorString() const;
private:
void readXBEL();
void readTitle(QTreeWidgetItem *item);
void readSeparator(QTreeWidgetItem *item);
void readFolder(QTreeWidgetItem *item);
void readBookmark(QTreeWidgetItem *item);
QTreeWidgetItem *createChildItem(QTreeWidgetItem *item);
QXmlStreamReader xml;
QTreeWidget *treeWidget;
QIcon folderIcon;
QIcon bookmarkIcon;
};
XbelReader类实现
构造器接受一个QTreeWidget来初始化treeWidget。一个QStyle对象被用来设置treeWidget的风格属性。folderIcon被设置为QIcon::Normal模式,pixmap只被显示当用户不影响icon。QStyle::SP_DirClosedIcon,QStyle::SP_DirOpenIcon,和SQtyle::SP_FileIcon符合标准的pixmap。
XbelReader::XbelReader(QTreeWidget *treeWidget)
: treeWidget(treeWidget)
{
QStyle *style = treeWidget->style();
folderIcon.addPixmap(style->standardPixmap(QStyle::SP_DirClosedIcon),
QIcon::Normal, QIcon::Off);
folderIcon.addPixmap(style->standardPixmap(QStyle::SP_DirOpenIcon),
QIcon::Normal, QIcon::On);
bookmarkIcon.addPixmap(style->standardPixmap(QStyle::SP_FileIcon));
}
read()函数接受一个QIODevice,并且使用setDevice()设置。只有当文件是一个有效的XBEL 1.0文件。注意XML输入需要完整的标准形式。否则,raiseError()函数被用来显示一个错误信息。因为XBEL阅读器只读XML元素,使用readNextStartElement()函数有广泛的应用。
bool XbelReader::read(QIODevice *device)
{
xml.setDevice(device);
if (xml.readNextStartElement()) {
if (xml.name() == "xbel" && xml.attributes().value("version") == "1.0")
readXBEL();
else
xml.raiseError(QObject::tr("The file is not an XBEL version 1.0 file."));
}
return !xml.error();
}
errorString()函数被调用如果一个错误发生,为了得到完整的包含行数和列数的错误描述。
QString XbelReader::errorString() const
{
return QObject::tr("%1\nLine %2, column %3")
.arg(xml.errorString())
.arg(xml.lineNumber())
.arg(xml.columnNumber());
}
readXBEL()函数读startElement的名字,调用合适的函数读它,依赖是否他是文件夹、书签或者分割线。否则,他调用skipCurrentElement()。Q_ASSERT()宏被用来提供一个函数的前提条件。
void XbelReader::readXBEL()
{
Q_ASSERT(xml.isStartElement() && xml.name() == "xbel");
while (xml.readNextStartElement()) {
if (xml.name() == "folder")
readFolder(0);
else if (xml.name() == "bookmark")
readBookmark(0);
else if (xml.name() == "separator")
readSeparator(0);
else
xml.skipCurrentElement();
}
}
readTitle()函数读书签的标题。
void XbelReader::readTitle(QTreeWidgetItem *item)
{
Q_ASSERT(xml.isStartElement() && xml.name() == "title");
QString title = xml.readElementText();
item->setText(0, title);
}
readSeparator()函数创造一个分割线并且设置他的标志。文本被设置为30“0xB7”。使用skipCurrentElement()跳过元素。
void XbelReader::readSeparator(QTreeWidgetItem *item)
{
Q_ASSERT(xml.isStartElement() && xml.name() == "separator");
QTreeWidgetItem *separator = createChildItem(item);
separator->setFlags(item->flags() & ~Qt::ItemIsSelectable);
separator->setText(0, QString(30, 0xB7));
xml.skipCurrentElement();
}
主窗口类定义
主窗口是QMainWindow的子类,带一个File按钮和help按钮
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
public slots:
void open();
void saveAs();
void about();
private:
void createActions();
void createMenus();
QTreeWidget *treeWidget;
QMenu *fileMenu;
QMenu *helpMenu;
QAction *openAct;
QAction *saveAsAct;
QAction *exitAct;
QAction *aboutAct;
QAction *aboutQtAct;
};
主窗口类实现
构造器例示QTreeWidget对象--treeWidget,并设置他的头使用QStringList对象--labels。构造器也唤醒createActions()和createMenus()来设置按钮。statusBar()被用来显示信息。
MainWindow::MainWindow()
{
QStringList labels;
labels << tr("Title") << tr("Location");
treeWidget = new QTreeWidget;
treeWidget->header()->setResizeMode(QHeaderView::Stretch);
treeWidget->setHeaderLabels(labels);
setCentralWidget(treeWidget);
createActions();
createMenus();
statusBar()->showMessage(tr("Ready"));
setWindowTitle(tr("QXmlStream Bookmarks"));
resize(480, 320);
}
open()函数使用户打开一个XBEL文件使用QFileDialog::getOpenFileName()。一个警告消息被显示如果文件不能被读或者有一个分析错误。
void MainWindow::open()
{
QString fileName =
QFileDialog::getOpenFileName(this, tr("Open Bookmark File"),
QDir::currentPath(),
tr("XBEL Files (*.xbel *.xml)"));
if (fileName.isEmpty())
return;
treeWidget->clear();
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
tr("Cannot read file %1:\n%2.")
.arg(fileName)
.arg(file.errorString()));
return;
}
XbelReader reader(treeWidget);
if (!reader.read(&file)) {
QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
tr("Parse error in file %1:\n\n%2")
.arg(fileName)
.arg(reader.errorString()));
} else {
statusBar()->showMessage(tr("File loaded"), 2000);
}
}
saveAs()函数显示一个QFileDialog,使用QFileDialog::getSaveFileName()提示用户输入文件名。与open()函数相似,这个函数也显示一个警告信息,如果文件不能被写。
void MainWindow::saveAs()
{
QString fileName =
QFileDialog::getSaveFileName(this, tr("Save Bookmark File"),
QDir::currentPath(),
tr("XBEL Files (*.xbel *.xml)"));
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
tr("Cannot write file %1:\n%2.")
.arg(fileName)
.arg(file.errorString()));
return;
}
XbelWriter writer(treeWidget);
if (writer.writeFile(&file))
statusBar()->showMessage(tr("File saved"), 2000);
}
about()函数显示一个QMessageBox。
void MainWindow::about()
{
QMessageBox::about(this, tr("About QXmlStream Bookmarks"),
tr("The <b>QXmlStream Bookmarks</b> example demonstrates how to use Qt's "
"QXmlStream classes to read and write XML documents."));
}
为了实现open(),saveAs(),exit()和aboutQt()函数,我们连接他们到一个QAction对象,增加他们到fileMenu和helpMenu。
void MainWindow::createActions()
{
openAct = new QAction(tr("&Open..."), this);
openAct->setShortcuts(QKeySequence::Open);
connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
saveAsAct = new QAction(tr("&Save As..."), this);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcuts(QKeySequence::Quit);
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
aboutAct = new QAction(tr("&About"), this);
connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
aboutQtAct = new QAction(tr("About &Qt"), this);
connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}
void MainWindow::createMenus()
{
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(openAct);
fileMenu->addAction(saveAsAct);
fileMenu->addAction(exitAct);
menuBar()->addSeparator();
helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
}
main()函数
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWin;
mainWin.show();
mainWin.open();
return app.exec();
}