冥界3大法王 发表于 2023-3-20 14:57

在RichViewEdit控件中如何去选择一个查找到的关键字?

或者是设置I形光标的位置?

在上一贴中lovemit帮助解决了大问题
@lovemit
还有最后一问题搞不明白如何设置?


帮助中有以下小节是这么说的,感觉有门就是不知咋调用?

Functions from RVLinear Unit
TopPreviousNext


const

RVCharsPerLineBreak: Integer = 2;

RVNonTextCharacter: TRVUnicodeChar = ' ';



function RVGetLinearCaretPos(rve: TCustomRichViewEdit;
CharsPerLineBreak: Integer = -1): Integer;
procedure RVSetLinearCaretPos(rve: TCustomRichViewEdit; LinearPos: Integer;
CharsPerLineBreak: Integer = -1);

RVGetLinearCaretPos returns the caret position (as a number of characters before the caret). Non-text objects (except for tables and tabulators) are treated as one character, line breaks are treated as CharsPerLineBreak characters.

RVSetLinearCaretPos moves the caret to the specified position.



Value of CharsPerLineBreak parameter

Meaning


2

Use #13#10 to separate lines


1

Use #13 to separate lines


0

Lines are not separated


-1

Use the value of RVCharsPerLineBreak global variable (which, in its order, may be 2, 1, or 0)


procedure RVGetSelection(rv: TCustomRichView; out SelStart, SelLength: Integer;
CharsPerLineBreak: Integer = -1);
procedure RVSetSelection(rv: TCustomRichView; SelStart, SelLength: Integer;
CharsPerLineBreak: Integer = -1);

RVGetSelection returns the selection position in memo/richedit-like parameters (SelStart and SelLength). RVSetSelection sets selection by these values.

type

TRVSelection = record

    SelStart, SelLength: Integer;

    MultiCell: Boolean;

    StartRow, StartCol, RowOffs, ColOffs: Integer;

end;

procedure RVGetSelectionEx(rv: TCustomRichView; out Selection: TRVSelection;
CharsPerLineBreak: Integer = -1);
procedure RVSetSelectionEx(rv: TCustomRichView; const Selection: TRVSelection;
CharsPerLineBreak: Integer = -1);

RVGetSelectionEx returns the selection position in TRVSelection record. RVSetSelectionEx sets selection by this record. These functions can handle not only a normal selection, but a multicell selection in tables as well.

function RichViewToLinear(rv: TCustomRichView; CurRVData, RVData: TCustomRVData;
ItemNo, ItemOffs: Integer; out LinearPos: Integer;
CharsPerLineBreak: Integer = -1): Boolean;
function LinearToRichView(rv: TCustomRichView; CurRVData: TCustomRVData;
var LinearPos: Integer; out RVData: TCustomRVData;
out ItemNo, ItemOffs: Integer; CharsPerLineBreak: Integer = -1): Boolean;

RichViewToLinear converts the position specified in TRichView coordinates (RVData ? document, ItemNo ? index of item in this document, ItemOffs ? offset in this item) to a linear coordinate (a number of characters from the beginning of CurRVData before this position). Non-text objects (except for tables and tabulators) are treated as one character, line breaks are treated as CharsPerLineBreak characters. LinearToRichView performs an opposite conversion.

function RVGetTextRange(rv: TCustomRichView;
RangeStart, RangeLength: Integer;
CharsPerLineBreak: Integer = -1): TRVUnicodeString;
function RVGetTextLength(rv: TCustomRichView;
CharsPerLineBreak: Integer = -1): Integer;

RVGetTextRange returns text from rv, from RangeStart to RangeLength positions. Non-text items (except for the tables and tabulators) are returned as RVNonTextCharacter. As for line breaks, see the table about CharsPerLineBreak above.

The call RVGetTextRange(rv, 0, RVGetTextLength(rv)) returns the whole text.



All these functions are compatible, they calculate position identically (providing that the same value of CharsPerLineBreak is used). A text returned by RVGetTextRange has one-to-one correspondence to TRichView document (unlike text returned by the functions from RVGetText unit).

冥界3大法王 发表于 2023-3-20 15:01

还有以下的:
//RichViewEdit1.SelectCurrentWord;      选择当前单词,但是搜索出来的咋去做到呢?
// RichViewEdit1.SelectWordAt(5, 2);         这个不行,咋感觉有门?
//RichViewEdit1.SetSelectionBounds(1, 2, 3, 1);

下面写写官方实例:有参考的地方吗?
unit SyntaxRichViewEdit;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
RVScroll, RichView, RVEdit, RVStyle, ExtCtrls;

type
TSyntaxRichViewEdit = class(TRichViewEdit)
private
    { Private declarations }
    FSyntaxUpdateTimer : TTimer;
    FTimerInterval : Cardinal;
    FSyntaxUpdating : boolean;
    FOnColorize: TNotifyEvent;
    procedure SetTimerInterval(Value: Cardinal);
protected
    { Protected declarations }
    procedure DoUpdateSyntax(Sender: TObject);
public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure DoChange(ClearRedo: Boolean); override;
    procedure Undo; override;

    function ItemOffsToAbs(aItemNo, aOffs : integer) : integer;
    procedure AbsToItemOffs(aPos : integer; var aItemNo, aOffs : integer);
    procedure GetSelBounds(var aStart, aEnd : integer; var Inverted : boolean);
    procedure SetSelBounds(aStart, aEnd : integer; Inverted : boolean);
    function GetSelStart : integer;
    function GetSelEnd : integer;
    function GetSelLength : integer;
    procedure SetSelLength(aLen : integer);
    function GetAbsCaretPos : integer;
    procedure SetAbsCaretPos(aPos : integer);

    procedure Mark(aText : string; aStyleIndex : integer);
    procedure MarkBetween(aStartText, aEndText : string;
      aOuterStyleIndex, aInnerStyleIndex : integer;
      aAllowMultiline: boolean);
    procedure InsertTags(aTag1, aTag2 : string);
published
    { Published declarations }
    property TimerInterval : Cardinal read FTimerInterval write SetTimerInterval default 100;
    property OnColorize: TNotifyEvent read FOnColorize write FOnColorize;
end;

procedure Register;
function GetTextFromClipboard : string;

implementation

uses
Clipbrd;

//------------------------------------------------------------------------------
procedure Register;
//------------------------------------------------------------------------------
begin
RegisterComponents('RichView', );
end;

//------------------------------------------------------------------------------
function GetTextFromClipboard : string;
//------------------------------------------------------------------------------
var
Clipboard : TClipboard;
begin
Clipboard := TClipboard.Create;
Clipboard.Open;
Result := Clipboard.AsText;
Clipboard.Close;
Clipboard.Free;
end;

//------------------------------------------------------------------------------
constructor TSyntaxRichViewEdit.Create(AOwner: TComponent);
//------------------------------------------------------------------------------
begin
inherited Create(AOwner);
Options := [rvoAllowSelection,rvoClientTextWidth,rvoShowPageBreaks,
            rvoAutoCopyText,rvoFormatInvalidate,rvoDblClickSelectsWord,
            rvoRClickDeselects];

SetAddParagraphMode(False);

FSyntaxUpdating := false;

FTimerInterval := 100;

FSyntaxUpdateTimer := TTimer.Create(nil);
with FSyntaxUpdateTimer do
begin
    Enabled := false;
    Interval := FTimerInterval;
    OnTimer := DoUpdateSyntax;
end;
end;

//------------------------------------------------------------------------------
destructor TSyntaxRichViewEdit.Destroy;
//------------------------------------------------------------------------------
begin
FSyntaxUpdateTimer.Free;
inherited Destroy;
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.DoChange(ClearRedo: Boolean);
//------------------------------------------------------------------------------
begin
FSyntaxUpdateTimer.Enabled := false;
if not FSyntaxUpdating then
begin
    inherited DoChange(ClearRedo);

    if Assigned(FOnColorize) then // do nothing if no colorizer procedure defined
      FSyntaxUpdateTimer.Enabled := true;
end;
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.Undo;
//------------------------------------------------------------------------------
begin
BeginUpdate;
if (UndoAction = rvutCustom) then
    inherited Undo;
inherited Undo;
EndUpdate;
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.SetTimerInterval(Value: Cardinal);
//------------------------------------------------------------------------------
begin
if (Value < 20) then Value := 20;
if (FTimerInterval <> Value) then
begin
    FTimerInterval := Value;
    FSyntaxUpdateTimer.Interval := FTimerInterval;
end;
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.DoUpdateSyntax(Sender: TObject);
//------------------------------------------------------------------------------
var
OldSelStart,
OldSelEnd : integer;
OldInverted : boolean;
begin
FSyntaxUpdateTimer.Enabled := false;
FSyntaxUpdating := true;

BeginUpdate;
LockWindowUpdate(Handle);

try
    GetSelBounds(OldSelStart, OldSelEnd, OldInverted);

    BeginUndoGroup(rvutCustom);
    SetUndoGroupMode(true);

    SelectAll;
    ApplyTextStyle(0);

    if (GetSelText <> '') then
    begin
      if Assigned(FOnColorize) then
      FOnColorize(Self);
    end;

    SetUndoGroupMode(false);

finally
    LockWindowUpdate(0);
    EndUpdate;

    SetSelBounds(OldSelStart, OldSelEnd, OldInverted);

    FSyntaxUpdating := false;
end;
end;

//------------------------------------------------------------------------------
function TSyntaxRichViewEdit.ItemOffsToAbs(aItemNo, aOffs : integer) : integer;
//------------------------------------------------------------------------------
var
i, n : integer;
begin
n := 0;
for i := 0 to aItemNo-1 do
begin
    if IsFromNewLine(i) then
      n := n + 1;

    if (GetItemStyle(i) >= 0) then // if it is a text item
      n := n + Length(GetItemText(i));
end;
n := n + aOffs-1;

if IsFromNewLine(aItemNo) then
    n := n + 1;

Result := n;
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.AbsToItemOffs(aPos : integer;
var aItemNo, aOffs : integer);
//------------------------------------------------------------------------------
var
i, j, l, n : integer;
begin
n := aPos;
j := 0;
for i := 0 to ItemCount-1 do
begin
    j := i;

    l := 0;
    if (GetItemStyle(i) >= 0) then // if it is a text item
      l := Length(GetItemText(i));

    if IsFromNewLine(i) then
      l := l + 1;

    if n <= l then Break;

    n := n - l;
end;

if IsFromNewLine(j) then
    n := n - 1;

aItemNo := j;
aOffs := n + 1;
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.GetSelBounds(var aStart, aEnd : integer;
var Inverted : boolean);
//------------------------------------------------------------------------------
var
aStartItem, aStartOffs,
aEndItem, aEndOffs, i : integer;
begin
RVData.GetSelectionBoundsEx(aStartItem, aStartOffs,
                              aEndItem, aEndOffs, false);

aStart := ItemOffsToAbs(aStartItem, aStartOffs);
aEnd := ItemOffsToAbs(aEndItem, aEndOffs);

Inverted := (aStart > aEnd);
if Inverted then
begin // swap values
    i := aStart;
    aStart := aEnd;
    aEnd := i;
end;
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.SetSelBounds(aStart, aEnd : integer;
Inverted : boolean);
//------------------------------------------------------------------------------
var
aStartItem, aStartOffs,
aEndItem, aEndOffs : integer;
begin
AbsToItemOffs(aStart, aStartItem, aStartOffs);
AbsToItemOffs(aEnd, aEndItem, aEndOffs);

if Inverted then
    SetSelectionBounds(aEndItem, aEndOffs, aStartItem, aStartOffs)
else
    SetSelectionBounds(aStartItem, aStartOffs, aEndItem, aEndOffs);
end;

//------------------------------------------------------------------------------
function TSyntaxRichViewEdit.GetSelStart : integer;
//------------------------------------------------------------------------------
var
i : integer;
f : boolean;
begin
GetSelBounds(Result, i, f);
end;

//------------------------------------------------------------------------------
function TSyntaxRichViewEdit.GetSelEnd : integer;
//------------------------------------------------------------------------------
var
i : integer;
f : boolean;
begin
GetSelBounds(i, Result, f);
end;

//------------------------------------------------------------------------------
function TSyntaxRichViewEdit.GetSelLength : integer;
//------------------------------------------------------------------------------
var
aStart, aEnd : integer;
f : boolean;
begin
GetSelBounds(aStart, aEnd, f);
Result := (aEnd - aStart);
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.SetSelLength(aLen : integer);
//------------------------------------------------------------------------------
var
aStartItem, aStartOffs,
aEndItem, aEndOffs,
aStart, aEnd : integer;
begin
RVData.GetSelectionBoundsEx(aStartItem, aStartOffs,
                              aEndItem, aEndOffs, false);

aStart := ItemOffsToAbs(aStartItem, aStartOffs);
aEnd := ItemOffsToAbs(aEndItem, aEndOffs);

if (aLen < 0) then aLen := 0;

if (aEnd - aStart) = aLen then Exit;

if (aLen > 0) then
    AbsToItemOffs(aStart + aLen, aEndItem, aEndOffs)
else
begin
    aEndItem := aStartItem;
    aEndOffs := aStartOffs;
end;

SetSelectionBounds(aStartItem, aStartOffs, aEndItem, aEndOffs);
end;

//------------------------------------------------------------------------------
function TSyntaxRichViewEdit.GetAbsCaretPos : integer;
//------------------------------------------------------------------------------
begin
Result := ItemOffsToAbs(CurItemNo, OffsetInCurItem);
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.SetAbsCaretPos(aPos : integer);
//------------------------------------------------------------------------------
var
aItemNo, aOffs : integer;
begin
AbsToItemOffs(aPos, aItemNo, aOffs);

SetSelectionBounds(aItemNo, aOffs, aItemNo, aOffs);
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.Mark(aText : string; aStyleIndex : integer);
//------------------------------------------------------------------------------
begin
if ItemCount = 0 then Exit;
SetSelectionBounds(0, GetOffsBeforeItem(0), 0, GetOffsBeforeItem(0));

while SearchText(aText, ) do
    ApplyTextStyle(aStyleIndex);
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.MarkBetween(aStartText, aEndText : string;
aOuterStyleIndex, aInnerStyleIndex : integer;
aAllowMultiline: boolean);
//------------------------------------------------------------------------------
var
StartItemNo, EndItemNo, i : integer;
OldProtect : boolean;
begin
if ItemCount = 0 then Exit;
SetSelectionBounds(0, GetOffsBeforeItem(0), 0, GetOffsBeforeItem(0));

while SearchText(aStartText, ) do
begin
    ApplyTextStyle(aOuterStyleIndex);

    StartItemNo := CurItemNo;

    if SearchText(aEndText, ) then
    begin
      ApplyTextStyle(aOuterStyleIndex);

      EndItemNo := CurItemNo;

      If (StartItemNo < 1 + EndItemNo) then
      begin
      if not aAllowMultiline then
          for i := StartItemNo+1 to EndItemNo do
            if IsFromNewLine(i) then
            exit;
      OldProtect := (rvprConcateProtect in Style.TextStyles.Protection);
      if not OldProtect then
          with Style.TextStyles do
            Protection := Protection + ;

      for i := StartItemNo+1 to EndItemNo-1 do
          GetItem(i).StyleNo := aInnerStyleIndex;

      if not OldProtect then
          with Style.TextStyles do
            Protection := Protection - ;
      end;
    end;
end;
end;

//------------------------------------------------------------------------------
procedure TSyntaxRichViewEdit.InsertTags(aTag1, aTag2 : string);
//------------------------------------------------------------------------------
var
OldSelStart, OldSelEnd, SelLen : integer;
NewSelStart : integer;
f : boolean;
begin
BeginUpdate;
LockWindowUpdate(Handle);
try
    BeginUndoGroup(rvutInsert);
    SetUndoGroupMode(true);

    GetSelBounds(OldSelStart, OldSelEnd, f);
    SelLen := OldSelEnd - OldSelStart;

    SetAbsCaretPos(OldSelStart);
    InsertText(aTag1);

    NewSelStart := GetAbsCaretPos;

    SetAbsCaretPos(NewSelStart + SelLen);
    InsertText(aTag2);

    SetSelBounds(NewSelStart, NewSelStart + SelLen, f);

    SetUndoGroupMode(false);
finally
    LockWindowUpdate(0);
    EndUpdate;
    //Change;
end;
end;

end.

冥界3大法王 发表于 2023-3-20 15:08

下面的貌似好像有效果了:


CustomRichView.SetSelectionBounds
TopPreviousNext


Selects part of RichView document (for copying to the Clipboard)

procedure SetSelectionBounds(StartItemNo, StartItemOffs,

EndItemNo, EndItemOffs: Integer);

Parameters

StartItemNo ? index of the first selected item.

StartItemOffs:

§if the first item is a text item, then the selection start is before the StartItemOffs-th character of string (characters in strings are counted from 1, the last position (after the text item) is text length+1). The exception is empty text items formatted with style having EmptyWidth>0; for them, the position after the item is 2.

§if the first item is not a text, then

·if StartItemOffs=0, then the selection start is before the first item;

·if StartItemOffs=1, then the selection start is after the first item.

EndItemNo ? index of the last selected item.

EndItemOffs:

§if the last item is a text item, then the selection end is before the EndItemOffs-th character of string (characters in strings are counted from 1, the last position (after the text item) is text length+1). The exception is empty text items formatted with style having EmptyWidth>0; for them, the position after the item is 2.

§if the last item is not a text, then

·if EndItemOffs=0, then the selection end is before the last item

·if EndItemOffs=1, then the selection end is after the last item.



Caret position

In TRichViewEdit, the caret is always at the end of the selection, so this method can be used to move caret.



Selection in table cells

Before making selecting inside a table cell, activates its editing:

var RVData: TCustomRVFormattedData;


RVData := TCustomRVFormattedData(Table.Cells.Edit);
RVData.SetSelectionBounds(...);



Deselection

There are two ways to deselect:

§to pass StartItemNo=-1

§to pass StartItemNo=EndItemNo and StartItemOffs=EndItemOffs (in editor, the caret is moved to the specified position).

Please be careful and do not specify incorrect values.



Additional information

This method does not repaint the component (use Invalidate)

This method generates OnSelect event.

There are two useful methods to work with SetSelectionBounds: GetOffsBeforeItem and GetOffsAfterItem.

This method must be called only when the document is formatted.

If you want to set selection bounds using richedit-like parameters (SelStart and SelLength), use RVSetSelection from RVLinear unit instead.

lovemit 发表于 2023-3-20 16:43

这么多英文好复杂啊。{:1_908:}

冥界3大法王 发表于 2023-3-20 20:23

lovemit 发表于 2023-3-20 16:43
这么多英文好复杂啊。

找个没人的地方高声朗读10遍英语,竟然懂了。{:301_988:}

lovemit 发表于 2023-3-20 22:12

本帖最后由 lovemit 于 2023-3-20 23:33 编辑


var
lineNum, colNum: integer;
searchStr: string;
begin
searchStr := 'delphi';
RichViewEdit1.Clear;
RichViewEdit1.AllowSelection := true;
RichViewEdit1.SetItemTextEdW(0, 'adlfadfadsfadfdelphiadslfjaldjf');
RichViewEdit1.GetCurrentLineCol(lineNum, colNum);
ShowMessageFmt('光标所在行:%s,列:%s', );   // 光标所在行和列。
if not RichViewEdit1.SearchText(searchStr, ) then // 查找到字符串【delphi】后自动选择
begin
    ShowMessageFmt('未找到字符串:%s', );
end;
end;

搜索测试:https://wwgp.lanzoue.com/iS2sY0qn2i4j


页: [1]
查看完整版本: 在RichViewEdit控件中如何去选择一个查找到的关键字?