KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Жасмин Бланшет - QT 4: программирование GUI на С++

Жасмин Бланшет - QT 4: программирование GUI на С++

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Жасмин Бланшет, "QT 4: программирование GUI на С++" бесплатно, без регистрации.
Перейти на страницу:

Применяя архитектуру Qt модель/представление, мы можем использовать модели, которые представляют только те данные, которые действительно необходимы для отображения в представлении. Это значительно повышает скорость обработки очень больших наборов данных и уменьшает потребности в памяти по сравнению с подходом, требующим считывания всех данных. Связывая одну модель с двумя или более представлениями, мы можем предоставить пользователю возможность за счет незначительных дополнительных издержек просматривать данные и взаимодействовать с ними различными способами. Qt автоматически синхронизирует множественные представления данных — изменения в одном из представлений отражаются во всех других. Дополнительное преимущество архитектуры модель/представление проявляется в том, что если мы решаем изменить способ хранения исходных данных, нам просто потребуется изменить модель; представления по-прежнему будут работать правильно.

Во многих случаях пользователю необходимо работать только с относительно небольшим количеством элементов. В такой ситуации, как правило, мы можем использовать удобные классы Qt по отображению элементов (QListWidget, QTableWidget и QTreeWidget), непосредственно заполняя все элементы значениями. Эти классы работают подобно классам отображения элементов в предыдущих версиях Qt. Они хранят свои данные в «элементах» (например, QTableWidget содержит элементы QTableWidgetltem). При реализации этих удобных классов используются пользовательские модели, обеспечивающие появление требуемых элементов в представлениях.

Рис. 10.2. Одна модель может обслуживать несколько представлений.

При использовании больших наборов данных часто оказывается недопустимым дублирование данных. В этих случаях мы можем применять классы Qt по отображению элементов (QListView, QTableView и QTreeView) в сочетании с моделью данных, которой может быть как пользовательская модель, так и одна из заранее определенных в Qt моделей. Например, если набор данных хранится в базе данных, мы можем использовать QTableView в сочетании с QSqlTableModel.

Применение удобных классов отображения элементов

Удобные Qt—подклассы отображения элементов обычно использовать проще, чем определять пользовательскую модель, и они особенно удобны, когда разделение модели и представления нам не дает преимущества. Мы использовали этот подход в главе 4, когда создавали подклассы QTableWidget и QTableWidgetItem для реализации функциональности электронной таблицы.

В данном разделе мы покажем, как можно применять удобные классы отображения элементов для вывода на экран элементов. В первом примере приводится используемый только для чтения виджет QListWidget, во втором примере — редактируемый QTableWidget и в третьем примере — используемый только для чтения QTreeWidget.

Мы начинаем с простого диалогового окна, которое позволяет пользователю выбрать из списка символ, используемый в блок-схемах программ. Каждый элемент состоит из пиктограммы, текста и уникального идентификатора.

Сначала покажем фрагмент заголовочного файла диалогового окна:

01 class FlowChartSymbolPicker : public QDialog {

02 Q_OBJECT

03 public:

04 FlowChartSymbolPicker(const QMap<int, QString> &symbolMap,

05 QWidget *parent = 0);

06 int selectedId() const { return id; }

07 void done(int result);

08 …

09 }

Рис. 10.3. Приложение Выбор символа блок—схемы (Flowchart Symbol Picker).

При создании диалогового окна мы должны передать его конструктору ассоциативный массив QMap<int, QString>, и после выполнения конструктора мы можем получить идентификатор выбранного элемента (или —1, если пользователь ничего не выбрал), вызывая selectedId().

01 FlowChartSymbolPicker::FlowChartSymbolPicker(

02 const QMap<int, QString> &symbolMap, QWidget *parent)

03 : QDialog(parent)

04 {

05 id = -1;

06 listWidget = new QListWidget;

07 listWidget->setIconSize(QSize(60, 60));

08 QMapIterator<int, QString> i(symbolMap);

09 while (i.hasNext()) {

10 i.next();

11 QListWidgetItem *item = new QListWidgetItem(i.value(),

12 listWidget);

13 item->setIcon(iconForSymbol(i.value()));

14 item->setData(Qt::UserRole, i.key());

15 …

16 }

17 }

Мы инициализируем id (идентификатор последнего выбранного элемента) значением —1. Затем мы конструируем QListWidget — удобный виджет отображения элементов. Мы проходим в цикле по всем элементам ассоциативного массива символов блок—схемы symbolMap и для каждого создаем объект QListWidgetItem. Конструктор QListWidgetItem принимает выводимую на экран строку QString и родительский виджет QListWidget.

Затем задаем пиктограмму элемента и вызываем setData() для сохранения в QListWidgetItem идентификатора элемента. Закрытая функция iconForSymbol() возвращает QIcon для заданного имени символа.

QListWidgetItem может выступать в разных ролях, каждой из которых соответствует определенный объект QVariant. Самыми распространенными ролями являются Qt::DisplayRole, Qt::EditRole и Qt::IconRole, и для них предусмотрены удобные функции по установке и получению их значений (setText(), setIcon()), но имеется также несколько других ролей. Кроме того, мы можем определить пользовательские роли, задавая числовое значение, равное или большее, чем Qt::UserRole. В нашем примере мы используем Qt::UserRole при сохранении идентификатора каждого элемента.

В непоказанной части конструктора создаются кнопки, выполняется компоновка виджетов и задается заголовок окна.

01 void FlowChartSymbolPicker::done(int result)

02 {

03 id = -1;

04 if (result == QDialog::Accepted) {

05 QListWidgetItem *item = listWidget->currentItem();

06 if (item)

07 id = item->data(Qt::UserRole).toInt();

08 }

09 QDialog::done(result);

10 }

Функция done() класса QDialog переопределяется. Она вызывается при нажатии пользователем кнопок ОК или Cancel. Если пользователь нажимает кнопку OK, мы получаем доступ к соответствующему элементу и извлекаем идентификатор, используя функцию data(). Если бы нас интересовал текст элемента, мы могли бы его получить с помощью вызова item->data(Qt::DisplayRole).toString() или более простого вызова item->text().

По умолчанию QListWidget используется только для чтения. Если бы мы хотели разрешить пользователю редактировать элементы, мы могли бы соответствующим образом установить переключатели редактирования представления, используя QAbstractItemView::setEditTriggers(), например QAbstractItemView::AnyKeyPressed означает, что пользователь может инициировать редактирование элемента, просто начав вводить символы с клавиатуры. Можно было бы поступить по-другому и предусмотреть кнопку редактирования Edit (и, возможно, кнопки добавления и удаления Add и Delete) и связать их со слотами, чтобы можно было программно управлять операциями редактирования.

Теперь, когда мы увидели, как можно использовать удобный класс отображения элементов для просмотра и выбора данных, мы рассмотрим пример, в котором можно редактировать данные. Мы снова используем диалоговое окно, представляющее на этот раз набор точек с координатами (x, у), которые может редактировать пользователь.

Рис. 10.4. Приложение Редактор координат.

Как и в предыдущем примере, мы основное внимание уделим программному коду, относящемуся к представлению элементов, и начнем с конструктора.

01 CoordinateSetter::CoordinateSetter(QList<QPointF> *coords,

02 QWidget *parent)

03 : QDialog(parent)

04 {

05 coordinates = coords;

06 tableWidget = new QTableWidget(0, 2);

07 tableWidget->setHorizontalHeaderLabels(

08 QStringList() << tr("X") << tr("Y"));

09 for (int row = 0; row < coordinates->count(); ++row) {

10 QPointF point = coordinates->at(row);

11 addRow();

12 tableWidget->item(row, 0)->setText(

13 QString::number(point.x()));

14 tableWidget->item(row, 1)->setText(

15 QString::number(point.y()));

16 }

17 …

18 }

Конструктор QTableWidget принимает начальное число строк и столбцов таблицы, выводимой на экран. Каждый элемент в QTableWidget представлен объектом QTableWidgetltem, включая элементы заголовков строк и столбцов. Функция setHorizontalHeaderLabels() задает заголовки всем столбцам, используя соответствующий текст из переданного списка строк. По умолчанию QTableWidget обеспечивает заголовки строк числовыми метками, начиная с 1; именно это нам и нужно, поэтому нам не приходится задавать вручную заголовки строк.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*