QT 4: программирование GUI на С++
Шрифт:
Функция Cell::value, используемая в data, возвращает значение типа QVariant. Объекты типа QVariant могут содержать значения различных типов, например double или QString, и поддерживают функции для преобразования их в другие типы. Например, при вызове toString для переменной типа QVariant, содержащей значение типа double, в результате мы получим строковое представление числа с двойной точностью. Используемый по умолчанию конструктор QVariant устанавливает
Закрытая функция 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.
Теперь можно считать, что мы завершили приложение Электронная таблица, если не брать в расчет синтаксический анализ формул. В остальной части данного раздела рассматриваются функция evalExpression и две вспомогательные функции evalTerm и evalFactor. Их программный код немного сложен, но он включен сюда, чтобы приложение имело законченный вид. Поскольку этот программный код не относится к программированию графического интерфейса, вы можете спокойно его пропустить и продолжить чтение с главы 5 .
Функция evalExpression возвращает значение выражения из ячейки электронной таблицы. Выражение состоит из одного или нескольких термов, разделенных знаками операций «+» или «—». Термы состоят из одного или нескольких факторов (factors), разделенных знаками операций «*» или «/». Разбивая выражения на термы, а термы на факторы, мы обеспечиваем правильную последовательность выполнения операций.
Например, «2*C5+D6» является выражением, первый терм которого будет «2*C5», а второй терм — «D6». «2*C5» является термом, первый фактор которого будет «2», а второй фактор — «C5»; «D6» состоит из одного фактора — «D6». Фактором могут быть число («2»), обозначение ячейки («C5») или выражение в скобках, перед которым может стоять знак минуса.
Рис. 4.10. Блок—схема синтаксического анализа выражений электронной таблицы.
Блок—схема синтаксического анализа выражений электронной таблицы представлена на рис. 4.10. Для каждого грамматического символа (Expression, Term и Factor — выражение, терм и фактор) имеется соответствующая функция—член, которая выполняет его синтаксический анализ и структура которой очень хорошо отражает его грамматику. Построенные таким образом синтаксические анализаторы называются парсерами с рекурсивным спуском (recursive—descent parsers).