Part 07 项目视图(基本的M-V架构类)(Qt)
——2012.02.17
0. 本次学习Qt时主要方法:分析代码,理清原代码思路,摘录(修改)代码,编写读书笔记。
1. 编写学习笔记主要形式:展示程序功能,介绍类特点,展示程序代码(注释带思路)。
2. 主要参考学习资料: Qt Assistant与Qt学习之路(42~44)(豆子空间)。
3. 本Part内容:了解项目视图的M-V架构使用的基本使用方法,知道几个常用的关于M-V架构的类。
附:本次主要要使用到的类的类继承关系图
013 Program –stringListView
01. 展示程序功能
如图所示,该程序可完成一般的添加删除显示数据的功能:
当插入按钮被点击后,程序会在选中行的上方插入一行,然后,会提示用户输入需要插入的数据,之后,待按确定后,新插入的数据就会显示在表单中,另外,如果想修改数据,还可以直接双击数据,然后,直接输入对其进行修改。
当删除按钮被点击后,程序会删除用户选定的一行,同时在表单中显示执行删除操作后的数据表单。
当Show按钮被点点后,程序会以QMessageBox的样式显示当前表单的数据。
02. 介绍类的特点
0. class QStringListModel与 class QListView.
1. 引自Qt Assistant(V4.8):#include <QStringListModel>
The QStringListModel class provides a model that supplies strings to views.
QStringListModel is an editable model that can be used for simple cases where you need to display a number of strings in a view widget, such as aQListView or a QComboBox.
The model provides all the standard functions of an editable model, representing the data in the string list as a model with one column and a number of rows equal to the number of items in the list.
Model indexes corresponding to items are obtained with the index() function, and item flags are obtained with flags(). Item data is read with thedata() function and written with setData(). The number of rows (and number of items in the string list) can be found with the rowCount() function.
The model can be constructed with an existing string list, or strings can be set later with the setStringList() convenience function. Strings can also be inserted in the usual way with the insertRows() function, and removed with removeRows(). The contents of the string list can be retrieved with thestringList() convenience function.
2. 引自Qt Assistant(V4.8):#include <QListView>
The QListView class provides a list or icon view onto a model.
A QListView presents items stored in a model, either as a simple non-hierarchical list, or as a collection of icons. This class is used to provide lists and icon views that were previously provided by the QListBox and QIconView classes, but using the more flexible approach provided by Qt's model/view architecture.
The QListView class is one of the Model/View Classes and is part of Qt's model/view framework.
This view does not display horizontal or vertical headers; to display a list of items with a horizontal header, use QTreeView instead.
QListView implements the interfaces defined by the QAbstractItemView class to allow it to display data provided by models derived from theQAbstractItemModel class.
Items in a list view can be displayed using one of two view modes: In ListMode, the items are displayed in the form of a simple list; in IconMode, the list view takes the form of an icon view in which the items are displayed with icons like files in a file manager. By default, the list view is in ListMode. To change the view mode, use the setViewMode() function, and to determine the current view mode, use viewMode().
Items in these views are laid out in the direction specified by the flow() of the list view. The items may be fixed in place, or allowed to move, depending on the view's movement() state.
If the items in the model cannot be completely laid out in the direction of flow, they can be wrapped at the boundary of the view widget; this depends on isWrapping(). This property is useful when the items are being represented by an icon view.
The resizeMode() and layoutMode() govern how and when the items are laid out. Items are spaced according to their spacing(), and can exist within a notional grid of size specified by gridSize(). The items can be rendered as large or small icons depending on their iconSize().
03. 程序代码
// main.cpp
#include "stringlistview.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
stringListView w;
w.show();
return a.exec();
}
// stringlistview.h
#ifndef STRINGLISTVIEW_H
#define STRINGLISTVIEW_H
#include
class QStringListModel;
class QListView;
class stringListView : public QWidget
{
Q_OBJECT
public:
stringListView(QWidget *parent = 0, Qt::WFlags flags = 0);
~stringListView();
private:
QStringListModel * model;
QListView * listView;
private slots:
void insertData();
void deleteData();
void showData();
};
#endif // STRINGLISTVIEW_H
// stringlistview.cpp
#include "stringlistview.h"
#include
#include
#include
#include
#include
#include
// 构造函数
stringListView::stringListView(QWidget *parent, Qt::WFlags flags): QWidget(parent, flags)
{
// 初始化私有成员 - QStringListModel * model;
model = new QStringListModel(this);
// 往model里面添加数据
QStringList data;
data <<"Letter A" <<"Letter B" <<"Letter C";
model -> setStringList(data);
// 将model与view相关联,初始化私有成员 - QListView * listView
listView = new QListView(this);
listView -> setModel(model);
// 创建基本按钮以响应用户操作
QPushButton * insertBtn = new QPushButton(tr("Insert"), this);
QPushButton * delBtn = new QPushButton(tr("Delete"), this);
QPushButton * showBtn = new QPushButton(tr("Show"), this);
// 布局
QHBoxLayout * btnLayout = new QHBoxLayout; // 子布局,三个按钮的布局
btnLayout -> addWidget(insertBtn);
btnLayout -> addWidget(delBtn);
btnLayout -> addWidget(showBtn);
QVBoxLayout * mainLayout = new QVBoxLayout(this);
mainLayout -> addWidget(listView);
mainLayout -> addLayout(btnLayout);
this -> setLayout(mainLayout); // 窗口设置
// 信号-槽,连接Button的动作
connect(insertBtn, SIGNAL(clicked()), this, SLOT(insertData()));
connect(delBtn, SIGNAL(clicked()), this, SLOT(deleteData()));
connect(showBtn, SIGNAL(clicked()), this, SLOT(showData()));
}
// 插入操作
void stringListView::insertData()
{
// 插入操作可以总结为:获取数据 -> 获取行 -> 插入行 -> 将数据加入插入行 -> 设置该行为可编辑
// 从新建的输入对话框中获得所需要插入的字符串
bool isOK;
QString text = QInputDialog::getText(NULL, "Insert", "Please input new data:", QLineEdit::Normal, "You are inserting new data.", &isOK);
if(isOK) // 当用户点击了OK按钮才开始执行以下操作
{
// QModelIndex QAbstractItemView::currentIndex () const // Returns the model index of the current item.
// QModelIndex: QAbstractItemModel provides a hierarchical tree of data,
// whereas QML only operates on list data. This function assists in using tree models in QML.
// 另外,注意,此时只要知道QModelIndex保存了三个重要数据:行、列以及属于哪个model就行了。
// 使用listView来判断行数是因为这样可以判断用户所选择的当前行,从当前行前执行插入数据的操作
int row = listView -> currentIndex().row();
// 在第row行的前面插入一行(所谓1就是指1列(因为我们使用list是一维的,列数永远是1))
model -> insertRows(row, 1);
// 然后我们使用model的index()函数获取当前行的QModelIndex对象(即刚刚新建的那一行的“下标”)
QModelIndex index = model -> index(row);
// 使用setData插入新建的字符串对象,以上两步操作可以省略,此处只为演示
model -> setData(index, text);
listView -> setCurrentIndex(index);
// 使新插入的这一行可以被编缉
listView -> edit(index);
}
return;
}
// 删除操作
void stringListView::deleteData()
{
if(model -> rowCount() > 1)
{
// 直接调用删除行的函数即可实现功能,如果将其所有行清空,那么就不能再插入数据了,这也是该程序的缺憾
model -> removeRows(listView -> currentIndex().row(), 1);
}
return;
}
// 展示操作
void stringListView::showData()
{
// QStringList QStringListModel::stringList () const
// Returns the string list used by the model to store data.
QStringList data = model -> stringList();
QString str;
foreach(QString s, data) // 遍历QStringList并将加入到str对象中。(此处遍历为的是整理字符串的格式)
{
str += s + "\n";
}
QMessageBox::information(this, "Data", str);
return;
}
stringListView::~stringListView()
{
}
014 Program –QDirModel
01. 展示程序功能
该程序能完成创建文件夹,浏览,删除文件夹及文件的功能。
当点击“CreateDirectory”按钮时,将会从选中文件夹下创建一个新的文件夹,当遇上重名的情况时,程序将会给出错误提示,创建操作结束后,用户可以从该软件主窗口中浏览当前的文件夹情况。
当点击“Remove”按钮时,将会直接删除选中的文件或文件夹。
02. 介绍类的特点
0. class QDirModel与 class QTreeView.
1. 引自Qt Assistant(V4.8):#include <QDirModel>
The QDirModel class provides a data model for the local filesystem.
The usage of QDirModel is not recommended anymore. The QFileSystemModel class is a more performant alternative.
This class provides access to the local filesystem, providing functions for renaming and removing files and directories, and for creating new directories. In the simplest case, it can be used with a suitable display widget as part of a browser or filer.
QDirModel keeps a cache with file information. The cache needs to be updated with refresh().
QDirModel can be accessed using the standard interface provided by QAbstractItemModel, but it also provides some convenience functions that are specific to a directory model. The fileInfo() and isDir() functions provide information about the underlying files and directories related to items in the model.
Directories can be created and removed using mkdir(), rmdir(), and the model will be automatically updated to take the changes into account.
Note: QDirModel requires an instance of a GUI application.
See also nameFilters(), setFilter(), filter(), QListView, QTreeView, QFileSystemModel, Dir View Example, and Model Classes.
2. 引自Qt Assistant(V4.8):#include < QTreeView>
The QTreeView class provides a default model/view implementation of a tree view.
A QTreeView implements a tree representation of items from a model. This class is used to provide standard hierarchical lists that were previously provided by the QListView class, but using the more flexible approach provided by Qt's model/view architecture.
The QTreeView class is one of the Model/View Classes and is part of Qt's model/view framework.
QTreeView implements the interfaces defined by the QAbstractItemView class to allow it to display data provided by models derived from theQAbstractItemModel class.
03. 程序代码
// main.cpp
#include "dirmodel.h"
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
dirModel w;
w.setWindowIcon(QIcon(":/dirModel/Resources/main.png"));
w.show();
return a.exec();
}
// dirmodel.h
#ifndef DIRMODEL_H
#define DIRMODEL_H
#include
class QDirModel;
class QTreeView;
class dirModel : public QWidget
{
Q_OBJECT
public:
dirModel(QWidget *parent = 0, Qt::WFlags flags = 0);
~dirModel();
private:
QDirModel * model;
QTreeView * treeView;
private slots:
void mkdir();
void rm();
};
#endif // DIRMODEL_H
// dirmodel.cpp
#include "dirmodel.h"
#include
#include
#include
#include
#include
#include
#include
dirModel::dirModel(QWidget *parent, Qt::WFlags flags): QWidget(parent, flags)
{
// 初始化私有成员 QDirModel * model 及相关属性设置
model = new QDirModel;
model -> setReadOnly(false); // 非只读,即可更改
model -> setSorting(QDir::DirsFirst | QDir::IgnoreCase | QDir::Name); // 设置排序依据,文件夹优先,忽略大小写,根据名字排序
// 初始化私有成员 QTreeView * treeView 及相关属性设置
treeView = new QTreeView;
treeView -> setModel(model);
// 下面注意 #include
// stretchLastSection : bool
// This property holds whether the last visible section in the header takes up all the available space.
// The default value is false.
// Note: The horizontal headers provided by QTreeView are configured with this property set to true,
// ensuring that the view does not waste any of the space assigned to it for its header.
// If this value is set to true, this property will override the resize mode set on the last section in the header.
// 当QTreeView的宽度大于所有的列宽之和时,最后一列的宽度自动扩展以充满最后的边界;否则就让最后一列的宽度保持原始大小。
treeView -> header() -> setStretchLastSection(true);
// 设置按哪一列进行排序,传递参数为0,也就是说是第一列。
treeView -> header() -> setSortIndicator(0, Qt::AscendingOrder);
treeView -> header() -> setSortIndicatorShown(true); // 设置显示列头上面的排序小箭头
// 允许鼠标点击列头
treeView -> header() -> setClickable(true);
QModelIndex index = model -> index(QDir::currentPath()); // 获取当前exe文件运行时路径,并把这个路径当成程序启动时显示的路径
treeView -> expand(index); // 展开这一路径
treeView -> scrollTo(index); // 把视口滚动到这个路径的位置
treeView -> resizeColumnToContents(0); // 把列头适应内容的宽度,也就是说不产生...符号
// 创建按钮
QPushButton * createBtn = new QPushButton(tr("Create Directory"));
QPushButton * delBtn = new QPushButton(tr("Remove"));
// 布局
QHBoxLayout * btnLayout = new QHBoxLayout;
btnLayout -> addWidget(createBtn);
btnLayout -> addWidget(delBtn);
QVBoxLayout * mainLayout = new QVBoxLayout(this);
mainLayout -> addWidget(treeView);
mainLayout -> addLayout(btnLayout);
this -> setLayout(mainLayout);
// 信号/槽,将其与按钮连接
connect(createBtn, SIGNAL(clicked()), this, SLOT(mkdir()));
connect(delBtn, SIGNAL(clicked()), this, SLOT(rm()));
}
void dirModel::mkdir() // 创建文件夹
{
QModelIndex index = treeView -> currentIndex();
if(!index.isValid()) // 若无已选择的目录,则此路径为非法的
{
return;
}
QString dirName = QInputDialog::getText(this, tr("Create Directory"), tr("Directory name"));
if(!dirName.isEmpty()) // 创建失败时,会弹出提示
{
if(! model -> mkdir(index, dirName).isValid())
{
QMessageBox::information(this, tr("Create Directory"), tr("Failed to create the directory"));
}
}
return;
}
void dirModel::rm() // 删除文件夹
{
QModelIndex index = treeView -> currentIndex();
if(!index.isValid()) // 判断是否选中
{
return;
}
bool ok;
if(model -> fileInfo(index).isDir())
{
ok = model -> rmdir(index);
}
else
{
ok = model -> remove(index);
}
if (!ok)
{
QMessageBox::information(this, tr("Remove"), tr("Failed to remove %1").arg(model -> fileName(index)));
}
return;
}
dirModel::~dirModel()
{
}
015 Program –QSortFilterProxyModel
01. 展示程序功能
该程序可起过滤的作用,图中的表单内容是关于颜色的英文单词,在syntax的ComboBox能选中三种筛选单词的方式,在Filter中输入需要过滤的关键字。
02. 介绍类的特点
1. #include < QSortFilterProxyModel >
The QSortFilterProxyModel class provides support for sorting and filtering data passed between another model and a view.(也就是,它必须要依赖一个model或者view才能使用)
QSortFilterProxyModel can be used for sorting items, filtering out items, or both. The model transforms the structure of a source model by mapping the model indexes it supplies to new indexes, corresponding to different locations, for views to use. This approach allows a given source model to be restructured as far as views are concerned without requiring any transformations on the underlying data, and without duplicating the data in memory.
03. 程序代码
// main.cpp
#include "sortview.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
sortView w;
w.show();
return a.exec();
}
// sortview.h
#ifndef SORTVIEW_H
#define SORTVIEW_H
#include
class QListView;
class QStringListModel;
class QSortFilterProxyModel;
class QComboBox;
class sortView : public QWidget
{
Q_OBJECT
public:
sortView(QWidget *parent = 0, Qt::WFlags flags = 0);
~sortView();
private:
QListView * view;
QStringListModel * model;
QSortFilterProxyModel * modelProxy;
QComboBox * syntaxBox;
private slots:
void filterChanged(QString text);
};
#endif // SORTVIEW_H
// sortview.cpp
#include "sortview.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
sortView::sortView(QWidget *parent, Qt::WFlags flags): QWidget(parent, flags)
{
// 初始化QStringListModel对象
model = new QStringListModel(QColor::colorNames(), this);
// 初始化QSortFilterProxyModel对象
modelProxy = new QSortFilterProxyModel(this);
modelProxy -> setSourceModel(model); // 将model包含进QSortFilterProxyModel中
modelProxy -> setFilterKeyColumn(0); // 设定需要过滤的列数,第一列
// 初始化QListView对象
view = new QListView(this); // 将QsortFilterProxyModel包含进QListView中
view -> setModel(modelProxy);
// 创建按钮,编辑栏
QLineEdit * filterInput = new QLineEdit;
QLabel * filterLabel = new QLabel(tr("Filter"));
QLabel * syntaxLabel = new QLabel(tr("Syntax"));
syntaxBox = new QComboBox;
// 设置QComboBox的格式
syntaxBox -> setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
// 最一般的正则表达式语法,不过这个语法不支持贪婪限定符
syntaxBox -> addItem(tr("Regular expression"), QRegExp::RegExp);
// Unix下Shell的常见的一种规则
syntaxBox -> addItem(tr("Wildcard"), QRegExp::Wildcard);
// 固定表达式
syntaxBox -> addItem(tr("Fixed string"), QRegExp::FixedString);
// 布局
QHBoxLayout * filterLayout = new QHBoxLayout;
filterLayout -> addWidget(filterLabel);
filterLayout -> addWidget(filterInput);
QHBoxLayout * syntaxLayout = new QHBoxLayout;
syntaxLayout -> addWidget(syntaxLabel);
syntaxLayout -> addWidget(syntaxBox);
QVBoxLayout * layout = new QVBoxLayout(this);
layout -> addWidget(view);
layout -> addLayout(filterLayout);
layout -> addLayout(syntaxLayout);
connect(filterInput, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
}
void sortView::filterChanged(QString text)
{
// 通过私有成员QComoboBox * syntaxBox,创得QRegExp::PatternSyntax对象
QRegExp::PatternSyntax syntax = QRegExp::PatternSyntax(syntaxBox -> itemData(syntaxBox -> currentIndex()).toInt());
// 构建正则表达式
QRegExp regExp(text, Qt::CaseInsensitive, syntax);
// 设置proxy的过滤器表达式
modelProxy -> setFilterRegExp(regExp);
return;
}
sortView::~sortView()
{
}