Следующий пример демонстрирует, как перехватить комбинацию Ctrl-V в компоненте TMemo и поместить в него свой текст вместо того, который в буфере обмена.

 

 

Code:

procedure CaretPos(H: THandle; var L,C : Word);

begin

L := SendMessage(H,EM_LINEFROMCHAR,-1,0);

C := LoWord(SendMessage(H,EM_GETSEL,0,0)) - SendMessage(H,EM_LINEINDEX,-1,0);

end;

 

procedure TForm1.Button1Click(Sender: TObject);

var

LineNum,ColNum : Word;

begin

CaretPos(Memo1.Handle,LineNum,ColNum);

Edit1.Text := IntToStr(LineNum) + '  ' + IntToStr(ColNum);

end;

  

С помощью API-функции SendMessage можно задать поля в Memo-компоненте. Если необходимо, например, сделать отступ в 20 пикселей слева то можно это сделать следующим образом:

 

 Этот пример прокручивает на одну строку вниз.

Code:

memo1.Perform(WM_VScroll, SB_LINEDOWN,0);

 

В следующем примере создается процедура разбиения слов при переносах для TMemo. Заметьте, что реализованная процедура просто всегда разрешает перенос. Для дополнительной информации см.таже документацию к сообщению EM_SETWORDBREAKPROC.

 

 

Code:

procedure TForm1.Button1Click(Sender: TObject);

begin

if OpenDialog1.Execute then

   Memo1.Lines.LoadFromFile(OpenDialog1.FileName);

end;

 

procedure TForm1.Button2Click(Sender: TObject);

var

find: string;

text: string;

st, len: integer;

res: integer;

begin

if Memo1.SelStart >= Length(Memo1.Text) then

   Memo1.SelStart := 0;

st := Memo1.SelStart + 1;

if (Memo1.SelLength <= 0) or (not CheckBox1.Checked) then

begin

   inc(st, Memo1.SelLength);

   len := Length(Memo1.Text) - st;

end

else

   len := Memo1.SelLength;

text := copy(Memo1.Text, st, len);

find := Edit1.Text;

res := pos(find, text);

if res = 0 then

begin

   ShowMessage('Search string "' + find + '" not found');

   Exit;

end;

Memo1.SelStart := res + st - 2;

Memo1.SelLength := length(find);

end;

 

 


Поиск и замена текста в TMemo

Code:

procedure TForm1.FindDialog1Find(Sender: TObject);

var

Buff, P, FT: PChar;

BuffLen: Word;

begin

with Sender as TFindDialog do

begin

   GetMem(FT, Length(FindText) + 1);

   StrPCopy(FT, FindText);

   BuffLen := Memo1.GetTextLen + 1;

   GetMem(Buff, BuffLen);

   Memo1.GetTextBuf(Buff, BuffLen);

   P := Buff + Memo1.SelStart + Memo1.SelLength;

   P := StrPos(P, FT);

   if P = nil then

     MessageBeep(0)

   else

   begin

     Memo1.SelStart := P - Buff;

     Memo1.SelLength := Length(FindText);

   end;

   FreeMem(FT, Length(FindText) + 1);

   FreeMem(Buff, BuffLen);

end;

end;

 

procedure TForm1.ReplaceDialog1Replace(Sender: TObject);

begin

with Sender as TReplaceDialog do

   while True do

   begin

     if Memo1.SelText <> FindText then

       FindDialog1Find(Sender);

     if Memo1.SelLength = 0 then

       Break;

     Memo1.SelText := ReplaceText;

     if not (frReplaceAll in Options) then

       Break;

   end;

end;

 


 

Code:

{ **** UBPFD *********** by delphibase.endimus.com ****

>> Поиск и замена текста в поле МЕМО программно

 

На форму бросьте кнопку и поле МЕМО

напишите в МЕМО(в первой строке) текст и поставьте C:\, нажмите кнопку,

при этом C:\ замениться на D:\ без потери форматирования

Вот и все...

 

Зависимости: Смотрите uses

Автор:       Mirag, Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра., Mirag

Copyright:   Mirag

 

***************************************************** }

 

unit Unit1;

 

interface

 

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls;

 

type

TForm1 = class(TForm)

   Button1: TButton;

   Label1: TLabel;

   Memo1: TMemo;

   procedure Button1Click(Sender: TObject);

   procedure FormCreate(Sender: TObject);

private

   { Private declarations }

public

   { Public declarations }

end;

 

var

Form1: TForm1;

result: boolean;

implementation

 

{$R *.dfm}

 

function ReplaceSub(str, sub1, sub2: string): string;

var

aPos: Integer;

rslt: string;

begin

aPos := Pos(sub1, str);

rslt := '';

while (aPos <> 0) do

begin

   rslt := rslt + Copy(str, 1, aPos - 1) + sub2;

   Delete(str, 1, aPos + Length(sub1) - 1);

   aPos := Pos(sub1, str);

end;

Result := rslt + str;

end;

 

function MatchStrings(source, pattern: string): Boolean;

var

 

pSource: array[0..255] of Char;

pPattern: array[0..255] of Char;

 

function MatchPattern(element, pattern: PChar): Boolean;

 

   function IsPatternWild(pattern: PChar): Boolean;

   var

     t: Integer;

   begin

     Result := StrScan(pattern, '*') <> nil;

     if not Result then

       Result := StrScan(pattern, '?') <> nil;

   end;

 

begin

   if 0 = StrComp(pattern, '*') then

     Result := True

   else if (element^ = Chr(0)) and (pattern^ <> Chr(0)) then

     Result := False

   else if element^ = Chr(0) then

     Result := True

   else

   begin

     case pattern^ of

       '*': if MatchPattern(element, @pattern[1]) then

           Result := True

         else

           Result := MatchPattern(@element[1], pattern);

       '?': Result := MatchPattern(@element[1], @pattern[1]);

     else

       if element^ = pattern^ then

         Result := MatchPattern(@element[1], @pattern[1])

       else

         Result := False;

     end;

   end;

end;

 

begin

 

StrPCopy(pSource, source);

StrPCopy(pPattern, pattern);

Result := MatchPattern(pSource, pPattern);

end;

 

procedure TForm1.Button1Click(Sender: TObject);

var

ss: string;

begin

result := MatchStrings(memo1.Lines.Text, '*c:\*');

if result = true then

begin

   messagebox(0, '', '', MB_OK);

   ss := ReplaceSub(memo1.Lines.Strings[0], 'c:\', 'd:\');

   memo1.Lines.Delete(0);

   memo1.Lines.Insert(0, ss);

end;

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

 

end;

 

end.

 

 

 

 


 

Code:

{ **** UBPFD *********** by delphibase.endimus.com ****

>> Поиск строки в редакторе Memo

 

Зависимости: Windows, Classes, StdCtrls

Автор:       Fenik, Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра., Новоуральск

Copyright:   Автор: Федоровских Николай

 

***************************************************** }

 

function FindInMemo(Memo: TMemo; const FindText: string;

FindDown, MatchCase: Boolean): Boolean;

 

{Если строка найдена, то результат True, иначе - False;

 

FindText : искомая строка;

FindDown : True - поиск вниз от курсора ввода;

            False - поиск вверх от курсора ввода;

MatchCase : True - с учетом регистра букв,

            False - не учитывая регистр бук.

 

Если у Memo стоит автоперенос слов, то могут

возникнуть проблемы - текст будет найден,

но выделен не там где надо. Так что, для нормального поиска

свойство ScrollBars у Memo ставить в ssBoth (ну или ssHorizontal)}

 

function PosR2L(const FindStr, SrcStr: string): Integer;

   {Поиск последнего вхождения подстроки FindStr в строку SrcStr}

var

   ps, L: Integer;

 

   function InvertSt(const S: string): string;

     {Инверсия строки S}

   var

     i: Integer;

   begin

     L := Length(S);

     SetLength(Result, L);

     for i := 1 to L do

       Result[i] := S[L - i + 1];

   end;

 

begin

   ps := Pos(InvertSt(FindStr), InvertSt(SrcStr));

   if ps <> 0 then

     Result := Length(SrcStr) - Length(FindStr) - ps + 2

   else

     Result := 0;

end;

 

function MCase(const s: string): string;

   {Перевод заглавных букв в строчные;

    Функция вызывается если регистр не учитывается}

var

   i: Integer;

begin

   Result := s;

   for i := 1 to Length(s) do

   begin

     case s[i] of

       'A'..'Z',

         'А'..'Я': Result[i] := Chr(Ord(s[i]) + 32);

       'Ё': Result[i] := 'ё';

       'Ѓ': Result[i] := 'ѓ';

       'Ґ': Result[i] := 'ґ';

       'Є': Result[i] := 'є';

       'Ї': Result[i] := 'ї';

       'І': Result[i] := 'і';

       'Ѕ': Result[i] := 'ѕ';

     end;

   end;

end;

 

var

Y, X, SkipChars: Integer;

FindS, SrcS: string;

P: TPoint;

begin

Result := False;

 

if MatchCase then

   FindS := FindText

else

   FindS := MCase(FindText);

 

P := Memo.CaretPos;

 

if FindDown then

   {Поиск вправо и вниз от курсора ввода}

   for Y := P.y to Memo.Lines.Count do

   begin

 

     if Y <> P.y then

       {Если это не строка, в которой курсор вода,

        то ищем во всей строке}

       SrcS := Memo.Lines[Y]

     else

       {иначе обрезаем строку от курсора до конца}

       SrcS := Copy(Memo.Lines[Y], P.x + 1,

         Length(Memo.Lines[Y]) - P.x + 1);

 

     if not MatchCase then

       SrcS := MCase(SrcS);

     X := Pos(FindS, SrcS);

     if X <> 0 then

     begin

       if Y = P.y then

         Inc(X, P.x);

       P := Point(X, Y);

       Result := True;

       Break; {Выход из цикла}

     end

   end

else

   {Поиск влево и вверх от курсора ввода}

   for Y := P.y downto 0 do

   begin

 

     if Y <> P.y then

       {Если это не строка, в которой курсор вода,

        то ищем во всей строке}

       SrcS := Memo.Lines[Y]

     else

       {иначе обрезаем строку от начала до курсора

        минус выделенный текст}

       SrcS := Copy(Memo.Lines[Y], 1, P.x - Memo.SelLength);

 

     if not MatchCase then

       SrcS := MCase(SrcS);

     X := PosR2L(FindS, SrcS);

     if X <> 0 then

     begin

       P := Point(X, Y);

       Result := True;

       Break; {Выход из цикла}

     end

   end;

 

if Result then

begin

   {Если текст найден - выделяем его}

   SkipChars := 0;

   for y := 0 to P.Y - 1 do

     Inc(SkipChars, Length(Memo.Lines[y]));

   Memo.SelStart := SkipChars + (P.Y * 2) + P.X - 1;

   Memo.SelLength := Length(FindText);

end;

end;

Пример использования:

 

procedure TForm1.FindDialog1Find(Sender: TObject);

begin

if not FindInMemo(Memo1,

   FindDialog1.FindText,

   frDown in FindDialog1.Options,

   frMatchCase in FindDialog1.Options) then

   Application.MessageBox('Поиск результатов не дал.',

     PChar(Application.Title),

     MB_OK or MB_ICONINFORMATION);

end;

 

Пришло мне письмо от Алексея. На этот раз он прислал (цитирую): "юнит для поиска строки(текста) в TEdit, TMemo, или других компонентах (дочерних TCustomEdit'у)." Так как тескт "авторский" (более того, здесь также присутствует наследование), помещаю его здесь в том виде, в котором он был прислан, т.е. без перевода. В случае каких-либо вопросов и недоразумений обращайтесь по вышеуказанносу адресу электронной почты.

 


Code:

{ПРИМЕР :

 

[...]

 

implementation

 

uses Search;}

{$R *.DFM}

 

{procedure TForm1.Button1Click(Sender: TObject);

begin

 

SearchMemo(RichEdit1, 'Найди меня', [frDown]);

end;

 

В опции поиска можно подключать, отключать, комбинировать следующие

параметры:

frDown - указывает на то, что происходит поиск вниз по тексту от курсора(при

отключенном frDown'е будет происходит поиск вверх по тексту).

frMatchCase - указывает на то, что следует проводить поиск с учетом

регистра.

frWholeWord - указывает на то, что следует искать только слово целиком.

 

[...]

 

Авторские права на этот юнит пренадлежат неизвесно кому.

 

В каком виде этот юнит попал мне, практически в этом же

виде я отдаю его вам. Пользуйтесь и благодарите неизвесного

героя.}

 

unit Search;

 

interface

 

uses

 

WinProcs, SysUtils, StdCtrls, Dialogs;

 

const

{****************************************************************************

 

* Default word delimiters are any character except the core alphanumerics. *

****************************************************************************}

WordDelimiters: set of Char = [#0..#255] - ['a'..'z', 'A'..'Z', '1'..'9',

   '0'];

{******************************************************************************

 

* SearchMemo scans the text of a TEdit, TMemo, or other TCustomEdit-derived  *

* component for a given search string. The search starts at the current      *

* caret position in the control.  The Options parameter determines whether   *

* the search runs forward (frDown) or backward from the caret position,      *

* whether or not the text comparison is case sensitive, and whether the      *

* matching string must be a whole word.  If text is already selected in the  *

* control, the search starts at the 'far end' of the selection (SelStart if  *

* searching backwards, SelEnd if searching forwards).  If a match is found,  *

* the control's text selection is changed to select the found text and the   *

* function returns True.  If no match is found, the function returns False.  *

******************************************************************************}

function SearchMemo(Memo: TCustomEdit;

 

const SearchString: string;

Options: TFindOptions): Boolean;

{******************************************************************************

 

* SearchBuf is a lower-level search routine for arbitrary text buffers.      *

* Same rules as SearchMemo above. If a match is found, the function returns  *

* a pointer to the start of the matching string in the buffer. If no match,  *

* the function returns nil.                                                  *

******************************************************************************}

function SearchBuf(Buf: PChar; BufLen: Integer;

 

SelStart, SelLength: Integer;

SearchString: string;

Options: TFindOptions): PChar;

 

implementation

 

function SearchMemo(Memo: TCustomEdit;

 

const SearchString: string;

Options: TFindOptions): Boolean;

var

 

Buffer, P: PChar;

Size: Word;

begin

 

Result := False;

if (Length(SearchString) = 0) then

   Exit;

Size := Memo.GetTextLen;

if Size = 0 then

   Exit;

Buffer := StrAlloc(Size + 1);

try

   Memo.GetTextBuf(Buffer, Size + 1);

   P := SearchBuf(Buffer, Size, Memo.SelStart, Memo.SelLength, SearchString,

     Options);

   if P <> nil then

   begin

     Memo.SelStart := P - Buffer;

     Memo.SelLength := Length(SearchString);

     Result := True;

   end;

finally

   StrDispose(Buffer);

end;

end;

 

function SearchBuf(Buf: PChar; BufLen: Integer;

 

SelStart, SelLength: Integer;

SearchString: string;

Options: TFindOptions): PChar;

var

 

SearchCount, I: Integer;

C: Char;

Direction: Shortint;

CharMap: array[Char] of Char;

 

function FindNextWordStart(var BufPtr: PChar): Boolean;

begin { (True XOR N) is equivalent to (not N) }

   //    Result := False;      { (False XOR N) is equivalent to (N)    }

 

   { When Direction is forward (1), skip non delimiters, then skip delimiters. }

   { When Direction is backward (-1), skip delims, then skip non delims }

 

   while (SearchCount > 0) and

     ((Direction = 1) xor

     (BufPtr^ in WordDelimiters)) do

   begin

     Inc(BufPtr, Direction);

     Dec(SearchCount);

   end;

 

   while (SearchCount > 0) and

     ((Direction = -1) xor

     (BufPtr^ in WordDelimiters)) do

   begin

     Inc(BufPtr, Direction);

     Dec(SearchCount);

   end;

 

   Result := SearchCount > 0;

   if Direction = -1 then

   begin {back up one char, to leave ptr on first non delim}

     Dec(BufPtr, Direction);

     Inc(SearchCount);

   end;

end;

 

begin

 

Result := nil;

 

if BufLen <= 0 then

   Exit;

 

if frDown in Options then

begin {if frDown...}

   Direction := 1;

   Inc(SelStart, SelLength); { start search past end of selection }

   SearchCount := BufLen - SelStart - Length(SearchString);

 

   if SearchCount < 0 then

     Exit;

 

   if Longint(SelStart) + SearchCount > BufLen then

     Exit;

 

end {if frDown...}

else

begin {else}

   Direction := -1;

   Dec(SelStart, Length(SearchString));

   SearchCount := SelStart;

end; {else}

 

if (SelStart < 0) or (SelStart > BufLen) then

   Exit;

 

Result := @Buf[SelStart];

{ Using a Char map array is faster than calling AnsiUpper on every character }

 

for C := Low(CharMap) to High(CharMap) do

   CharMap[C] := C;

 

if not (frMatchCase in Options) then

begin {if not (frMatchCase}

   AnsiUpperBuff(PChar(@CharMap), sizeof(CharMap));

   AnsiUpperBuff(@SearchString[1], Length(SearchString));

end; {if not (frMatchCase}

 

while SearchCount > 0 do

begin {while SearchCount}

   if frWholeWord in Options then

   begin

     if not FindNextWordStart(Result) then

       Break;

   end;

   I := 0;

 

   while (CharMap[Result[I]] = SearchString[I + 1]) do

   begin {while (CharMap...}

     Inc(I);

     if I >= Length(SearchString) then

     begin {if I >=...}

       if (not (frWholeWord in Options)) or

         (SearchCount = 0) or

         (Result[I] in WordDelimiters) then

         Exit;

       Break;

     end; {if I >=...}

   end; {while (CharMap...}

 

   Inc(Result, Direction);

   Dec(SearchCount);

end; {while SearchCount}

 

Result := nil;

end;

 

end.

 

 

 

 

 

 

Code:

function LinesVisible(Memo: TMemo): integer;

   Var

     OldFont : HFont;

     Hand : THandle;

     TM : TTextMetric;

     Rect  : TRect;

     tempint : integer;

   begin

     Hand := GetDC(Memo.Handle);

     try

       OldFont := SelectObject(Hand, Memo.Font.Handle);

       try

         GetTextMetrics(Hand, TM);

         Memo.Perform(EM_GETRECT, 0, longint(@Rect));

         tempint := (Rect.Bottom - Rect.Top) div

            (TM.tmHeight + TM.tmExternalLeading);

       finally

         SelectObject(Hand, OldFont);

       end;

     finally

       ReleaseDC(Memo.Handle, Hand);

     end;

     Result := tempint;

   end;

 

  

Code:

procedure TForm1.Button1Click(Sender: TObject);

var

rgn: HRGN;

r: TRect;

begin

r := memo1.ClientRect;

rgn := CreateRoundRectRgn(r.Left, r.top, r.right, r.bottom, 20, 20);

memo1.BorderStyle := bsNone;

memo1.Perform(EM_GETRECT, 0, lparam(@r));

InflateRect(r, -5, -5);

memo1.Perform(EM_SETRECTNP, 0, lparam(@r));

SetWindowRgn(memo1.Handle, rgn, true);

end;

 

Code:

{

For this tip you need Memo1, ListBox1, Label1, Button1.

 

}

 

procedure TForm1.Button1Click(Sender: TObject);

var

   i, p: Integer;

  s: string;

begin

  ListBox1.Clear;

  for i := 0 to Memo1.Lines.Count - 1 do

  begin

    if Pos('https://', Memo1.Lines.Strings[i]) > 0 then

    begin

      s := '';

      {If the current line contains a "https://", read on until a space is found

 

      Die aktuelle Zeile wird nach der Zeichenfolge "https://" durchsucht

      und bei Erfolg ab der gefundenen Position ausgelesen, bis ein

      Leerzeichen auftritt...}

 

      for p := Pos('https://', Memo1.Lines.Strings[i]) to

        Length(Memo1.Lines.Strings[i]) do

        if Memo1.Lines.Strings[i][p] <> ' ' then

          s := s + Memo1.Lines.Strings[i][p]

      else

        break;

 

       {Remove some characters if address doesn't end with a space

 

      Falls die gefundene Adresse nicht mit einem Leerzeichen abschlie?t,

      werden hier noch anhangende Textzeichen entfernt...}

 

      while Pos(s[Length(s)], '..;!")]}?''>') > 0 do

        Delete(s, Length(s), 1);

      // Add the Address to the list...

     //Gefundene Adresse in die Liste aufnehmen...

     ListBox1.Items.Add(s);

    end;

  end;

 

  // Show the number of Addresses in Label1

// Die Zahl der gefundenen Adressen in Label1 anzeigen...

 

if ListBox1.Items.Count > 0 then

    label1.Caption := IntToStr(ListBox1.Items.Count) +

      ' Adresse(n) gefunden.'

  else

    label1.Caption := 'Keine Adresse gefunden.';

end;

 

Автор: Hog

 

Допустим у тебя TMemo..

 

1. Делаешь ListBox, заполняешь, visible := false, parent := Memo

2. У Memo в обработчике Memo.onKeyDown что-нибудь типа:

Автор: Xavier Pacheco

 

Создайте потомок TMemo, перехватывающий сообщения WM_HSCROLL и WM_VSCROLL: