Qt5.11 / QML。我正在尝试创建两级QAbstractListModel
以在QML中进行查看。认为是文件夹(第一级)和文件(第二级)模型。
这是我的代码:
model.h
class File
{
public:
File(const QString name) { _name = name; }
QString name() const { return _name; }
void setName(const QString &name) { _name = name; }
QPixmap thumbnail() const { return _thumbnail; }
void setThumbnail(QPixmap thumbnail) { _thumbnail = thumbnail; }
private:
QString _name;
QPixmap _thumbnail;
};
class FilesModel : public QAbstractListModel
{
Q_OBJECT
public:
enum FileRoles
{
NameRole = Qt::UserRole + 1,
ThumbnailRole
};
FilesModel(QObject *parent = nullptr);
void addFile(const File &file);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
protected:
QHash<int, QByteArray> roleNames() const;
private:
QString _name;
QList<File> _listFiles;
};
class Folder
{
public:
Folder(const QString name);
QString name() const { return _name; }
void setName(const QString &name) { _name = name; }
FilesModel *model() { return _model; }
private:
QString _name;
FilesModel *_model;
};
class FolderModel : public QAbstractListModel
{
Q_OBJECT
public:
enum FolderRoles
{
NameRole = Qt::UserRole + 1,
ModelRole
};
FolderModel(QObject *parent = nullptr);
void addFolder(const Folder &folder);
void clear();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
Folder *findFolder(QString name);
FilesModel *filesModel(QString name);
protected:
QHash<int, QByteArray> roleNames() const;
bool removeRows(int row, int count, const QModelIndex &parent);
private:
QString _name;
QList<Folder> _list;
};
Q_DECLARE_METATYPE(FilesModel*)
model.cpp
FilesModel::FilesModel(QObject *parent) : QAbstractListModel(parent) { }
void FilesModel::addFile(const File &file)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
_listFiles << file;
endInsertRows();
}
int FilesModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return _listFiles.count();
}
QVariant FilesModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= _listFiles.count()) return QVariant();
const File &item = _listFiles[index.row()];
switch (role) {
case NameRole: return item.name(); break;
case ThumbnailRole: return item.thumbnail(); break;
default: return QVariant();
}
}
QHash<int, QByteArray> FilesModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[NameRole] = "name";
roles[ThumbnailRole] = "thumbnail";
return roles;
}
FolderModel::FolderModel(QObject *parent) : QAbstractListModel(parent) { }
void FolderModel::addFolder(const Folder &folder)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
_list << folder;
endInsertRows();
}
bool FolderModel::removeRows(int row, int count, const QModelIndex &parent)
{
if (count == 0) return false;
beginRemoveRows(parent, row, row + count - 1);
for (int i = 0; i < count; i++) _list.removeAt(row);
endRemoveRows();
emit dataChanged(this->index(row, 0), this->index(row, 0));
return true;
}
void FolderModel::clear()
{
removeRows(0, rowCount(), QModelIndex());
}
int FolderModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return _list.count();
}
QVariant FolderModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= _list.count()) return QVariant();
const Folder &item = _list[index.row()];
switch (role) {
case NameRole: return item.name(); break;
default: return QVariant();
}
}
Folder *FolderModel::findFolder(QString name)
{
for (int i = 0; i < _list.size(); i++)
{
if (_list[i].name() == name) return &_list[i];
}
return NULL;
}
FilesModel *FolderModel::filesModel(QString name)
{
Folder *folder = findFolder(name);
if (folder)
{
FilesModel *model = folder->model();
QQmlEngine::setObjectOwnership(model, QQmlEngine::CppOwnership);
return model;
}
return NULL;
}
QHash<int, QByteArray> FolderModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[NameRole] = "name";
roles[ModelRole] = "model";
return roles;
}
Folder::Folder(const QString name) : _name(name)
{
_model = new FilesModel();
}
main.cpp
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
MyApp myapp;
QQmlApplicationEngine qmlEngine;
qmlEngine.rootContext()->setContextProperty("MyModel", myapp.model());
qmlEngine.rootContext()->setContextProperty("MyApp", &myapp);
qmlEngine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (qmlEngine.rootObjects().isEmpty()) return -1;
return app.exec();
}
在MyApp.cpp中,我填充了一些项目:
FolderModel _model;
_model.addFolder(Folder("Folder1"));
_model.addFolder(Folder("Folder2"));
// ...
Folder *objFolder = _model.findFolder(folder);
objFolder->model()->addFile(File("File 1"));
objFolder->model()->addFile(File("File 2"));
QML代码主要基于Photo Viewer演示。 main.qml
ApplicationWindow {
id: mainWindow
visible: true
DelegateModel { id: albumVisualModel; model: MyModel; delegate: AlbumDelegate {} }
GridView {
id: albumView
width: parent.width
height: parent.height
cellWidth: 210
cellHeight: 220
model: albumVisualModel.parts.album
visible: albumsShade.opacity !== 1.0
}
Rectangle {
id: albumsShade; color: mainWindow.color
width: parent.width; height: parent.height; opacity: 0.0
}
ListView {
anchors.fill: parent
model: albumVisualModel.parts.browser
interactive: false
}
}
AlbumDelegate.qml(第一部分)
Component {
id: albumDelegate
Package {
Item {
Package.name: 'browser'
GridView {
id: photosGridView; model: visualModel.parts.grid; width: mainWindow.width; height: mainWindow.height - 21
x: 0; y: 21; cellWidth: 160; cellHeight: 153; interactive: false
onCurrentIndexChanged: photosListView.positionViewAtIndex(currentIndex, ListView.Contain)
}
}
Item {
Package.name: 'fullscreen'
ListView {
id: photosListView; model: visualModel.parts.list; orientation: Qt.Horizontal
width: mainWindow.width; height: mainWindow.height; interactive: false
onCurrentIndexChanged: photosGridView.positionViewAtIndex(currentIndex, GridView.Contain)
highlightRangeMode: ListView.StrictlyEnforceRange; snapMode: ListView.SnapOneItem
}
}
Item {
Package.name: 'album'
id: albumWrapper; width: 210; height: 220
DelegateModel {
property string tag
id: visualModel; delegate: PhotoDelegate { }
model: MyApp.filesModel(tag)
}
它可以正确显示第一级模型(文件夹),但是当我尝试显示其中一个文件时出现以下错误,它会失败:
qrc:/AlbumDelegate.qml:36: Error: Unknown method return type: FilesModel*
但是我已经使用Q_DECLARE_METATYPE
声明了该类型。
我需要添加其他内容吗?
据我所知,我不需要qRegisterMetaType()
,因为我不在信号或插槽中使用它。