Шаг 105.
Библиотека Qt.
Иерархические данные

    На этом шаге рассмотрим организацию иерархических данных.

    Каждая ячейка в таблице может иметь дочерние таблицы. И, думая об иерархиях, мы должны не забыть об иерархиях таблиц. Давайте воспользуемся интерфейсом модели QStandardItemModel для создания нашей иерархии и отобразим ее (рис. 1).


Рис.1. Отображение иерархических данных

    Схема использования класса QStandardItemModel очень проста. Сначала необходимо создать его объект, а потом методом setData() установить данные для каждого элемента. Впоследствии эти данные можно будет получать методом data().

    Рассмотрим код программы, результат работы которой представлен на рисунке 1.

//создаем модель, представляющую собой таблицу из пяти строк и трех столбцов
QStandardItemModel model(5, 3);
for (int nTopRow = 0; nTopRow < 5; ++nTopRow)
{
    //получаем текущий индекс с помощью метода index()
    QModelIndex index = model.index(nTopRow, 0);
    //задаем данные для элемента
    model.setData(index, "Элемент" + QString::number(nTopRow + 1));
    //вставляем, по текущему индексу, подтаблицу с четырьмя строками 
    //и тремя столбцами при помощи методов insertRows() и insertColumns()
    model.insertRows(0, 4, index);
    model.insertColumns(0, 3, index);
    for (int nRow = 0; nRow < 4; ++nRow)
    {
        for (int nCol = 0; nCol < 3; ++nCol)
        {
            QString strPos = QString("%1,%2").arg(nRow+1).arg(nCol+1);
            //вызовом метода setData() ячейки подтаблицы заполняются данными
            model.setData(model.index(nRow, nCol, index), strPos);
        }
    }
}
QTreeView treeView;
treeView.setModel(&model);
treeView.show(); 

    Файлы приложения можно взять здесь.

    Теперь приведем пример, успевший стать с момента появления Qt4 настоящей классикой. Он как нельзя лучше показывает простоту и потенциал, связанный с использованием моделей. В программе, окно которой показано на рис. 2, благодаря готовой модели QDirModel всего лишь при помощи нескольких строк реализуется обозреватель файловой системы.


Рис.2. Показ каталогов и файлов

    Рассмотрим код программы, результат работы которой представлен на рисунке 2.

//создается объект модели класса QDirModel
QDirModel model;
QTreeView treeView;
//и устанавливается в представлении
treeView.setModel(&model);
treeView.show();

    Файлы приложения можно взять здесь.

    Для показа определенного пути можно воспользоваться методом index(). Обычно этот метод ожидает три параметра: столбец, строку и индекс предка, но можно обойтись и без них, достаточно передать в него строку с путем. Таким образом, мы увидим в нашем представлении содержимое только текущего каталога, добавив в нашу программу (рис. 2), следующие строки:

QModelIndex index = model.index(QDir::currentPath());
treeView.setRootIndex(index);

    Воспользовавшись слотом setRootIndex() и еще несколькими слотами и сигналами, можно соединить иерархическое представление с табличным представлением и реализовать программу обозревателя, окно которого показано на рис. 3.


Рис.3. Окно обозревателя

    Рассмотрим код программы, результат работы которой представлен на рисунке 3.

//создается виджет горизонтального разделителя (spl)
QSplitter spl(Qt::Horizontal);
QDirModel model;
QTreeView* pTreeView = new QTreeView;
pTreeView->setModel(&model);
QTableView* pTableView = new QTableView;
pTableView->setModel(&model);
//первое соединение в табличном представлении осуществляет установку каталога,
//выбранного в иерархическом представлении, в качестве узлового
QObject::connect(pTreeView, SIGNAL(clicked(const QModelIndex&)),
                 pTableView, SLOT(setRootIndex(const QModelIndex&)));
//второе соединение нам нужно для того, чтобы при выборе
//одного из каталогов табличного представления выполнялось выделение
//этого каталога в иерархическом представлении
QObject::connect(pTableView, SIGNAL(activated(const QModelIndex&)),
                 pTreeView, SLOT(setCurrentIndex(const QModelIndex&)));
//последнее соединение служит для показа содержимого
//каталога при работе в табличном представлении
QObject::connect(pTableView, SIGNAL(activated(const QModelIndex&)),
                 pTableView, SLOT(setRootIndex(const QModelIndex&)));
spl.addWidget(pTreeView);
spl.addWidget(pTableView);
spl.show();

    Файлы приложения можно взять здесь.

    Таким образом, двойной щелчок мыши или нажатие на клавишу Enter на каталоге вышлет из табличного представления сигнал activated(), который будет отловлен самим табличным представлением, и слот setRootIndex() установит данный каталог в качестве базового. А это значит, что табличное представление позволяет нам входить только внутрь каталогов, а не выходить из них. Но это не проблема, например, правая часть Проводника ОС Windows работает аналогичным образом. Воспользовавшись левой частью Проводника, мы можем выбрать любой интересующий нас каталог.

    На следующем шаге рассмотрим роли элементов в модели.




Предыдущий шаг Содержание Следующий шаг