Форум программистов, компьютерный форум, киберфорум
Dmitriy_M
Войти
Регистрация
Восстановить пароль

Используем Qt модели и QImage/QPixmap в QML, на примере FileBrowser

Запись от Dmitriy_M размещена 14.02.2013 в 22:44
Показов 14704 Комментарии 0

В прошлой записи рассмотрели использование своих C++ моделей в QML.
Сейчас же раcсмотрим использование Qt моделей на примере QFileSystemModel.

QFileSystemModel содержит следующие роли:
C++ (Qt)
1
2
3
4
QFileSystemModel::FileIconRole  Qt::DecorationRole
QFileSystemModel::FilePathRole  Qt::UserRole + 1
QFileSystemModel::FileNameRole  Qt::UserRole + 2
QFileSystemModel::FilePermissions   Qt::UserRole + 3
В принципе этого достаточно, для отображения имен файлов, но не достаточно, для обхода файловой системы.
QFileSystemModel содержит много полезных методов, но не содержит Q_INVOKABLE методов, позволяющих использовать их из QML, поэтому придется переопределить следующим способом:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class FileSystemModel: public QFileSystemModel
{
  Q_OBJECT
 
  Q_PROPERTY(QString rootPath READ rootPath WRITE setRootPath NOTIFY rootPathChanged)
public:
  FileSystemModel(QObject* parent = 0);
 
  /*!
   * @brief получить корень
   */
  QString rootPath()const;
 
  /*!
   * @brief установить корень
   */
  void setRootPath(const QString& path);
 
  /*!
   * @brief обертка над QFileSystemModel::index
   */
  Q_INVOKABLE QModelIndex indexFromPath(const QString & path, int column = 0) const;
 
  /*!
   * @brief получение имени файла
   */
  Q_INVOKABLE QString fileName(const QModelIndex & index) const;
 
  /*!
   * @brief получиение пути
   */
  Q_INVOKABLE QString filePath(const QModelIndex & index) const;
 
  /*!
   * @brief проверка на каталог
   */
  Q_INVOKABLE bool isDir(const QString& path) const;
 
  /*!
   * @brief получение родительского индекса
   */
  Q_INVOKABLE QModelIndex parentIndex(const QModelIndex& child) const;
 
signals:
  void rootPathChanged();
 
};
Реализация крайне проста:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
FileSystemModel::FileSystemModel(QObject* parent):
  QFileSystemModel(parent)
{
  setFilter(QDir::Files | QDir::AllDirs);
}
 
QString FileSystemModel::rootPath()const
{
  return QFileSystemModel::rootPath();
 
}
 
void FileSystemModel::setRootPath(const QString& path)
{
  QFileSystemModel::setRootPath(path);
  emit rootPathChanged();
}
 
QModelIndex FileSystemModel::indexFromPath(const QString & path, int column ) const
{
  return QFileSystemModel::index(path, column);
}
 
QString FileSystemModel::fileName(const QModelIndex & index) const
{
  return QFileSystemModel::fileName(index);
}
QString FileSystemModel::filePath(const QModelIndex & index) const
{
  return QFileSystemModel::filePath(index);
}
 
bool FileSystemModel::isDir(const QString& path) const
{
    return QFileSystemModel::isDir(index(path));
}
 
QModelIndex FileSystemModel::parentIndex(const QModelIndex& child) const
{
  return QFileSystemModel::parent(child);
}
Стоит отметить установку фильтра в конструкторе.
Далее следует обычная регистрация типа в QML:
C++ (Qt)
1
qmlRegisterType<FileSystemModel>(uri, 1, 0, "FileSystemModelBinding");
Большинство методов принимают QModelIndex в качестве параметра, а в том же ListModel используются целые индексы.
Тут и приходит на помощь VisualDataModel имеющий в себе свойство
JavaScript
1
rootIndex : QModelIndex
.
Инкапсулируем свою модель в VisualDataModel:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import QtQuick 2.0
import QmlExtension 1.0
 
VisualDataModel{
    id: fsModel
 
    property alias rootPath:fsBinding.rootPath
 
    function cdUp(){
        rootIndex = fsBinding.parentIndex(fsModel.rootIndex);
    }
 
    function isDir(path){
        return fsBinding.isDir(path);
    }
 
    function cd(path){
        rootIndex=fsBinding.indexFromPath(path)
    }
 
    model:FileSystemModelBinding{
        id: fsBinding
 
        }
}
Сохраним это в FileSystemModel.qml
Вот простой пример использования:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Rectangle {
    width: 500
    height: 500
    //color: "#4e4d4e"
 
    FileSystemModel{
        id:fsModel
        rootPath:"/"
        delegate:Item{
            height: view.cellHeight
            width: view.cellWidth
                Text{
                    anchors.horizontalCenter: icon.horizontalCenter
                    text:fileName
                    horizontalAlignment: Text.AlignHCenter
                    wrapMode:Text.WordWrap
                    width: parent.width
 
                    font.family: "Verdana"
                    //color: "white"
                }
        }
    }
 
    GridView{
        id:view
        width: parent.width
        height: parent.height
        anchors.fill: parent
        model: fsModel
        cellHeight : 128
        cellWidth : 128
    }
}
В Windows отобразится сетка с названием диска, в Unix сетка с содержимым корня.

Теперь хочется отображать иконки. И тут встает вопрос, как использовать QIcon или QImage/QPixmap в QML?
Для этих целей есть поставщик изображений QQuickImageProvider
Когда мы пишем такую схему:
JavaScript
1
Image { source: "image://MyImageProvider/image.png" }
То ищется поставщик зарегистрированный под именем MyImageProvider, в который передастся идентификатор
объекта, который требуется отобразит, в данном случае это image.png.

Описываем поставщика:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*!
 * @brief поставщик иконок
 */
class FileSystemIconProvider: public QQuickImageProvider
{
public:
  /*!
    \brief дефолтная длина
    */
  static const size_t DEFAULT_WIDTH  = 64;
 
  /*!
    \brief дефолтная высота
    */
  static const size_t DEFAULT_HEIGTH = 64;
 
  FileSystemIconProvider();
 
  virtual QPixmap requestPixmap(const QString & id, QSize * size, const QSize & requestedSize);
 
private:
  QFileIconProvider iconProvider_; //!< поставщик иконок fs
 
};
И реализация:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
FileSystemIconProvider::FileSystemIconProvider():
  QQuickImageProvider(QQmlImageProviderBase::Pixmap)
{
}
 
QPixmap FileSystemIconProvider::requestPixmap(const QString & id, QSize * size, const QSize & requestedSize)
{
  *size = QSize(DEFAULT_WIDTH, DEFAULT_HEIGTH);
 
  QIcon icon = iconProvider_.icon(id);
 
  return icon.pixmap( requestedSize.isValid() ? requestedSize :  *size);
}
Здесь id идентификатор ресурса, size истинный размер ресурса, requestedSize запрашиваемый размер из QML Image.
Добавляем поставщика в движек:
C++ (Qt)
1
2
3
4
void QMLExtensionPlugin::initializeEngine(QQmlEngine * engine, const char * uri)
{
  engine->addImageProvider("filesystem", new FileSystemIconProvider());
}
Теперь собираем все вместе:
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import QtQuick 2.0
 
Rectangle {
    width: 500
    height: 500
    //color: "#4e4d4e"
 
    FileSystemModel{
        id:fsModel
        rootPath:"/"
        delegate:Item{
            height: view.cellHeight
            width: view.cellWidth
 
            Column{
                anchors.centerIn: parent
                width: parent.width
 
 
                Image {
 
                    id: icon
                    source: "image://filesystem/"+filePath
                    smooth: true
                }
 
                Text{
                    anchors.horizontalCenter: icon.horizontalCenter
                    text:fileName
                    horizontalAlignment: Text.AlignHCenter
                    wrapMode:Text.WordWrap
                    width: parent.width
 
                    font.family: "Verdana"
                    //color: "white"
                }
 
            }
 
            MouseArea{
                anchors.fill: parent
                onDoubleClicked: {
                    fsModel.cd(filePath)
                }
            }
        }
 
 
    }
 
    GridView{
        id:view
        width: parent.width
        height: parent.height
        anchors.fill: parent
        model: fsModel
        cellHeight : 128
        cellWidth : 128
    }
}
Одна из особенности QFileIconProvider в Windows, он не может отдавать большие иконки Windows Vista.
Миниатюры
Нажмите на изображение для увеличения
Название: drivers.png
Просмотров: 766
Размер:	29.8 Кб
ID:	1730   Нажмите на изображение для увеличения
Название: folrers.png
Просмотров: 954
Размер:	41.1 Кб
ID:	1731  
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru