Малко за TRichEdit - Компоненти - Система - Каталог със статии - Kingdom of Delphi

  • СвойствоСвойства
  • SelLength , SelStartИзберете текст
  • МетодиМетоди
  • FindTextТърсете в текста според модела, в посочения диапазон.
  • Lines.AddДобавя ред в края на текста.
  • SelStart, SelLength

    Библиотеката с компоненти на Delphi има следните описания на тези методи:

    Във файла Source\RTL\WIN\richedit.pas описанието на типа

    Този тип е необходим за прехвърляне на границите на избраната част от текста. За Windows избраната част от текста се определя по следния начин:cpMinе първият символ, от който започва селекцията (т.е. този знак е включен в селекцията), аcpMaxе първият знак от неизбран текст, непосредствено след селекцията (т.е. този знак не е включен в селекцията).

    Във файла Source\VCL\stdctrls.pas

    СвойстватаSelStartиSelLengthса дефинирани тук.

    Във файла Source\VCL\comctrls.pas

    Когато е зададеноSelStart, началото и краят на избраната част се намаляват до една стойност. Курсорът ще се премести до посочения знак и компонентът ще преначертае изображението, така че курсорът да се вижда.

    Методът FindText търси шаблонен низ в посочения диапазон от текст.

    Методътвръщаномера на позицията на търсения шаблон в текста (от началото на текста, от0), ако шаблонът не е намерен, връща-1(минус едно).

    От файл RTL\WIN\richedit.pas описание на типа

    Този тип е необходим за преминаване на границите на частта от текста, в която ще се извършва търсенето. За Windows границите на текста са посочени по следния начин:cpMinе първият знак, който започва търсенето, аcpMaxе последният знак, до който трябва да се търси.

    Полето lpstrText е указател към низ, завършващ с нула (PAnsiChar е нормаленPCchar).

    От файла VCL\comctrls.pas

    Този тип определя как трябва да се извърши търсенето. АкоstMatchCaseе зададено, тогава търсенето трябва да е чувствително към главни и малки букви (големи или малки). Ако е зададеноstWholeWord, тогава намерената последователност трябва да бъде ограничена с разделители (напр. интервали). ВOSR2rusтова се нарича "само цяла дума", въпреки че може да има повече от една дума.

    Това е описателната част на класа и по-нататък в раздела за изпълнение:

    Добавя ред в края на текста

    КласътTRichEditнаследява методаAddот класаTStrings, тъй като това е типът, който притежава свойствотоLines. От файла Source\VCL\classes.pas:

    Искаме броя на редовете в текста и извикваме методаInsert, за да вмъкнем ред в края на текста. И двете използвани функции са описани на едно и също място като:

    Тоест, те са абстрактни и виртуални, което означава, че те трябва да бъдат предефинирани в потомците без грешка. Такова дете е класътTRichEditStrings, чийто конструктор се извиква, за да създаде свойствотоLinesв конструктораTCustomRichEdit, най-близкият родител наTRichEdit

    От файл Source\VCL\comctrls.pas

    Изискваме броя редове в текста и го съхраняваме в служебната променливаРезултат. Ако дължината на последния низ е нула (т.е. празен), извадете го от резултата (Резултат).

    По номера на реда, пред който ще вмъкнем, определяме номера на символа, от който започва реда, и го съхраняваме в променливатаSelection.cpMin. Ако номерът на знака е неотрицателен, това означава, че ред с такъв номер съществува и в края на добавения ред трябва да се постави знак за край. Ако номерът на знакаотрицателен означава, че няма такъв ред. Но може би е направен опит за вмъкване след последния ред, така че искаме номера на знака за предишния ред. Ако сега числото е отрицателно или дължината на този низ е нула, ние спираме по-нататъшното изпълнение. При благоприятен изход, ние увеличавамеSelection.cpMinс дължината на последния ред, така че сега той сочи към последния знак в текста (ще го вмъкнем тук). Наличието на ненулева дължина на последния ред показва, че редът не е завършен. За да го завършите, е необходимо първо да прехвърлите в текста знака за край на реда, а след това и самия добавен ред, така че знакът за край на реда да бъде включен в началото му. След това задайте края на селекцията в началото на селекцията (променливаSelection.cpMax) и преместете курсора там, като изпратите съобщениетоEM_EXSETSEL. Ние форматираме низа и изпращаме съобщениетоEM_REPLACESEL, за да приспособим вмъкнатия низ. След успешно вмъкване новата позиция на курсора трябва да е равна на позицията преди вмъкването плюс дължината на вмъкнатия низ (Selection.cpMax+ Length(Str)). Ако не, се хвърля изключение (raiseEOutOfResources.Create(sRichEditInsertError)).

    Грешката възниква, защото съобщениетоEM_LINELENGTHизползва само долните 16 бита на параметъра. Този параметър трябва да съдържа броя на всеки знак от низа, чиято дължина трябва да бъде определена. Ако бъде подадено число, по-голямо от 65 535, добре, например 65 536, тогава съобщението връща дължината на низа, съдържащ знака с числото 0. По този начин, в методаAdd, когато се иска функциятаGetCount, може да се получи стойност, по-голяма от едно, ако се срещне низ с ненулева дължина. И тогава на процедуратаInsertще бъде предадена стойност с едно по-голяма от номера на последниялинии. Това е първата грешка.

    Между другото, свойствотоCount, което извиква функциятаGetCount, може да даде още един ред, ако размерът на текста надвишава 65 535 байта. Подчертавам, че грешката възниква само ако низът, съдържащ съкратения знак, не е празен, тоест грешката ще има плаващ знак.

    Връщайки се към методаAdd, отбелязвам, че тази грешка не засяга процедуратаInsert. Тъй като процедуратаInsertопитва не само посочения ред, но също така, в случай на грешка, предишния, и това ще бъде само последният ред в текста. Но тук се крие истинската грешка. Веднъж в този клонif(т.е. следelse), процедуратаInsertизисква дължината на реда, използвайки съобщениетоEM_LINELENGTHи отново получава грешна стойност. Обстоятелствата се разрастват като снежна топка, неизбежно. Сега грешната дължина на низа се използва за определяне на номера на последния знак в текста. Но дължината на истинския последен ред вероятно е нула, което означава, че вече имаме номера на последния знак в текста след предишното съобщениеEM_LINEINDEX. След като добавим дължина на някой друг към него, получаваме номер на символ, който очевидно надхвърля текста. Поради това ще бъде извикано изключение, но по-късно. Изпращането на съобщениеEM_EXSETSELс параметри извън границите протича без катастрофални последици, стойността се игнорира и курсорът се премества в края на текста. СъобщениетоEM_REPLACESELвмъква добавения ред в края на текста. И накрая се задейства веригата от грешки.

    След вмъкване курсорът се премества отвъд вмъкнатия ред, т.е. до края на текста. Новата позиция на курсора не съответства на предишната, освен това дължината на вмъкнатия ред е точно колкото дължината на чуждия ред,и това води до хвърляне на изключение. Една драма с гафове и игнорирането им завършва трагично заради една дреболия.

    Според мен примерът демонстрира добре компенсаторния характер наDelphiиWindows, без да разглежда масата от грешки, които се крият в тях (за какво говоря, чудя се?).

    Можете да избегнете тази неприятна ситуация, ако предефиниратеGetCount,InsertиDeleteв класаTRichEditStringsили коригирате тези функции в изходните текстове, или напишете свои собствени.