QT 4: программирование GUI на С++
Шрифт:
• переменная cachedValue кэширует значение ячейки в виде значения типа QVariant;
• переменная cacheIsDirty принимает значение true, если кэшируемое значение устарело.
Мы используем QVariant, поскольку некоторые ячейки имеют тип числа двойной точности double, а другие имеют тип строки QString.
При объявлении переменных cachedValue и cacheIsDirty используется ключевое слово mutable языка С++. Это позволяет нам модифицировать эти переменные
Следует отметить, что в определении класса не используется макрос Q_OBJECT. Класс Cell является «чистым» классом С++, который не имеет сигналов и слотов. На самом деле из-за того, что QTableWidgetltem не является наследником QObject, мы не можем использовать в Cell как таковые сигналы и слоты. Классы элементов Qt не наследуют QObject, чтобы свести к минимуму затраты на их обработку. Если сигналы и слоты необходимы, они могут быть реализованы в виджете, содержащем элементы, или (в виде исключения) при помощи множественного наследования класса QObject.
Теперь мы перейдем к написанию cell.cpp:
В конструкторе нам необходимо установить признак «dirty» («грязный») только для кэша. Передавать родительский объект нет необходимости; когда делается вставка ячейки в QTableWidget с помощью setItem, QTableWidget автоматически станет ее владельцем.
Каждый элемент QTableWidgetltem может иметь некоторые данные — до одного типа QVariant на каждую «роль» данных. Наиболее распространенными ролями являются Qt::EditRole и Qt::DisplayRole (роль правки и роль отображения). Роль правки используется для данных, которые должны редактироваться, а роль отображения — для данных, которые должны отображаться на экране. Часто обе роли используются для одних и тех же данных, однако в Cell роль правки соответствует формуле ячейки, а роль отображения — значению ячейки (результату вычисления формулы).
Функция clone вызывается в QTableWidget, когда необходимо создать новую ячейку, например когда пользователь начинает вводить данные в пустую ячейку, которая до сих пор не использовалась. Переданный функции QTableWidget::setItemPrototype экземпляр является дубликатом. Поскольку для копирования Cell можно ограничиться функцией—членом, мы полагаемся на используемый по умолчанию конструктор копирования, автоматически создаваемый С++ при создании экземпляров новых ячеек Cell в функции clone.
Функция setFormula задает формулу ячейки. Это просто удобная функция для вызова setData с указанием
роли правки. Она вызывается из функции Spreadsheet::setFormula.Функция formula вызывается из Spreadsheet::formula. Подобно setFormula этой функцией удобно пользоваться на этот раз для получения данных EditRole заданного элемента.
Если мы имеем новую формулу, мы устанавливаем cacheIsDirty на значение true, чтобы обеспечить перерасчет ячейки при последующем вызове text.
В Cell нет определения функции text, хотя мы и вызываем text для экземпляров Cell в функции Spreadsheet::text. QTableWidgetltem содержит удобную функцию text, которая эквивалентна вызову data(Qt::DisplayRole).toString.
Функция setDirty вызывается для принудительного перерасчета значения ячейки. Она просто устанавливает флажок cacheIsDirty на значение true, указывая на то, что значение cachedValue больше не отражает текущее состояние. Перерасчет не будет выполняться до тех пор, пока он не станет действительно необходим.
Функция data класса QTableWidgetltem переопределяется. Она возвращает текст, который должен отображаться в электронной таблице, если в вызове указана роль Qt::DisplayRole, или формулу, если в вызове указана роль Qt::EditRole. Она обеспечивает подходящее выравнивание, если вызывается с ролью Qt::TextAlignmentRole. При задании роли DisplayRole она использует функцию value для расчета значения ячейки. Если нельзя получить достоверное значение (из-за того, что формула неверна), мы возвращаем значение «####».