Field Control - это штатный контрол PalmOS для редактируемого поля. Как обычно, умение работать с аналогичными контролами в других ОС как помогают, так и мешают работе с field.
Field традиционно проще своих десктопных аналогов.
Отдельные символы в поле задаются позициями. позиция - смещение символа в байтах от начала поля.
Можно задать диапазон. Диапазон задается позицией первого символа диапазона и позицией символа после диапазона. Если позиции начала и конца совпадают, то диапазон пустой.
Приведем описание поля в файле ресурсов. Описание отдельных параметров будет приведено позже в разделе атрибутов
FIELD ID <Id.n> AT (<Left.p> <Top.p> <Width.p> <Height.p>) [USABLE] [NONUSABLE] [DISABLED] [LEFTALIGN] [RIGHTALIGN] [[FONT|<FontId.n>]] [EDITABLE] [NONEDITABLE] [UNDERLINED] [SINGLELINE] [MULTIPLELINES] [DYNAMICSIZE] [[MAXCHARS|<MaxChars.n>]] [AUTOSHIFT] [NUMERIC] [HASSCROLLBAR]
В этом разделе перечислены атрибуты поля. После описания обычно даются функции по получению и установке атрибута, а также имя атрибута в файле ресурсов.
Имя поля | Описание | Функции извлечения | Функции модификации | Параметр в ресурсах | |||||
id | идентификатор поля на форме | ID <Id.n> | |||||||
rect | стандартные координаты поля типа RectangleType | FldGetBounds | FldSetBounds | AT (<Left.p> <Top.p> <Width.p> <Height.p>) | |||||
fontID | шрифт, используемый в поле | FldGetFont | FldSetFont | FONT <FontId.n>) | |||||
text | указатель на текст, содержащийся в поле. текст завершается нулевым байтом. | FldGetTextPtr | FldSetTextPtr | ||||||
textHandle | хендл текстового блока | FldGetTextHandle | FldSetTextHandle FldSetText | ||||||
textLen | реальная длина текста, используемая блоком, StrLen(text). | FldGetTextLength | |||||||
textBlockSize | длина блока, выделенного для текста. По сути дела максимальная длина текста, которую поле будет использовать до перевыделения памяти. | FldGetTextAllocatedSize | FldSetTextAllocatedSize | ||||||
maxChars | максимальное допустимое число вводимых символов. Учтите, что для мультибайтных кодировок это не будет совпадать с максимальной длиной блока в байтах. Предельный размер поля - 32767 байт. | FldGetMaxChars | FldSetMaxChars | MAXCHARS <MaxChars.n> | |||||
selFirstPost, selLastPos | позиции выделенного текста. | FldGetSelection | FldSetSelection | ||||||
insert position | позиция ввода. реально в структуре FieldType не хранится, вместо него хранятся следующие два поля. | FldGetInsPtPosition | FldSetInsPtPosition (с перерисовкой) FldSetInsertionPoint (без перерисовки) | ||||||
insPtXPos | смещение в байтах позиции ввода от начала строки. А если текущая строка не видна, то абсолютная позиция. | ||||||||
insPtYPos | строка на экране, в которой находится позиция ввода. Если позиция невидима, то в поле хранится 0x8000 | ||||||||
maxVisibleLines | максимальное число видимых строк | FldSetMaxVisibleLines | |||||||
lines | информация разбиения текста по строкам. Поле указывает на массив информации о началах строк и числе символов в каждой. Число строк можно получить с помощью функции FldGetVisibleLines. |
Следующие поля входят в структуру FieldAttrType. Для работы с этими полями используются функции FldGetAttributes и FldSetAttributes
Имя поля | Описание | Функции извлечения | Функции модификации | Параметр в ресурсах | ||||||
usable | признак использования поля в форме | FldSetUsable | USABLE NONUSABLE | |||||||
visible | признак видимости поля. | FldDrawField FldEraseField | DISABLED | |||||||
editable | признак возможности редактирования поля пользователем | EDITABLE NONEDITABLE | ||||||||
singleLine | Признак однострочного или многострочного поля | SINGLELINE MULTIPLELINES | ||||||||
hasFocus | поле держит фокус. Если поле в фокусе, то в нем мерцает курсор | FldGrabFocus FldReleaseFocus | ||||||||
dynamicSize | Обманчивое имя признака. На самом деле, если флаг выставлен, то при изменении числа строк генерируется событие fldHeightChangedEvent. Приложение может отслеживать событие и изменять видимые границы поля. Если признак не выставлен, то событие не генерируется. Никакого автоматического изменения размера не происходит. Для однострочных полей смысла не имеет. | DYNAMICSIZE | ||||||||
insPtVisible | внутренний признак того, что строка с позицией ввода видна на экране. | |||||||||
dirty | признак “грязного” поля. Поле является грязным, когда изменения в содержимом не отображены на экране. | FldDirty | FldSetDirty | |||||||
underlined | Признак указывает на тип подчеркивания строк. PilRC позволяет только стандартный способ - grayUnderline. Программно можно задать noUnderline, solidUnderline, colorUnderline. | UNDERLINED | ||||||||
justification | задает выравнивание поля: leftAlign, rightAlign. centerAlign не поддерживается. | LEFTALIGN RIGHTALIGN | ||||||||
autoShift | если признак задан, то поддерживаются правила autoShift (автоматическое выставление заглавных букв в начале предложений). | AUTOSHIFT | ||||||||
hasScrollBar | Еще одно обманчивое имя. При выставлении поле начинает чаще посылать fldChangedEvent. Слово “чаще” нужно понимать как “поле чаще пересчитывает разбиение на строки”. | HASSCROLLBAR | ||||||||
numeric | К версии PalmOS 3.5 поле научилось воспринимать только цифры, разделитель тысяч и десятичную точку. | NUMERIC |
Первое, что следует усвоить при работе с полями - это стратегии выделения памяти для содержимого поля.
Функция FldFreeMemory освобождает память, выделенную для поля. В случае фиксированного поля ничего не освобождается. Если поле хранит содержимое в куче, то все освобождение происходит автоматически. В третьем случае функция попытается освободить память связанную с записью, что приведет к краху. Чтобы его избежать следует отвязать запись от поля вызовом
FldSetTextHandle(fldP, NULL)
.
Таким образом, аккуратного программирования требует только третья стратегия. Две первые ведут себя ожидаемо и предсказуемо. Не рекомендуется смешивать стратегии работы без необходимости.
Также не стоит сохранять указатель на текст в двух последних стратегиях, поскольку указатель может измениться.
Функция FldCompactText уменьшает размер чанка до текущего размера поля.
Обычная отрисовка поля происходит автоматически. Программировать перерисовку руками нужно только есть вы изменяете содержимое поля функциями FldSetTextPtr/FldSetText/FldSetTextHandle. В этом случае используйте следующие функции:
Сверяйтесь со справочником при использовании функций, модифицирующих поле. Некоторые функции обновляют поле, а некоторые этого не делают.
Для непосредственной работы с полем существуют привычные функции: FldCopy, FldCut, FldPaste. Эти функции реализуют стандартные функции взаимодействия поля с клипбордом.
Функция FldUndo откатывает последние операции. Функции отката могут откатить до 100 действий, сделанных над текущим полем.
Существует удобная функция для вставки в текущую позицию (или замены выделенного текста) - FldInsert. Пользоваться этой функцией удобно, но нужно учесть, что она заместит выделение и запостит в очередь сообщений fldChangedEvent. Сотня вставок с помощью FldInsert просто вызовет переполнение очереди. В этом случае проще получить хэндл текста, модифицировать содержимое и установить новый хэндл.
Функция FldDelete удаляет символы из указанного диапазона.
Взаимодействие со скролл баром должно быть реализовано вручную. К счастью технология взаимодействия достаточно простая.
Описание поля и скроллбара в ресурсах:
FIELD ID MainDescriptionField AT (0 20 151 122) EDITABLE MULTIPLELINES LEFTALIGN MAXCHARS 8192 HASSCROLLBAR SCROLLBAR ID MainDescriptionScl AT (152 20 7 122) VALUE 0 MIN 0 MAX 100 PAGESIZE 8
Для обновления скроллбара нужно получить текущую позицию текста в поле с помощью функции FldGetScrollValues. Функция для обновления позиции скроллбара:
static void UpdateScrollBar(void){ UInt16 scrollPos; UInt16 textHeight; UInt16 fieldHeight; Int16 maxValue; FieldPtr fld; ScrollBarPtr bar; fld = GetObjectPtr (MainDescriptionField); bar = GetObjectPtr (MainDescriptionScl); FldGetScrollValues (fld, &scrollPos, &textHeight, &fieldHeight); if (textHeight > fieldHeight) { // On occasion, such as after deleting a multi-line selection of text, // the display might be the last few lines of a field followed by some // blank lines. To keep the current position in place and allow the user // to "gracefully" scroll out of the blank area, the number of blank lines // visible needs to be added to max value. Otherwise the scroll position // may be greater than maxValue, get pinned to maxvalue in SclSetScrollBar // resulting in the scroll bar and the display being out of sync. maxValue = (textHeight - fieldHeight) + FldGetNumberOfBlankLines (fld); } else if (scrollPos) maxValue = scrollPos; else maxValue = 0; SclSetScrollBar (bar, scrollPos, 0, maxValue, fieldHeight-1); }
Для точного позиционирования поля по первому видимому байту используются функции FldGetScrollPosition и FldSetScrollPosition. Но для грубых позиционирований достаточно использовать FldScrollField.
Выяснить, скроллится ли поле в указанном направлении можно с помощью функции FldScrollable.
Функция для скролла поля по изменению скролл бара:
static void ViewScroll (Int16 linesToScroll, Boolean updateScrollbar) { UInt16 blankLines; FieldPtr fld; fld = GetObjectPtr (MainDescriptionField); blankLines = FldGetNumberOfBlankLines (fld); if (linesToScroll < 0) FldScrollField (fld, -linesToScroll, winUp); else if (linesToScroll > 0) FldScrollField (fld, linesToScroll, winDown); // If there were blank lines visible at the end of the field // then we need to update the scroll bar. if ((blankLines && (linesToScroll < 0)) || updateScrollbar){ UpdateScrollBar(); } }
Фрагмент обработчика событий формы:
case fldChangedEvent: UpdateScrollBar(); break; case sclRepeatEvent: ViewScroll (e->data.sclRepeat.newValue - e->data.sclRepeat.value, false); break;
PalmOS позволяет отслеживать высоту поля и изменять его размеры на форме. Изменение размеров нужно писать самому, PalmOS позволяет только отделить изменение поля от перерасчета размеров. Для отслеживания необходимо:
К сожалению, событие fldChangedEvent посылается при всех визуальных изменениях поля, в том числе и просто скроллах. Не существует надежного механизма для изменения переменной, связанной с полем при выходе из поля. Можно посоветовать только изменять переменную на все fldChangedEvent.
Оставшиеся функции нужны редко. В основном они вызываются другими модулями PalmOS.
Следующие функции полезны при “ручной” реализации статических полей, они позволяют разбить длинную текстовую строку на отдельные строки заданной ширины:
http://www.palmosters.com/back/palmstranges.shtm - на странице описаны недокументированные нюансы программирования в PalmOS, в том числе некоторые грабли, связанные с филдами.