Теперь мы перейдем к написанию cell.cpp:
01 #include <QtGui>
02 #include "cell.h"
03 Celclass="underline" :Cell()
04 {
05 setDirty();
06 }
В конструкторе нам необходимо установить признак «dirty» («грязный») только для кэша. Передавать родительский объект нет необходимости; когда делается вставка ячейки в QTableWidget с помощью setItem(), QTableWidget автоматически станет ее владельцем.
Каждый элемент QTableWidgetltem может иметь некоторые данные — до одного типа QVariant на каждую «роль» данных. Наиболее распространенными ролями являются Qt::EditRole и Qt::DisplayRole (роль правки и роль отображения). Роль правки используется для данных, которые должны редактироваться, а роль отображения — для данных, которые должны отображаться на экране. Часто обе роли используются для одних и тех же данных, однако в Cell роль правки соответствует формуле ячейки, а роль отображения — значению ячейки (результату вычисления формулы).
02 QTableWidgetltem *Celclass="underline" :clone() const
03 {
04 return new Cell(*this);
05 }
Функция clone() вызывается в QTableWidget, когда необходимо создать новую ячейку, например когда пользователь начинает вводить данные в пустую ячейку, которая до сих пор не использовалась. Переданный функции QTableWidget::setItemPrototype() экземпляр является дубликатом. Поскольку для копирования Cell можно ограничиться функцией—членом, мы полагаемся на используемый по умолчанию конструктор копирования, автоматически создаваемый С++ при создании экземпляров новых ячеек Cell в функции clone().
06 void Celclass="underline" :setFormula(const QString &formula)
07 {
08 setData(Qt::EditRole, formula);
09 }
Функция setFormula() задает формулу ячейки. Это просто удобная функция для вызова setData() с указанием роли правки. Она вызывается из функции Spreadsheet::setFormula().
10 QString Celclass="underline" :formula() const
11 {
12 return data(Qt::EditRole).toString();
13 }
Функция formula() вызывается из Spreadsheet::formula(). Подобно setFormula() этой функцией удобно пользоваться на этот раз для получения данных EditRole заданного элемента.
14 void Celclass="underline" :setData(int role, const QVariant &value)
15 {
16 QTableWidgetltem::setData(role, value);
17 if (role == Qt::EditRole)
18 setDirty();
19 }
Если мы имеем новую формулу, мы устанавливаем cacheIsDirty на значение true, чтобы обеспечить перерасчет ячейки при последующем вызове text().
В Cell нет определения функции text(), хотя мы и вызываем text() для экземпляров Cell в функции Spreadsheet::text(). QTableWidgetltem содержит удобную функцию text(), которая эквивалентна вызову data(Qt::DisplayRole).toString().
20 void Celclass="underline" :setDirty()
21 {
22 cacheIsDirty = true;
23 }
Функция setDirty() вызывается для принудительного перерасчета значения ячейки. Она просто устанавливает флажок cacheIsDirty на значение true, указывая на то, что значение cachedValue больше не отражает текущее состояние. Перерасчет не будет выполняться до тех пор, пока он не станет действительно необходим.
24 QVariant Celclass="underline" :data(int role) const
25 {
26 if (role == Qt::DisplayRole) {
27 if (value().isValid()) {
28 return value().toString();
29 } else {
30 return "####";
31 }
32 } else if (role == Qt::TextAlignmentRole) {
33 if (value().type() == QVariant::String) {
34 return int(Qt::AlignLeft | Qt::AlignVCenter);
35 } else {
36 return int(Qt::AlignRight | Qt::AlignVCenter);
37 }
38 } else {
39 return QTableWidgetltem::data(role);
40 }
41 }
Функция data() класса QTableWidgetltem переопределяется. Она возвращает текст, который должен отображаться в электронной таблице, если в вызове указана роль Qt::DisplayRole, или формулу, если в вызове указана роль Qt::EditRole. Она обеспечивает подходящее выравнивание, если вызывается с ролью Qt::TextAlignmentRole. При задании роли DisplayRole она использует функцию value() для расчета значения ячейки. Если нельзя получить достоверное значение (из-за того, что формула неверна), мы возвращаем значение «####».