20 void Cell::setDirty()
21 {
22 cacheIsDirty = true;
23 }
Функция setDirty() вызывается для принудительного перерасчета значения ячейки. Она просто устанавливает флажок cacheIsDirty на значение true, указывая на то, что значение cachedValue больше не отражает текущее состояние. Перерасчет не будет выполняться до тех пор, пока он не станет действительно необходим.
24 QVariant Cell::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() для расчета значения ячейки. Если нельзя получить достоверное значение (из-за того, что формула неверна), мы возвращаем значение «####».
Функция Cell::value(), используемая в data(), возвращает значение типа QVariant. Объекты типа QVariant могут содержать значения различных типов, например double или QString, и поддерживают функции для преобразования их в другие типы. Например, при вызове toString() для переменной типа QVariant, содержащей значение типа double, в результате мы получим строковое представление числа с двойной точностью. Используемый по умолчанию конструктор QVariant устанавливает значение «invalid» (недопустимое).
42 const QVariant Invalid;
43 QVariant Cell::value() const
44 {
45 if (cacheIsDirty) {
46 cacheIsDirty = false;
47 QString formulaStr = formula();
48 if (formulaStr.startsWith('\'')) {
49 cachedValue = formulaStr.mid(1);
50 } else if (formulaStr.startsWith('=')) {
51 cachedValue = Invalid;
52 QString expr = formulaStr.mid(1);
53 expr.replace(" ", "");
54 expr.append(QChar::Null);
55 int pos = 0;
56 cachedValue = evalExpression(expr, pos);
57 if (expr[pos] != QChar::Null)
58 cachedValue = Invalid;
59 } else {
60 bool ok;
61 double d = formulaStr.toDouble(&ok);
62 if (ok) {
63 cachedValue = d;
64 } else {
65 cachedValue = formulaStr;
66 }
67 }
68 }
69 return cachedValue;
70 }
Закрытая функция value() возвращает значение ячейки. Если флажок cacheIsDirty имеет значение true, нам необходимо выполнить перерасчет значения.
Если формула начинается с одиночной кавычки (например, «'12345»), то одиночная кавычка занимает позицию 0, а значение представляет собой строку в позициях с 1 до последней.
Если формула начинается со знака равенства («=»), мы выделяем строку, начиная с позиции 1, и удаляем из нее любые пробелы. Затем мы вызываем функцию evalExpression() для вычисления значения выражения. Аргумент pos передается по ссылке; он задает позицию символа, с которого должен начинаться синтаксический анализ выражения. После вызова функции evalExpression() в позиции pos нами должен быть установлен символ QChar::Null, если синтаксический анализ завершился успешно. Если синтаксический анализ не закончился успешно, мы устанавливаем cachedValue на значение Invalid.
Если формула не начинается с одиночной кавычки или знака равенства, мы пытаемся преобразовать ее в число с плавающей точкой, используя функцию toDouble(). Если преобразование удается выполнить, мы устанавливаем cachedValue на полученное значение; в противном случае мы устанавливаем cachedValue на строку формулы. Например, формула «1.50» приводит к тому, что функция toDouble() устанавливает
переменную ok на значение true и возвращает 1.5, а формула «World Population» (население Земли) приводит к тому, что функция toDouble() устанавливает переменную ok на значение false и возвращает 0.0.
Благодаря заданному в функции toDouble() указателю на булево значение мы можем отличать строку преобразования, представляющую числовое значение 0.0, от ошибки преобразования (в последнем случае также возвращается 0.0, но булева переменная устанавливается в значение false ). Иногда нулевое значение при неудачном преобразовании оказывается именно тем, что нам нужно; в этом случае нет необходимости передавать указать на переменную типа bool. По причинам, связанным с производительностью и переносимостью, в Qt никогда не используются исключения С++ для вывода сообщений об ошибках. Это не значит, что вы не можете использовать их в своих Qtпрограммах, если ваш компилятор поддерживает исключения С++.
Функция value() объявлена с модификатором const. При объявлении переменных cachedValue и cacheIsValid мы использовали ключевое слово mutable, чтобы компилятор позволял нам модифицировать эти переменные в функциях типа const. Может показаться заманчивой возможность сделать функцию value() не типа const и удалить ключевые слова mutable, но это не пропустит компилятор, поскольку мы вызываем value() из data() функции с модификатором const.