Функция Celclass="underline" :value(), используемая в data(), возвращает значение типа QVariant. Объекты типа QVariant могут содержать значения различных типов, например double или QString, и поддерживают функции для преобразования их в другие типы. Например, при вызове toString() для переменной типа QVariant, содержащей значение типа double, в результате мы получим строковое представление числа с двойной точностью. Используемый по умолчанию конструктор QVariant устанавливает значение «invalid» (недопустимое).
42 const QVariant Invalid;
43 QVariant Celclass="underline" :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.