OpenWiki

Field Control

Edit this page (last edited June 28, 2004)
Palm Notes | Recent Changes | Title Index | User Preferences | Random Page | Help
  • Общие замечания
  • Описание в ресурсах
  • Атрибуты
  • Работа с памятью
  • Рисование поля
  • Операции над полем
  • Взаимодействие со скроллбаром
  • Динамический размер поля
  • Как отследить изменение поля?
  • Прочие функции
  • Полезные ссылки
  • Field Control - это штатный контрол Palm OS для редактируемого поля. Как обычно, умение работать с аналогичными контролами в других ОС как помогают, так и мешают работе с 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стандартные координаты поля типа RectangleTypeFldGetBoundsFldSetBoundsAT (<Left.p> <Top.p> <Width.p> <Height.p>)
    fontIDшрифт, используемый в полеFldGetFontFldSetFontFONT <FontId.n>)
    textуказатель на текст, содержащийся в поле. текст завершается нулевым байтом.FldGetTextPtrFldSetTextPtr 
    textHandleхендл текстового блокаFldGetTextHandleFldSetTextHandle FldSetText 
    textLenреальная длина текста, используемая блоком, StrLen(text).FldGetTextLength 
    textBlockSizeдлина блока, выделенного для текста. По сути дела максимальная длина текста, которую поле будет использовать до перевыделения памяти.FldGetTextAllocatedSizeFldSetTextAllocatedSize 
    maxCharsмаксимальное допустимое число вводимых символов. Учтите, что для мультибайтных кодировок это не будет совпадать с максимальной длиной блока в байтах. Предельный размер поля - 32767 байт.FldGetMaxCharsFldSetMaxCharsMAXCHARS <MaxChars.n>
    selFirstPost, selLastPosпозиции выделенного текста.FldGetSelectionFldSetSelection  
    insert positionпозиция ввода. реально в структуре FieldType не хранится, вместо него хранятся следующие два поля.FldGetInsPtPosition FldSetInsPtPosition (с перерисовкой) FldSetInsertionPoint (без перерисовки) 
    insPtXPosсмещение в байтах позиции ввода от начала строки. А если текущая строка не видна, то абсолютная позиция. 
    insPtYPosстрока на экране, в которой находится позиция ввода. Если позиция невидима, то в поле хранится 0x8000 
    maxVisibleLinesмаксимальное число видимых строк FldSetMaxVisibleLines 
    linesинформация разбиения текста по строкам. Поле указывает на массив информации о началах строк и числе символов в каждой. Число строк можно получить с помощью функции FldGetVisibleLines. 

    Следующие поля входят в структуру FieldAttrType. Для работы с этими полями используются функции FldGetAttributes и FldSetAttributes

    Имя поляОписаниеФункции извлеченияФункции модификацииПараметр в ресурсах
    usableпризнак использования поля в форме FldSetUsableUSABLE NONUSABLE
    visibleпризнак видимости поля. FldDrawField FldEraseFieldDISABLED
    editableпризнак возможности редактирования поля пользователем  EDITABLE NONEDITABLE
    singleLineПризнак однострочного или многострочного поля  SINGLELINE MULTIPLELINES
    hasFocusполе держит фокус. Если поле в фокусе, то в нем мерцает курсор FldGrabFocus FldReleaseFocus 
    dynamicSizeОбманчивое имя признака. На самом деле, если флаг выставлен, то при изменении числа строк генерируется событие fldHeightChangedEvent. Приложение может отслеживать событие и изменять видимые границы поля. Если признак не выставлен, то событие не генерируется. Никакого автоматического изменения размера не происходит. Для однострочных полей смысла не имеет.  DYNAMICSIZE
    insPtVisibleвнутренний признак того, что строка с позицией ввода видна на экране. 
    dirtyпризнак "грязного" поля. Поле является грязным, когда изменения в содержимом не отображены на экране.FldDirtyFldSetDirty 
    underlinedПризнак указывает на тип подчеркивания строк. PilRC? позволяет только стандартный способ - grayUnderline. Программно можно задать noUnderline, solidUnderline, colorUnderline.  UNDERLINED
    justificationзадает выравнивание поля: leftAlign, rightAlign. centerAlign не поддерживается.  LEFTALIGN RIGHTALIGN
    autoShiftесли признак задан, то поддерживаются правила autoShift (автоматическое выставление заглавных букв в начале предложений).   AUTOSHIFT
    hasScrollBarЕще одно обманчивое имя. При выставлении поле начинает чаще посылать fldChangedEvent?. Слово "чаще" нужно понимать как "поле чаще пересчитывает разбиение на строки".  HASSCROLLBAR
    numericК версии Palm OS 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;
    

    Динамический размер поля

    Palm OS позволяет отслеживать высоту поля и изменять его размеры на форме. Изменение размеров нужно писать самому, Palm OS позволяет только отделить изменение поля от перерасчета размеров. Для отслеживания необходимо:

    Как отследить изменение поля?

    К сожалению, событие fldChangedEvent? посылается при всех визуальных изменениях поля, в том числе и просто скроллах. Не существует надежного механизма для изменения переменной, связанной с полем при выходе из поля. Можно посоветовать только изменять переменную на все fldChangedEvent?.

    Прочие функции

    Оставшиеся функции нужны редко. В основном они вызываются другими модулями Palm OS.

    Следующие функции полезны при "ручной" реализации статических полей, они позволяют разбить длинную текстовую строку на отдельные строки заданной ширины:

    Полезные ссылки

    http://www.palmosters.com/back/palmstranges.shtm - на странице описаны недокументированные нюансы программирования в Palm OS, в том числе некоторые грабли, связанные с филдами.

    Palm Notes | Recent Changes | Title Index | User Preferences | Random Page | Help
    Edit this page | View other revisions
    Print this page | View XML
    Find page by browsing, searching or an index
    Edited June 28, 2004 (diff)
    Valid XHTML 1.0!Valid CSS!